OSDN Git Service

Merge "input: touchscreen: Fix uninitialized variable usage in Atmel driver"
authorLinux Build Service Account <lnxbuild@localhost>
Thu, 15 Mar 2018 12:42:55 +0000 (05:42 -0700)
committerGerrit - the friendly Code Review server <code-review@localhost>
Thu, 15 Mar 2018 12:42:55 +0000 (05:42 -0700)
742 files changed:
.mailmap
Documentation/ABI/testing/sysfs-fs-f2fs
Documentation/devicetree/bindings/arm/msm/subsystem_notif_virt.txt [new file with mode: 0644]
Documentation/devicetree/bindings/display/google,goldfish-fb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/dma/snps-dma.txt
Documentation/devicetree/bindings/i2c/i2c-msm-v2.txt
Documentation/devicetree/bindings/interrupt-controller/google,goldfish-pic.txt [new file with mode: 0644]
Documentation/devicetree/bindings/power/mti,mips-cpc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/google,goldfish-rtc.txt [new file with mode: 0644]
Documentation/filesystems/ext4.txt
Documentation/kernel-parameters.txt
Documentation/speculation.txt [new file with mode: 0644]
MAINTAINERS
Makefile
arch/Kconfig
arch/alpha/kernel/pci_impl.h
arch/alpha/kernel/process.c
arch/arc/kernel/process.c
arch/arm/Kconfig
arch/arm/boot/compressed/string.c
arch/arm/boot/dts/am4372.dtsi
arch/arm/boot/dts/omap4.dtsi
arch/arm/boot/dts/qcom/msm8996-auto-mizar.dts
arch/arm/boot/dts/qcom/msm8996-cv2x.dtsi
arch/arm/boot/dts/qcom/vplatform-lfv-msm-pm8994.dtsi [new file with mode: 0644]
arch/arm/boot/dts/qcom/vplatform-lfv-msm8996-common.dtsi
arch/arm/boot/dts/qcom/vplatform-lfv-msm8996-ivi-lv-mt.dts
arch/arm/boot/dts/qcom/vplatform-lfv-msm8996-ivi.dts
arch/arm/boot/dts/qcom/vplatform-lfv-msm8996-telematics.dts
arch/arm/boot/dts/qcom/vplatform-lfv-msm8996-usb.dtsi
arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dtsi
arch/arm/boot/dts/s5pv210.dtsi
arch/arm/boot/dts/spear1310-evb.dts
arch/arm/boot/dts/spear1340.dtsi
arch/arm/boot/dts/spear13xx.dtsi
arch/arm/boot/dts/spear600.dtsi
arch/arm/boot/dts/stih407.dtsi
arch/arm/boot/dts/stih410.dtsi
arch/arm/crypto/Kconfig
arch/arm/crypto/Makefile
arch/arm/crypto/speck-neon-core.S [new file with mode: 0644]
arch/arm/crypto/speck-neon-glue.c [new file with mode: 0644]
arch/arm/kernel/process.c
arch/arm/kvm/handle_exit.c
arch/arm/mach-omap2/omap-secure.c
arch/arm/mach-omap2/omap-secure.h
arch/arm/mach-omap2/pm.h
arch/arm/mach-omap2/pm34xx.c
arch/arm/mach-omap2/prm33xx.c
arch/arm/mach-omap2/sleep34xx.S
arch/arm/mach-pxa/tosa-bt.c
arch/arm/mach-tegra/Kconfig
arch/arm/vfp/vfpmodule.c
arch/arm64/Kconfig
arch/arm64/Kconfig.platforms
arch/arm64/boot/dts/mediatek/mt8173.dtsi
arch/arm64/configs/msm-auto-gvm-perf_defconfig
arch/arm64/configs/msm-auto-gvm_defconfig
arch/arm64/configs/msm-auto-perf_defconfig
arch/arm64/configs/msm-auto_defconfig
arch/arm64/include/asm/bug.h
arch/arm64/kernel/image.h
arch/arm64/kernel/process.c
arch/arm64/lib/strnlen.S
arch/avr32/Kconfig
arch/avr32/kernel/process.c
arch/blackfin/include/asm/processor.h
arch/c6x/kernel/process.c
arch/cris/Kconfig
arch/cris/arch-v10/kernel/process.c
arch/cris/arch-v32/kernel/process.c
arch/frv/include/asm/processor.h
arch/h8300/include/asm/processor.h
arch/hexagon/kernel/process.c
arch/ia64/Kconfig
arch/ia64/kernel/perfmon.c
arch/ia64/kernel/process.c
arch/m32r/kernel/process.c
arch/m68k/include/asm/processor.h
arch/metag/Kconfig
arch/metag/include/asm/processor.h
arch/metag/kernel/process.c
arch/microblaze/include/asm/processor.h
arch/mips/Kbuild.platforms
arch/mips/Kconfig
arch/mips/Makefile
arch/mips/alchemy/common/dbdma.c
arch/mips/alchemy/common/setup.c
arch/mips/bmips/setup.c
arch/mips/boot/Makefile
arch/mips/cavium-octeon/executive/cvmx-interrupt-decodes.c
arch/mips/cavium-octeon/executive/cvmx-pko.c
arch/mips/cavium-octeon/smp.c
arch/mips/configs/generic/32r1.config [new file with mode: 0644]
arch/mips/configs/generic/32r2.config [new file with mode: 0644]
arch/mips/configs/generic/32r6.config [new file with mode: 0644]
arch/mips/configs/generic/64r1.config [new file with mode: 0644]
arch/mips/configs/generic/64r2.config [new file with mode: 0644]
arch/mips/configs/generic/64r6.config [new file with mode: 0644]
arch/mips/configs/generic/board-ranchu.config [new file with mode: 0644]
arch/mips/configs/generic/eb.config [new file with mode: 0644]
arch/mips/configs/generic/el.config [new file with mode: 0644]
arch/mips/configs/generic/micro32r2.config [new file with mode: 0644]
arch/mips/configs/generic_defconfig [new file with mode: 0644]
arch/mips/configs/ranchu32r5_defconfig [new file with mode: 0644]
arch/mips/configs/ranchu32r6_defconfig [new file with mode: 0644]
arch/mips/configs/ranchu64_defconfig [new file with mode: 0644]
arch/mips/configs/ranchu_defconfig [new file with mode: 0644]
arch/mips/dec/int-handler.S
arch/mips/fw/arc/memory.c
arch/mips/generic/Kconfig [new file with mode: 0644]
arch/mips/generic/Makefile [new file with mode: 0644]
arch/mips/generic/Platform [new file with mode: 0644]
arch/mips/generic/board-ranchu.c [new file with mode: 0644]
arch/mips/generic/init.c [new file with mode: 0644]
arch/mips/generic/irq.c [new file with mode: 0644]
arch/mips/generic/proc.c [new file with mode: 0644]
arch/mips/generic/vmlinux.its.S [new file with mode: 0644]
arch/mips/include/asm/bootinfo.h
arch/mips/include/asm/cpu-features.h
arch/mips/include/asm/cpu-info.h
arch/mips/include/asm/cpu.h
arch/mips/include/asm/device.h
arch/mips/include/asm/dma-coherence.h
arch/mips/include/asm/dma-mapping.h
arch/mips/include/asm/dsemul.h [new file with mode: 0644]
arch/mips/include/asm/elf.h
arch/mips/include/asm/fpu_emulator.h
arch/mips/include/asm/irq_regs.h
arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h
arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h
arch/mips/include/asm/mach-generic/dma-coherence.h
arch/mips/include/asm/mach-generic/kernel-entry-init.h
arch/mips/include/asm/mach-ip27/irq.h
arch/mips/include/asm/mach-ip27/kernel-entry-init.h
arch/mips/include/asm/mach-jz4740/gpio.h
arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h
arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
arch/mips/include/asm/machine.h [new file with mode: 0644]
arch/mips/include/asm/mips-cm.h
arch/mips/include/asm/mips-cpc.h
arch/mips/include/asm/mips-r2-to-r6-emul.h
arch/mips/include/asm/mipsregs.h
arch/mips/include/asm/mmu.h
arch/mips/include/asm/mmu_context.h
arch/mips/include/asm/octeon/cvmx-config.h
arch/mips/include/asm/octeon/cvmx.h
arch/mips/include/asm/page.h
arch/mips/include/asm/pci/bridge.h
arch/mips/include/asm/processor.h
arch/mips/include/asm/r4kcache.h
arch/mips/include/asm/sgi/hpc3.h
arch/mips/include/asm/sgiarcs.h
arch/mips/include/asm/smp-cps.h
arch/mips/include/asm/sn/ioc3.h
arch/mips/include/asm/sn/sn0/hubio.h
arch/mips/include/asm/switch_to.h
arch/mips/include/asm/uaccess.h
arch/mips/include/asm/vdso.h
arch/mips/include/uapi/asm/inst.h
arch/mips/kernel/binfmt_elfn32.c
arch/mips/kernel/binfmt_elfo32.c
arch/mips/kernel/branch.c
arch/mips/kernel/cps-vec.S
arch/mips/kernel/cpu-probe.c
arch/mips/kernel/elf.c
arch/mips/kernel/head.S
arch/mips/kernel/linux32.c
arch/mips/kernel/mips-cm.c
arch/mips/kernel/mips-cpc.c
arch/mips/kernel/mips-r2-to-r6-emul.c
arch/mips/kernel/perf_event_mipsxx.c
arch/mips/kernel/pm-cps.c
arch/mips/kernel/process.c
arch/mips/kernel/ptrace.c
arch/mips/kernel/setup.c
arch/mips/kernel/signal.c
arch/mips/kernel/smp-cps.c
arch/mips/kernel/smp.c
arch/mips/kernel/traps.c
arch/mips/kernel/unaligned.c
arch/mips/kernel/vdso.c
arch/mips/kvm/tlb.c
arch/mips/kvm/trap_emul.c
arch/mips/math-emu/Makefile
arch/mips/math-emu/cp1emu.c
arch/mips/math-emu/dp_add.c
arch/mips/math-emu/dp_div.c
arch/mips/math-emu/dp_fmax.c
arch/mips/math-emu/dp_fmin.c
arch/mips/math-emu/dp_maddf.c
arch/mips/math-emu/dp_msubf.c [deleted file]
arch/mips/math-emu/dp_mul.c
arch/mips/math-emu/dp_rint.c [new file with mode: 0644]
arch/mips/math-emu/dp_simple.c
arch/mips/math-emu/dp_sqrt.c
arch/mips/math-emu/dp_sub.c
arch/mips/math-emu/dp_tint.c
arch/mips/math-emu/dp_tlong.c
arch/mips/math-emu/dsemul.c
arch/mips/math-emu/ieee754.c
arch/mips/math-emu/ieee754.h
arch/mips/math-emu/ieee754dp.c
arch/mips/math-emu/ieee754dp.h
arch/mips/math-emu/ieee754int.h
arch/mips/math-emu/ieee754sp.c
arch/mips/math-emu/ieee754sp.h
arch/mips/math-emu/me-debugfs.c
arch/mips/math-emu/sp_add.c
arch/mips/math-emu/sp_div.c
arch/mips/math-emu/sp_fdp.c
arch/mips/math-emu/sp_fint.c
arch/mips/math-emu/sp_fmax.c
arch/mips/math-emu/sp_fmin.c
arch/mips/math-emu/sp_maddf.c
arch/mips/math-emu/sp_msubf.c [deleted file]
arch/mips/math-emu/sp_mul.c
arch/mips/math-emu/sp_rint.c [new file with mode: 0644]
arch/mips/math-emu/sp_simple.c
arch/mips/math-emu/sp_sqrt.c
arch/mips/math-emu/sp_sub.c
arch/mips/math-emu/sp_tint.c
arch/mips/math-emu/sp_tlong.c
arch/mips/mm/c-r4k.c
arch/mips/mm/dma-default.c
arch/mips/mm/sc-ip22.c
arch/mips/mm/sc-mips.c
arch/mips/mm/tlbex.c
arch/mips/mti-malta/malta-init.c
arch/mips/mti-malta/malta-setup.c
arch/mips/pci/pci-alchemy.c
arch/mips/sgi-ip27/ip27-memory.c
arch/mips/sgi-ip27/ip27-nmi.c
arch/mips/sgi-ip27/ip27-xtalk.c
arch/mips/sni/rm200.c
arch/mips/vdso/gettimeofday.c
arch/mn10300/Kconfig
arch/mn10300/include/asm/fpu.h
arch/mn10300/kernel/process.c
arch/mn10300/mm/misalignment.c
arch/nios2/include/asm/processor.h
arch/openrisc/include/asm/processor.h
arch/openrisc/kernel/traps.c
arch/parisc/kernel/process.c
arch/powerpc/Kconfig
arch/powerpc/include/asm/exception-64e.h
arch/powerpc/include/asm/exception-64s.h
arch/powerpc/include/asm/feature-fixups.h
arch/powerpc/include/asm/hvcall.h
arch/powerpc/include/asm/paca.h
arch/powerpc/include/asm/plpar_wrappers.h
arch/powerpc/include/asm/ppc_asm.h
arch/powerpc/include/asm/setup.h
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kernel/entry_64.S
arch/powerpc/kernel/exceptions-64s.S
arch/powerpc/kernel/misc_64.S
arch/powerpc/kernel/module_64.c
arch/powerpc/kernel/process.c
arch/powerpc/kernel/setup_64.c
arch/powerpc/kernel/vmlinux.lds.S
arch/powerpc/kvm/book3s_hv_rmhandlers.S
arch/powerpc/kvm/book3s_rmhandlers.S
arch/powerpc/kvm/book3s_segment.S
arch/powerpc/lib/feature-fixups.c
arch/powerpc/perf/core-book3s.c
arch/powerpc/platforms/powernv/setup.c
arch/powerpc/platforms/pseries/setup.c
arch/s390/kernel/compat_linux.c
arch/s390/kernel/process.c
arch/score/kernel/process.c
arch/sh/Kconfig
arch/sh/kernel/process_32.c
arch/sh/kernel/process_64.c
arch/sh/kernel/traps_32.c
arch/sparc/Kconfig
arch/sparc/kernel/process_32.c
arch/sparc/kernel/process_64.c
arch/tile/Kconfig
arch/tile/kernel/process.c
arch/um/kernel/process.c
arch/unicore32/kernel/process.c
arch/x86/Kconfig
arch/x86/Kconfig.debug
arch/x86/boot/Makefile
arch/x86/crypto/poly1305_glue.c
arch/x86/crypto/twofish-x86_64-asm_64-3way.S
arch/x86/entry/common.c
arch/x86/include/asm/asm-prototypes.h
arch/x86/include/asm/asm.h
arch/x86/include/asm/barrier.h
arch/x86/include/asm/microcode_amd.h
arch/x86/include/asm/msr.h
arch/x86/include/asm/nospec-branch.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/vmx.h
arch/x86/include/asm/vsyscall.h
arch/x86/kernel/alternative.c
arch/x86/kernel/cpu/bugs.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/mcheck/mce-inject.c
arch/x86/kernel/cpu/microcode/amd.c
arch/x86/kernel/cpu/microcode/core.c
arch/x86/kernel/cpu/microcode/intel.c
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/cpu/proc.c
arch/x86/kernel/head_32.S
arch/x86/kernel/process.c
arch/x86/kvm/Kconfig
arch/x86/kvm/emulate.c
arch/x86/kvm/mmu.c
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/lib/getuser.S
arch/x86/lib/retpoline.S
arch/x86/math-emu/Makefile
arch/x86/math-emu/reg_compare.c
arch/x86/mm/ioremap.c
arch/x86/mm/kaiser.c
arch/x86/mm/kmmio.c
arch/x86/platform/olpc/olpc-xo15-sci.c
arch/xtensa/Kconfig
arch/xtensa/include/asm/futex.h
arch/xtensa/kernel/process.c
certs/Makefile
crypto/Kconfig
crypto/Makefile
crypto/ahash.c
crypto/cryptd.c
crypto/poly1305_generic.c
crypto/speck.c [new file with mode: 0644]
crypto/tcrypt.c
crypto/testmgr.c
crypto/testmgr.h
drivers/Makefile
drivers/acpi/sbshc.c
drivers/android/binder.c
drivers/ata/ahci.c
drivers/block/pktcdvd.c
drivers/bluetooth/btsdio.c
drivers/bluetooth/btusb.c
drivers/char/hw_random/exynos-rng.c
drivers/clk/msm/clock-dummy.c
drivers/clk/msm/mdss/mdss-dsi-pll-8996-util.c
drivers/clk/qcom/mmcc-sdm660.c
drivers/crypto/caam/ctrl.c
drivers/crypto/s5p-sss.c
drivers/devfreq/devfreq.c
drivers/dma/at_hdmac.c
drivers/dma/dma-jz4740.c
drivers/dma/dmatest.c
drivers/dma/ioat/init.c
drivers/dma/zx296702_dma.c
drivers/edac/octeon_edac-lmc.c
drivers/gpio/gpio-intel-mid.c
drivers/gpio/gpio-xgene.c
drivers/gpu/drm/armada/armada_crtc.c
drivers/gpu/drm/drm_modeset_lock.c
drivers/gpu/drm/gma500/mdfld_dsi_dpi.c
drivers/gpu/drm/gma500/mdfld_dsi_output.c
drivers/gpu/drm/msm-hyp/msm_drv_hyp.c
drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_1_4.c
drivers/gpu/drm/msm/dsi-staging/dsi_display.c
drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
drivers/gpu/drm/msm/hdmi/hdmi.h
drivers/gpu/drm/msm/msm_drv.h
drivers/gpu/drm/msm/sde/sde_connector.c
drivers/gpu/drm/msm/sde/sde_connector.h
drivers/gpu/drm/msm/sde/sde_crtc.c
drivers/gpu/drm/msm/sde/sde_encoder.c
drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
drivers/gpu/drm/msm/sde/sde_kms.c
drivers/gpu/drm/msm/sde/sde_plane.c
drivers/gpu/drm/nouveau/nouveau_gem.c
drivers/gpu/drm/radeon/radeon_uvd.c
drivers/gpu/drm/rcar-du/rcar_du_crtc.c
drivers/gpu/drm/rcar-du/rcar_du_crtc.h
drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c
drivers/gpu/msm/kgsl.c
drivers/gpu/msm/kgsl.h
drivers/gpu/msm/kgsl_device.h
drivers/hid/hid-core.c
drivers/hv/hv.c
drivers/i2c/busses/i2c-msm-v2.c
drivers/i2c/i2c-boardinfo.c
drivers/idle/Kconfig
drivers/iio/adc/axp288_adc.c
drivers/infiniband/core/cma.c
drivers/infiniband/hw/cxgb4/device.c
drivers/infiniband/hw/mlx4/main.c
drivers/input/keyboard/tca8418_keypad.c
drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c
drivers/irqchip/Kconfig
drivers/irqchip/Makefile
drivers/irqchip/irq-goldfish-pic.c [new file with mode: 0644]
drivers/irqchip/irq-mips-gic.c
drivers/isdn/hardware/eicon/message.c
drivers/isdn/icn/icn.c
drivers/isdn/sc/init.c
drivers/md/dm.c
drivers/md/md.c
drivers/media/common/b2c2/flexcop-fe-tuner.c
drivers/media/dvb-frontends/ts2020.c
drivers/media/i2c/s5k6aa.c
drivers/media/i2c/tc358743.c
drivers/media/platform/msm/ais/camera/camera.c
drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
drivers/media/platform/msm/vidc/msm_vidc_common.c
drivers/media/platform/soc_camera/soc_scale_crop.c
drivers/media/tuners/r820t.c
drivers/media/usb/dvb-usb-v2/lmedm04.c
drivers/media/usb/dvb-usb/cxusb.c
drivers/media/usb/dvb-usb/dib0700_devices.c
drivers/media/usb/em28xx/Kconfig
drivers/media/usb/go7007/Kconfig
drivers/media/usb/hdpvr/hdpvr-core.c
drivers/media/usb/pwc/pwc-if.c
drivers/media/v4l2-core/Kconfig
drivers/media/v4l2-core/v4l2-compat-ioctl32.c
drivers/media/v4l2-core/v4l2-ioctl.c
drivers/media/v4l2-core/videobuf2-v4l2.c
drivers/message/fusion/mptbase.c
drivers/misc/profiler.c
drivers/mmc/core/sd.c
drivers/mtd/chips/Kconfig
drivers/mtd/maps/ck804xrom.c
drivers/mtd/maps/esb2rom.c
drivers/mtd/maps/ichxrom.c
drivers/mtd/nand/brcmnand/brcmnand.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/sh_flctl.c
drivers/mtd/nand/sunxi_nand.c
drivers/mtd/ubi/block.c
drivers/net/Kconfig
drivers/net/ethernet/3com/3c509.c
drivers/net/ethernet/3com/3c59x.c
drivers/net/ethernet/amd/xgbe/xgbe-main.c
drivers/net/ethernet/dec/tulip/de4x5.c
drivers/net/ethernet/freescale/gianfar.c
drivers/net/ethernet/hp/hp100.c
drivers/net/ethernet/marvell/mvpp2.c
drivers/net/ethernet/mellanox/mlx4/qp.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/ti/tlan.c
drivers/net/hippi/rrunner.c
drivers/net/ipvlan/ipvlan_core.c
drivers/net/usb/Kconfig
drivers/net/usb/Makefile
drivers/net/usb/cdc_ncm.c
drivers/net/wireless/ath/ath10k/core.c
drivers/net/wireless/ath/ath10k/testmode.c
drivers/net/wireless/ath/ath10k/wow.c
drivers/net/wireless/cw1200/cw1200_spi.c
drivers/net/wireless/cw1200/pm.h
drivers/net/wireless/cw1200/wsm.c
drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c
drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
drivers/net/wireless/realtek/rtlwifi/wifi.h
drivers/nvme/host/pci.c
drivers/pinctrl/sunxi/pinctrl-sun9i-a80.c
drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
drivers/platform/x86/Kconfig
drivers/platform/x86/intel_mid_thermal.c
drivers/platform/x86/tc1100-wmi.c
drivers/power/Kconfig
drivers/power/bq27xxx_battery.c
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-goldfish.c [new file with mode: 0644]
drivers/rtc/rtc-opal.c
drivers/s390/block/dasd_eckd.c
drivers/scsi/advansys.c
drivers/scsi/dpt_i2o.c
drivers/scsi/fdomain.c
drivers/scsi/g_NCR5380.c
drivers/scsi/initio.c
drivers/scsi/mvumi.c
drivers/scsi/sim710.c
drivers/scsi/ufs/ufshcd.c
drivers/soc/qcom/Makefile
drivers/soc/qcom/scm_qcpe.c
drivers/soc/qcom/subsystem_notif_virt.c [new file with mode: 0644]
drivers/spi/spi-sun4i.c
drivers/spmi/virtspmi-pmic-arb.c
drivers/ssb/main.c
drivers/staging/android/ashmem.c
drivers/staging/iio/adc/ad7192.c
drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c
drivers/staging/unisys/visorinput/Kconfig
drivers/staging/wilc1000/wilc_wlan_if.h
drivers/target/target_core_user.c
drivers/tee/optee/Makefile
drivers/tee/optee/call.c
drivers/tee/optee/core.c
drivers/tee/optee/optee_msg.h
drivers/tee/optee/optee_private.h
drivers/tee/optee/optee_smc.h
drivers/tee/optee/rpc.c
drivers/tee/optee/shm_pool.c [new file with mode: 0644]
drivers/tee/optee/shm_pool.h [new file with mode: 0644]
drivers/tee/optee/supp.c
drivers/tee/tee_core.c
drivers/tee/tee_private.h
drivers/tee/tee_shm.c
drivers/tee/tee_shm_pool.c
drivers/thermal/Kconfig
drivers/thermal/spear_thermal.c
drivers/tty/Kconfig
drivers/tty/goldfish.c
drivers/tty/hvc/hvc_xen.c
drivers/tty/serial/8250/Kconfig
drivers/usb/gadget/function/uvc_configfs.c
drivers/usb/host/Kconfig
drivers/usb/musb/ux500_dma.c
drivers/usb/phy/Kconfig
drivers/usb/usbip/stub_dev.c
drivers/usb/usbip/vhci_hcd.c
drivers/usb/usbip/vhci_sysfs.c
drivers/vhost/net.c
drivers/video/console/dummycon.c
drivers/video/fbdev/Kconfig
drivers/video/fbdev/atmel_lcdfb.c
drivers/video/fbdev/auo_k190x.c
drivers/video/fbdev/exynos/s6e8ax0.c
drivers/video/fbdev/intelfb/intelfbdrv.c
drivers/video/fbdev/mmp/core.c
drivers/video/fbdev/msm/mdss.h
drivers/video/fbdev/msm/mdss_mdp.c
drivers/video/fbdev/msm/mdss_mdp_ctl.c
drivers/video/fbdev/msm/mdss_mdp_overlay.c
drivers/video/fbdev/msm/mdss_mdp_pp.c
drivers/video/fbdev/msm/msm_dba/adv7533.c
drivers/video/fbdev/sis/init301.c
drivers/video/fbdev/sm712fb.c
drivers/video/fbdev/via/viafbdev.c
drivers/virtio/virtio_balloon.c
drivers/watchdog/imx2_wdt.c
drivers/xen/Kconfig
fs/binfmt_elf.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/tree-log.c
fs/cifs/cifsencrypt.c
fs/cifs/connect.c
fs/cifs/file.c
fs/cifs/misc.c
fs/cifs/smb2pdu.c
fs/compat_binfmt_elf.c
fs/ext4/inode.c
fs/ext4/namei.c
fs/ext4/super.c
fs/ext4/symlink.c
fs/f2fs/checkpoint.c
fs/f2fs/data.c
fs/f2fs/debug.c
fs/f2fs/dir.c
fs/f2fs/f2fs.h
fs/f2fs/file.c
fs/f2fs/gc.c
fs/f2fs/gc.h
fs/f2fs/inode.c
fs/f2fs/namei.c
fs/f2fs/node.c
fs/f2fs/node.h
fs/f2fs/recovery.c
fs/f2fs/segment.c
fs/f2fs/segment.h
fs/f2fs/super.c
fs/f2fs/sysfs.c
fs/f2fs/trace.c
fs/f2fs/xattr.c
fs/inode.c
fs/kernfs/file.c
fs/namei.c
fs/ncpfs/dir.c
fs/nfs/direct.c
fs/nfs/nfs4idmap.c
fs/nfs/pnfs.c
fs/nfs/write.c
fs/nsfs.c
fs/overlayfs/readdir.c
fs/reiserfs/lbalance.c
fs/reiserfs/reiserfs.h
fs/sdcardfs/file.c
include/crypto/internal/hash.h
include/crypto/poly1305.h
include/crypto/speck.h [new file with mode: 0644]
include/linux/device.h
include/linux/f2fs_fs.h
include/linux/fdtable.h
include/linux/fs.h
include/linux/i2c/i2c-msm-v2.h
include/linux/init.h
include/linux/irqchip/mips-gic.h
include/linux/kaiser.h
include/linux/migrate.h
include/linux/module.h
include/linux/msi.h
include/linux/mtd/map.h
include/linux/mtd/sh_flctl.h
include/linux/nospec.h [new file with mode: 0644]
include/linux/sched.h
include/linux/string.h
include/linux/tee_drv.h
include/net/dst_cache.h [new file with mode: 0644]
include/net/ip6_tunnel.h
include/net/netfilter/nf_queue.h
include/net/netlink.h
include/net/netns/netfilter.h
include/net/red.h
include/sound/apr_audio-v2.h
include/sound/q6adm-v2.h
include/sound/q6afe-v2.h
include/trace/events/clk.h
include/trace/events/f2fs.h
include/uapi/linux/tee.h
kernel/async.c
kernel/configs/android-base.config [new file with mode: 0644]
kernel/configs/android-recommended.config [new file with mode: 0644]
kernel/exit.c
kernel/module.c
kernel/profile.c
kernel/sched/core.c
kernel/sched/fair.c
kernel/sched/rt.c
kernel/sched/sched.h
kernel/sched/sched_avg.c
kernel/time/posix-timers.c
kernel/time/timekeeping.c
kernel/trace/blktrace.c
kernel/trace/ftrace.c
lib/Kconfig.debug
lib/oid_registry.c
mm/compaction.c
mm/early_ioremap.c
mm/memory.c
mm/memory_hotplug.c
mm/migrate.c
mm/page_alloc.c
mm/util.c
mm/vmscan.c
net/Kconfig
net/core/Makefile
net/core/dev.c
net/core/dst_cache.c [new file with mode: 0644]
net/dccp/proto.c
net/decnet/af_decnet.c
net/ipv4/igmp.c
net/ipv4/ip_sockglue.c
net/ipv4/ipconfig.c
net/ipv4/netfilter/ipt_CLUSTERIP.c
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
net/ipv4/tcp.c
net/ipv6/Kconfig
net/ipv6/ip6_gre.c
net/ipv6/ip6_tunnel.c
net/ipv6/ip6_vti.c
net/ipv6/ip6mr.c
net/ipv6/ipv6_sockglue.c
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
net/netfilter/ipvs/ip_vs_app.c
net/netfilter/ipvs/ip_vs_ctl.c
net/netfilter/nf_queue.c
net/netfilter/nfnetlink_queue.c
net/netfilter/x_tables.c
net/netfilter/xt_RATEEST.c
net/netfilter/xt_qtaguid.c
net/sched/sch_choke.c
net/sched/sch_gred.c
net/sched/sch_red.c
net/sched/sch_sfq.c
net/wireless/core.c
net/wireless/nl80211.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_user.c
scripts/dtc/checks.c
scripts/dtc/dt_to_config [new file with mode: 0755]
scripts/dtc/dtc-lexer.l
scripts/dtc/dtc-lexer.lex.c_shipped
scripts/dtc/dtc-parser.tab.c_shipped
scripts/dtc/dtc-parser.tab.h_shipped
scripts/dtc/dtc-parser.y
scripts/dtc/dtc.c
scripts/dtc/dtc.h
scripts/dtc/dtx_diff [new file with mode: 0755]
scripts/dtc/flattree.c
scripts/dtc/fstree.c
scripts/dtc/libfdt/Makefile.libfdt
scripts/dtc/libfdt/fdt.c
scripts/dtc/libfdt/fdt_ro.c
scripts/dtc/libfdt/fdt_rw.c
scripts/dtc/libfdt/fdt_strerror.c
scripts/dtc/libfdt/fdt_wip.c
scripts/dtc/libfdt/libfdt.h
scripts/dtc/libfdt/libfdt_env.h
scripts/dtc/livetree.c
scripts/dtc/srcpos.c
scripts/dtc/srcpos.h
scripts/dtc/treesource.c
scripts/dtc/util.c
scripts/dtc/util.h
scripts/dtc/version_gen.h
scripts/genksyms/parse.tab.c_shipped
scripts/genksyms/parse.tab.h_shipped
scripts/genksyms/parse.y
scripts/kernel-doc
scripts/mod/modpost.c
security/keys/encrypted-keys/encrypted.c
security/selinux/ss/services.c
sound/core/seq/seq_clientmgr.c
sound/pci/hda/patch_ca0132.c
sound/pci/hda/patch_realtek.c
sound/soc/codecs/pcm512x-spi.c
sound/soc/generic/simple-card.c
sound/soc/intel/Kconfig
sound/soc/mediatek/Kconfig
sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
sound/soc/msm/qdsp6v2/msm-transcode-loopback-q6-v2.c
sound/soc/msm/qdsp6v2/q6adm.c
sound/soc/msm/qdsp6v2/q6afe.c
sound/soc/msm/qdsp6v2/q6asm.c
sound/soc/rockchip/rockchip_spdif.c
sound/soc/sh/rcar/rsnd.h
sound/soc/sh/rcar/ssi.c
sound/soc/ux500/mop500.c
sound/soc/ux500/ux500_pcm.c
sound/usb/mixer.c
sound/usb/pcm.c
tools/build/Makefile.build
tools/perf/bench/numa.c
tools/perf/builtin-top.c
tools/scripts/Makefile.include

index b1e9a97..8cbe2bd 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -14,6 +14,7 @@ Adrian Bunk <bunk@stusta.de>
 Alan Cox <alan@lxorguk.ukuu.org.uk>
 Alan Cox <root@hraefn.swansea.linux.org.uk>
 Aleksey Gorelov <aleksey_gorelov@phoenix.com>
+Aleksandar Markovic <aleksandar.markovic@mips.com> <aleksandar.markovic@imgtec.com>
 Al Viro <viro@ftp.linux.org.uk>
 Al Viro <viro@zenIV.linux.org.uk>
 Andreas Herrmann <aherrman@de.ibm.com>
@@ -85,6 +86,7 @@ Matthieu CASTET <castet.matthieu@free.fr>
 Mayuresh Janorkar <mayur@ti.com>
 Michael Buesch <m@bues.ch>
 Michel Dänzer <michel@tungstengraphics.com>
+Miodrag Dinic <miodrag.dinic@mips.com> <miodrag.dinic@imgtec.com>
 Mitesh shah <mshah@teja.com>
 Mohit Kumar <mohit.kumar@st.com> <mohit.kumar.dhaka@gmail.com>
 Morten Welinder <terra@gnome.org>
index 2baed11..db7aab1 100644 (file)
@@ -186,3 +186,9 @@ Date:               August 2017
 Contact:       "Jaegeuk Kim" <jaegeuk@kernel.org>
 Description:
                 Controls sleep time of GC urgent mode
+
+What:          /sys/fs/f2fs/<disk>/readdir_ra
+Date:          November 2017
+Contact:       "Sheng Yong" <shengyong1@huawei.com>
+Description:
+                Controls readahead inode block in readdir.
diff --git a/Documentation/devicetree/bindings/arm/msm/subsystem_notif_virt.txt b/Documentation/devicetree/bindings/arm/msm/subsystem_notif_virt.txt
new file mode 100644 (file)
index 0000000..50fffbe
--- /dev/null
@@ -0,0 +1,35 @@
+Subsystem Notification Virtual Driver
+
+The guest VM uses this driver to communicate
+subsystem state notifications to a backend driver
+via the virtual device's registers.
+
+[Root level node]
+Required Properties:
+-compatible : Should be "qcom,subsys-notif-virt"
+       for notifications regarding state.
+-reg : The start and size of the virtual device's
+       register set.
+-reg-names :  Should be "vdev_base" for virtual device's
+       base address.
+-subsys-names : The name of the subsystem that the
+       driver is registering to notifications for.
+-offset : The offset from the virtual device's register
+       base where the subsystem state will be written.
+
+Example:
+
+       subsys_notif_virt: qcom,subsys_notif_virt@2D000000 {
+               compatible = "qcom,subsys-notif-virt";
+               reg = <0x2D000000 0x10>;
+               reg-names = "vdev_base";
+               adsp {
+                       subsys-name = "adsp";
+                       offset = <0>;
+               };
+               mpss {
+                       subsys-name = "modem";
+                       offset = <8>;
+               };
+       };
+
diff --git a/Documentation/devicetree/bindings/display/google,goldfish-fb.txt b/Documentation/devicetree/bindings/display/google,goldfish-fb.txt
new file mode 100644 (file)
index 0000000..751fa9f
--- /dev/null
@@ -0,0 +1,17 @@
+Android Goldfish framebuffer
+
+Android Goldfish framebuffer device used by Android emulator.
+
+Required properties:
+
+- compatible : should contain "google,goldfish-fb"
+- reg        : <registers mapping>
+- interrupts : <interrupt mapping>
+
+Example:
+
+       display-controller@1f008000 {
+               compatible = "google,goldfish-fb";
+               interrupts = <0x10>;
+               reg = <0x1f008000 0x100>;
+       };
index c261598..17d43ca 100644 (file)
@@ -58,6 +58,6 @@ Example:
                interrupts = <0 35 0x4>;
                status = "disabled";
                dmas = <&dmahost 12 0 1>,
-                       <&dmahost 13 1 0>;
+                       <&dmahost 13 1 0>;
                dma-names = "rx", "rx";
        };
index fa3abb2..0413013 100644 (file)
@@ -16,6 +16,8 @@ Required properties:
  - dma-names :  dma channel names.
  - qcom,clk-freq-out : Desired I2C bus clock frequency in Hz
  - qcom,clk-freq-in  : Supplied core clock frequency in Hz.
+ - qcom,i2c-dat : specifies GPIO which corresponds to the I2C data line.
+ - qcom,i2c-clk : specifies GPIO which corresponds to the I2C clock line.
 
 Required alias:
  - The desired bus-number is specified by an alias with the following format:
@@ -51,5 +53,7 @@ Example:
                qcom,clk-freq-in  = <24000000>;
                qcom,noise-rjct-scl = <0>;
                qcom,noise-rjct-sda = <0>;
+               qcom,i2c-dat = <&tlmm 67 0x00>;
+               qcom,i2c-clk = <&tlmm 68 0x00>;
 
        };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/google,goldfish-pic.txt b/Documentation/devicetree/bindings/interrupt-controller/google,goldfish-pic.txt
new file mode 100644 (file)
index 0000000..35f7527
--- /dev/null
@@ -0,0 +1,30 @@
+Android Goldfish PIC
+
+Android Goldfish programmable interrupt device used by Android
+emulator.
+
+Required properties:
+
+- compatible : should contain "google,goldfish-pic"
+- reg        : <registers mapping>
+- interrupts : <interrupt mapping>
+
+Example for mips when used in cascade mode:
+
+        cpuintc {
+                #interrupt-cells = <0x1>;
+                #address-cells = <0>;
+                interrupt-controller;
+                compatible = "mti,cpu-interrupt-controller";
+        };
+
+        interrupt-controller@1f000000 {
+                compatible = "google,goldfish-pic";
+                reg = <0x1f000000 0x1000>;
+
+                interrupt-controller;
+                #interrupt-cells = <0x1>;
+
+                interrupt-parent = <&cpuintc>;
+                interrupts = <0x2>;
+        };
diff --git a/Documentation/devicetree/bindings/power/mti,mips-cpc.txt b/Documentation/devicetree/bindings/power/mti,mips-cpc.txt
new file mode 100644 (file)
index 0000000..c6b8251
--- /dev/null
@@ -0,0 +1,8 @@
+Binding for MIPS Cluster Power Controller (CPC).
+
+This binding allows a system to specify where the CPC registers are
+located.
+
+Required properties:
+compatible : Should be "mti,mips-cpc".
+regs: Should describe the address & size of the CPC register region.
diff --git a/Documentation/devicetree/bindings/rtc/google,goldfish-rtc.txt b/Documentation/devicetree/bindings/rtc/google,goldfish-rtc.txt
new file mode 100644 (file)
index 0000000..634312d
--- /dev/null
@@ -0,0 +1,17 @@
+Android Goldfish RTC
+
+Android Goldfish RTC device used by Android emulator.
+
+Required properties:
+
+- compatible : should contain "google,goldfish-rtc"
+- reg        : <registers mapping>
+- interrupts : <interrupt mapping>
+
+Example:
+
+       goldfish_timer@9020000 {
+               compatible = "google,goldfish-rtc";
+               reg = <0x9020000 0x1000>;
+               interrupts = <0x3>;
+       };
index 6c0108e..2139ea2 100644 (file)
@@ -233,7 +233,7 @@ data_err=ignore(*)  Just print an error message if an error occurs
 data_err=abort         Abort the journal if an error occurs in a file
                        data buffer in ordered mode.
 
-grpid                  Give objects the same group ID as their creator.
+grpid                  New objects have the group ID of their parent.
 bsdgroups
 
 nogrpid                (*)     New objects have the group ID of their creator.
index d101831..d3e2943 100644 (file)
@@ -1463,6 +1463,41 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        In such case C2/C3 won't be used again.
                        idle=nomwait: Disable mwait for CPU C-states
 
+       ieee754=        [MIPS] Select IEEE Std 754 conformance mode
+                       Format: { strict | legacy | 2008 | relaxed }
+                       Default: strict
+
+                       Choose which programs will be accepted for execution
+                       based on the IEEE 754 NaN encoding(s) supported by
+                       the FPU and the NaN encoding requested with the value
+                       of an ELF file header flag individually set by each
+                       binary.  Hardware implementations are permitted to
+                       support either or both of the legacy and the 2008 NaN
+                       encoding mode.
+
+                       Available settings are as follows:
+                       strict  accept binaries that request a NaN encoding
+                               supported by the FPU
+                       legacy  only accept legacy-NaN binaries, if supported
+                               by the FPU
+                       2008    only accept 2008-NaN binaries, if supported
+                               by the FPU
+                       relaxed accept any binaries regardless of whether
+                               supported by the FPU
+
+                       The FPU emulator is always able to support both NaN
+                       encodings, so if no FPU hardware is present or it has
+                       been disabled with 'nofpu', then the settings of
+                       'legacy' and '2008' strap the emulator accordingly,
+                       'relaxed' straps the emulator for both legacy-NaN and
+                       2008-NaN, whereas 'strict' enables legacy-NaN only on
+                       legacy processors and both NaN encodings on MIPS32 or
+                       MIPS64 CPUs.
+
+                       The setting for ABS.fmt/NEG.fmt instruction execution
+                       mode generally follows that for the NaN encoding,
+                       except where unsupported by hardware.
+
        ignore_loglevel [KNL]
                        Ignore loglevel setting - this will print /all/
                        kernel messages to the console. Useful for debugging.
@@ -2445,6 +2480,25 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        noexec=on: enable non-executable mappings (default)
                        noexec=off: disable non-executable mappings
 
+       noexec          [MIPS]
+                       Force indicating stack and heap as non-executable or
+                       executable regardless of PT_GNU_STACK entry or CPU XI
+                       (execute inhibit) support. Valid valuess are: on, off.
+                       noexec=on:  force indicating non-executable
+                                   stack and heap
+                       noexec=off: force indicating executable
+                                   stack and heap
+                       If this parameter is omitted, stack and heap will be
+                       indicated non-executable or executable as they are
+                       actually set up, which depends on PT_GNU_STACK entry
+                       and possibly other factors (for instance, CPU XI
+                       support).
+                       NOTE: Using noexec=on on a system without CPU XI
+                       support is not recommended since there is no actual
+                       HW support that provide non-executable stack/heap.
+                       Use only for debugging purposes and not in a
+                       production environment.
+
        nosmap          [X86]
                        Disable SMAP (Supervisor Mode Access Prevention)
                        even if it is supported by processor.
@@ -2581,8 +2635,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
        norandmaps      Don't use address space randomization.  Equivalent to
                        echo 0 > /proc/sys/kernel/randomize_va_space
 
-       noreplace-paravirt      [X86,IA-64,PV_OPS] Don't patch paravirt_ops
-
        noreplace-smp   [X86-32,SMP] Don't replace SMP instructions
                        with UP alternatives
 
diff --git a/Documentation/speculation.txt b/Documentation/speculation.txt
new file mode 100644 (file)
index 0000000..e9e6cba
--- /dev/null
@@ -0,0 +1,90 @@
+This document explains potential effects of speculation, and how undesirable
+effects can be mitigated portably using common APIs.
+
+===========
+Speculation
+===========
+
+To improve performance and minimize average latencies, many contemporary CPUs
+employ speculative execution techniques such as branch prediction, performing
+work which may be discarded at a later stage.
+
+Typically speculative execution cannot be observed from architectural state,
+such as the contents of registers. However, in some cases it is possible to
+observe its impact on microarchitectural state, such as the presence or
+absence of data in caches. Such state may form side-channels which can be
+observed to extract secret information.
+
+For example, in the presence of branch prediction, it is possible for bounds
+checks to be ignored by code which is speculatively executed. Consider the
+following code:
+
+       int load_array(int *array, unsigned int index)
+       {
+               if (index >= MAX_ARRAY_ELEMS)
+                       return 0;
+               else
+                       return array[index];
+       }
+
+Which, on arm64, may be compiled to an assembly sequence such as:
+
+       CMP     <index>, #MAX_ARRAY_ELEMS
+       B.LT    less
+       MOV     <returnval>, #0
+       RET
+  less:
+       LDR     <returnval>, [<array>, <index>]
+       RET
+
+It is possible that a CPU mis-predicts the conditional branch, and
+speculatively loads array[index], even if index >= MAX_ARRAY_ELEMS. This
+value will subsequently be discarded, but the speculated load may affect
+microarchitectural state which can be subsequently measured.
+
+More complex sequences involving multiple dependent memory accesses may
+result in sensitive information being leaked. Consider the following
+code, building on the prior example:
+
+       int load_dependent_arrays(int *arr1, int *arr2, int index)
+       {
+               int val1, val2,
+
+               val1 = load_array(arr1, index);
+               val2 = load_array(arr2, val1);
+
+               return val2;
+       }
+
+Under speculation, the first call to load_array() may return the value
+of an out-of-bounds address, while the second call will influence
+microarchitectural state dependent on this value. This may provide an
+arbitrary read primitive.
+
+====================================
+Mitigating speculation side-channels
+====================================
+
+The kernel provides a generic API to ensure that bounds checks are
+respected even under speculation. Architectures which are affected by
+speculation-based side-channels are expected to implement these
+primitives.
+
+The array_index_nospec() helper in <linux/nospec.h> can be used to
+prevent information from being leaked via side-channels.
+
+A call to array_index_nospec(index, size) returns a sanitized index
+value that is bounded to [0, size) even under cpu speculation
+conditions.
+
+This can be used to protect the earlier load_array() example:
+
+       int load_array(int *array, unsigned int index)
+       {
+               if (index >= MAX_ARRAY_ELEMS)
+                       return 0;
+               else {
+                       index = array_index_nospec(index, MAX_ARRAY_ELEMS);
+                       return array[index];
+               }
+       }
index b09e805..414c3c4 100644 (file)
@@ -746,6 +746,11 @@ W: http://ez.analog.com/community/linux-device-drivers
 S:     Supported
 F:     drivers/dma/dma-axi-dmac.c
 
+ANDROID CONFIG FRAGMENTS
+M:     Rob Herring <robh@kernel.org>
+S:     Supported
+F:     kernel/configs/android*
+
 ANDROID DRIVERS
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 M:     Arve HjønnevÃ¥g <arve@android.com>
@@ -756,6 +761,18 @@ S: Supported
 F:     drivers/android/
 F:     drivers/staging/android/
 
+ANDROID GOLDFISH PIC DRIVER
+M:     Miodrag Dinic <miodrag.dinic@mips.com>
+S:     Supported
+F:     Documentation/devicetree/bindings/interrupt-controller/google,goldfish-pic.txt
+F:     drivers/irqchip/irq-goldfish-pic.c
+
+ANDROID GOLDFISH RTC DRIVER
+M:     Miodrag Dinic <miodrag.dinic@mips.com>
+S:     Supported
+F:     Documentation/devicetree/bindings/rtc/google,goldfish-rtc.txt
+F:     drivers/rtc/rtc-goldfish.c
+
 AOA (Apple Onboard Audio) ALSA DRIVER
 M:     Johannes Berg <johannes@sipsolutions.net>
 L:     linuxppc-dev@lists.ozlabs.org
@@ -7074,6 +7091,20 @@ S:       Supported
 F:     Documentation/mips/
 F:     arch/mips/
 
+MIPS GENERIC PLATFORM
+M:     Paul Burton <paul.burton@imgtec.com>
+L:     linux-mips@linux-mips.org
+S:     Supported
+F:     Documentation/devicetree/bindings/power/mti,mips-cpc.txt
+F:     arch/mips/generic/
+
+MIPS RINT INSTRUCTION EMULATION
+M:     Aleksandar Markovic <aleksandar.markovic@mips.com>
+L:     linux-mips@linux-mips.org
+S:     Supported
+F:     arch/mips/math-emu/sp_rint.c
+F:     arch/mips/math-emu/dp_rint.c
+
 MIROSOUND PCM20 FM RADIO RECEIVER DRIVER
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
@@ -8876,6 +8907,13 @@ S:       Maintained
 F:     Documentation/blockdev/ramdisk.txt
 F:     drivers/block/brd.c
 
+RANCHU VIRTUAL BOARD FOR MIPS
+M:     Miodrag Dinic <miodrag.dinic@mips.com>
+L:     linux-mips@linux-mips.org
+S:     Supported
+F:     arch/mips/generic/board-ranchu.c
+F:     arch/mips/configs/generic/board-ranchu.config
+
 RANDOM NUMBER DRIVER
 M:     "Theodore Ts'o" <tytso@mit.edu>
 S:     Maintained
index 05aa930..77063ad 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 4
 PATCHLEVEL = 4
-SUBLEVEL = 115
+SUBLEVEL = 118
 EXTRAVERSION =
 NAME = Blurry Fish Butt
 
@@ -87,10 +87,12 @@ endif
 ifneq ($(filter 4.%,$(MAKE_VERSION)),) # make-4
 ifneq ($(filter %s ,$(firstword x$(MAKEFLAGS))),)
   quiet=silent_
+  tools_silent=s
 endif
 else                                   # make-3.8x
 ifneq ($(filter s% -s%,$(MAKEFLAGS)),)
   quiet=silent_
+  tools_silent=-s
 endif
 endif
 
@@ -1553,11 +1555,11 @@ image_name:
 # Clear a bunch of variables before executing the submake
 tools/: FORCE
        $(Q)mkdir -p $(objtree)/tools
-       $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(shell cd $(objtree) && /bin/pwd) subdir=tools -C $(src)/tools/
+       $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(tools_silent) $(filter --j% -j,$(MAKEFLAGS))" O=$(shell cd $(objtree) && /bin/pwd) subdir=tools -C $(src)/tools/
 
 tools/%: FORCE
        $(Q)mkdir -p $(objtree)/tools
-       $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(shell cd $(objtree) && /bin/pwd) subdir=tools -C $(src)/tools/ $*
+       $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(tools_silent) $(filter --j% -j,$(MAKEFLAGS))" O=$(shell cd $(objtree) && /bin/pwd) subdir=tools -C $(src)/tools/ $*
 
 # Single targets
 # ---------------------------------------------------------------------------
index ed2539c..a29c609 100644 (file)
@@ -536,6 +536,11 @@ config HAVE_ARCH_MMAP_RND_BITS
          - ARCH_MMAP_RND_BITS_MIN
          - ARCH_MMAP_RND_BITS_MAX
 
+config HAVE_EXIT_THREAD
+       bool
+       help
+         An architecture implements exit_thread.
+
 config ARCH_MMAP_RND_BITS_MIN
        int
 
index 2b0ac42..412bb3c 100644 (file)
@@ -143,7 +143,8 @@ struct pci_iommu_arena
 };
 
 #if defined(CONFIG_ALPHA_SRM) && \
-    (defined(CONFIG_ALPHA_CIA) || defined(CONFIG_ALPHA_LCA))
+    (defined(CONFIG_ALPHA_CIA) || defined(CONFIG_ALPHA_LCA) || \
+     defined(CONFIG_ALPHA_AVANTI))
 # define NEED_SRM_SAVE_RESTORE
 #else
 # undef NEED_SRM_SAVE_RESTORE
index 84d1326..60c17b9 100644 (file)
@@ -210,14 +210,6 @@ start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
 }
 EXPORT_SYMBOL(start_thread);
 
-/*
- * Free current thread data structures etc..
- */
-void
-exit_thread(void)
-{
-}
-
 void
 flush_thread(void)
 {
@@ -273,12 +265,13 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
           application calling fork.  */
        if (clone_flags & CLONE_SETTLS)
                childti->pcb.unique = regs->r20;
+       else
+               regs->r20 = 0;  /* OSF/1 has some strange fork() semantics.  */
        childti->pcb.usp = usp ?: rdusp();
        *childregs = *regs;
        childregs->r0 = 0;
        childregs->r19 = 0;
        childregs->r20 = 1;     /* OSF/1 has some strange fork() semantics.  */
-       regs->r20 = 0;
        stack = ((struct switch_stack *) regs) - 1;
        *childstack = *stack;
        childstack->r26 = (unsigned long) ret_from_fork;
index a3f750e..b5db9e7 100644 (file)
@@ -183,13 +183,6 @@ void flush_thread(void)
 {
 }
 
-/*
- * Free any architecture-specific thread data structures, etc.
- */
-void exit_thread(void)
-{
-}
-
 int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
 {
        return 0;
index 22b546e..162bd82 100644 (file)
@@ -50,6 +50,7 @@ config ARM
        select HAVE_DMA_CONTIGUOUS if MMU
        select HAVE_DYNAMIC_FTRACE if (!XIP_KERNEL) && !CPU_ENDIAN_BE32
        select HAVE_EFFICIENT_UNALIGNED_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && MMU
+       select HAVE_EXIT_THREAD
        select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL)
        select HAVE_FUNCTION_GRAPH_TRACER if (!THUMB2_KERNEL)
        select HAVE_FUNCTION_TRACER if (!XIP_KERNEL)
index 36e53ef..6894674 100644 (file)
@@ -65,6 +65,15 @@ size_t strlen(const char *s)
        return sc - s;
 }
 
+size_t strnlen(const char *s, size_t count)
+{
+       const char *sc;
+
+       for (sc = s; count-- && *sc != '\0'; ++sc)
+               /* nothing */;
+       return sc - s;
+}
+
 int memcmp(const void *cs, const void *ct, size_t count)
 {
        const unsigned char *su1 = cs, *su2 = ct, *end = su1 + count;
index de8791a..3ef1d5a 100644 (file)
                        reg = <0x48038000 0x2000>,
                              <0x46000000 0x400000>;
                        reg-names = "mpu", "dat";
-                       interrupts = <80>, <81>;
+                       interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "tx", "rx";
                        status = "disabled";
                        dmas = <&edma 8>,
                        reg = <0x4803C000 0x2000>,
                              <0x46400000 0x400000>;
                        reg-names = "mpu", "dat";
-                       interrupts = <82>, <83>;
+                       interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>,
+                                    <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "tx", "rx";
                        status = "disabled";
                        dmas = <&edma 10>,
index 5a206c1..8a5628c 100644 (file)
                        usbhsohci: ohci@4a064800 {
                                compatible = "ti,ohci-omap3";
                                reg = <0x4a064800 0x400>;
-                               interrupt-parent = <&gic>;
                                interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
                        };
 
                        usbhsehci: ehci@4a064c00 {
                                compatible = "ti,ehci-omap";
                                reg = <0x4a064c00 0x400>;
-                               interrupt-parent = <&gic>;
                                interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
                        };
                };
index e7af060..8c750da 100644 (file)
@@ -42,6 +42,7 @@
 
        qcom,ntn_avb {
                qcom,ntn-rc-num = <2>;
+               pinctrl-0 = <&ntn_clk_sync &ntn2_clk_sync>;
        };
 
        i2c@75b6000 { /* BLSP8 */
                };
        };
 
+       clock_audio: audio_ext_clk {
+               /delete-property/pinctrl-0;
+               /delete-property/pinctrl-1;
+       };
 };
 
 &cci {
                        output-high;
                };
        };
+
+       ntn2_clk_sync: ntn2_clk_sync {
+               mux {
+                       pins = "gpio98";
+                       function = "gpio";
+               };
+
+               config {
+                       pins = "gpio98";
+                       drive-strength = <8>; /* 8 mA */
+                       output-low;
+                       bias-pull-down;         /* PULL down */
+               };
+       };
 };
 
 &pil_modem {
index 7814133..22c694b 100644 (file)
                pinctrl-names = "active", "sleep";
                pinctrl-0 = <&can_rst_on>;
                pinctrl-1 = <&can_rst_off>;
-               status = "disabled";
        };
 };
 
diff --git a/arch/arm/boot/dts/qcom/vplatform-lfv-msm-pm8994.dtsi b/arch/arm/boot/dts/qcom/vplatform-lfv-msm-pm8994.dtsi
new file mode 100644 (file)
index 0000000..6a6fb68
--- /dev/null
@@ -0,0 +1,276 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/spmi/spmi.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+&spmi_bus {
+       qcom,pm8994@0 {
+               compatible ="qcom,spmi-pmic";
+               reg = <0x0 SPMI_USID>;
+               #address-cells = <2>;
+               #size-cells = <0>;
+
+               pm8994_gpios: gpios {
+                       compatible = "qcom,qpnp-pin";
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       label = "pm8994-gpio";
+
+                       gpio@c000 {
+                               reg = <0xc000 0x100>;
+                               qcom,pin-num = <1>;
+                               status = "disabled";
+                       };
+
+                       gpio@c100 {
+                               reg = <0xc100 0x100>;
+                               qcom,pin-num = <2>;
+                               status = "disabled";
+                       };
+
+                       gpio@c200 {
+                               reg = <0xc200 0x100>;
+                               qcom,pin-num = <3>;
+                               status = "disabled";
+                       };
+
+                       gpio@c300 {
+                               reg = <0xc300 0x100>;
+                               qcom,pin-num = <4>;
+                               status = "disabled";
+                       };
+
+                       gpio@c400 {
+                               reg = <0xc400 0x100>;
+                               qcom,pin-num = <5>;
+                               status = "disabled";
+                       };
+
+                       gpio@c500 {
+                               reg = <0xc500 0x100>;
+                               qcom,pin-num = <6>;
+                               status = "disabled";
+                       };
+
+                       gpio@c600 {
+                               reg = <0xc600 0x100>;
+                               qcom,pin-num = <7>;
+                               status = "disabled";
+                       };
+
+                       gpio@c700 {
+                               reg = <0xc700 0x100>;
+                               qcom,pin-num = <8>;
+                               status = "disabled";
+                       };
+
+                       gpio@c800 {
+                               reg = <0xc800 0x100>;
+                               qcom,pin-num = <9>;
+                               status = "disabled";
+                       };
+
+                       gpio@c900 {
+                               reg = <0xc900 0x100>;
+                               qcom,pin-num = <10>;
+                               status = "disabled";
+                       };
+
+                       gpio@ca00 {
+                               reg = <0xca00 0x100>;
+                               qcom,pin-num = <11>;
+                               status = "disabled";
+                       };
+
+                       gpio@cb00 {
+                               reg = <0xcb00 0x100>;
+                               qcom,pin-num = <12>;
+                               status = "disabled";
+                       };
+
+                       gpio@cc00 {
+                               reg = <0xcc00 0x100>;
+                               qcom,pin-num = <13>;
+                               status = "disabled";
+                       };
+
+                       gpio@cd00 {
+                               reg = <0xcd00 0x100>;
+                               qcom,pin-num = <14>;
+                               status = "disabled";
+                       };
+
+                       gpio@ce00 {
+                               reg = <0xce00 0x100>;
+                               qcom,pin-num = <15>;
+                               status = "disabled";
+                       };
+
+                       gpio@cf00 {
+                               reg = <0xcf00 0x100>;
+                               qcom,pin-num = <16>;
+                               status = "disabled";
+                       };
+
+                       gpio@d000 {
+                               reg = <0xd000 0x100>;
+                               qcom,pin-num = <17>;
+                               status = "disabled";
+                       };
+
+                       gpio@d100 {
+                               reg = <0xd100 0x100>;
+                               qcom,pin-num = <18>;
+                               status = "disabled";
+                       };
+
+                       gpio@d200 {
+                               reg = <0xd200 0x100>;
+                               qcom,pin-num = <19>;
+                               status = "disabled";
+                       };
+
+                       gpio@d300 {
+                               reg = <0xd300 0x100>;
+                               qcom,pin-num = <20>;
+                               status = "disabled";
+                       };
+
+                       gpio@d500 {
+                               reg = <0xd500 0x100>;
+                               qcom,pin-num = <22>;
+                               status = "disabled";
+                       };
+               };
+
+               pm8994_mpps: mpps {
+                       compatible = "qcom,qpnp-pin";
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       label = "pm8994-mpp";
+
+                       mpp@a000 {
+                               reg = <0xa000 0x100>;
+                               qcom,pin-num = <1>;
+                               status = "disabled";
+                       };
+
+                       mpp@a100 {
+                               reg = <0xa100 0x100>;
+                               qcom,pin-num = <2>;
+                               status = "disabled";
+                       };
+
+                       mpp@a200 {
+                               reg = <0xa200 0x100>;
+                               qcom,pin-num = <3>;
+                               status = "disabled";
+                       };
+
+                       mpp@a300 {
+                               reg = <0xa300 0x100>;
+                               qcom,pin-num = <4>;
+                               status = "disabled";
+                       };
+
+                       mpp@a400 {
+                               reg = <0xa400 0x100>;
+                               qcom,pin-num = <5>;
+                               status = "disabled";
+                       };
+
+                       mpp@a500 {
+                               reg = <0xa500 0x100>;
+                               qcom,pin-num = <6>;
+                               status = "disabled";
+                       };
+
+                       mpp@a600 {
+                               reg = <0xa600 0x100>;
+                               qcom,pin-num = <7>;
+                               status = "disabled";
+                       };
+
+                       mpp@a700 {
+                               reg = <0xa700 0x100>;
+                               qcom,pin-num = <8>;
+                               status = "disabled";
+                       };
+               };
+
+               pm8994_vadc: vadc@3100 {
+                       compatible = "qcom,qpnp-vadc";
+                       reg = <0x3100 0x100>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       interrupts = <0x0 0x31 0x0 IRQ_TYPE_NONE>;
+                       interrupt-names = "eoc-int-en-set";
+                       qcom,adc-bit-resolution = <15>;
+                       qcom,adc-vdd-reference = <1800>;
+                       qcom,vadc-poll-eoc;
+
+                       chan@8 {
+                               label = "die_temp";
+                               reg = <8>;
+                               qcom,decimation = <0>;
+                               qcom,pre-div-channel-scaling = <0>;
+                               qcom,calibration-type = "absolute";
+                               qcom,scale-function = <3>;
+                               qcom,hw-settle-time = <0>;
+                               qcom,fast-avg-setup = <0>;
+                       };
+
+                       chan@9 {
+                               label = "ref_625mv";
+                               reg = <9>;
+                               qcom,decimation = <0>;
+                               qcom,pre-div-channel-scaling = <0>;
+                               qcom,calibration-type = "absolute";
+                               qcom,scale-function = <0>;
+                               qcom,hw-settle-time = <0>;
+                               qcom,fast-avg-setup = <0>;
+                       };
+
+                       chan@a {
+                               label = "ref_1250v";
+                               reg = <0xa>;
+                               qcom,decimation = <0>;
+                               qcom,pre-div-channel-scaling = <0>;
+                               qcom,calibration-type = "absolute";
+                               qcom,scale-function = <0>;
+                               qcom,hw-settle-time = <0>;
+                               qcom,fast-avg-setup = <0>;
+                       };
+               };
+
+               pm8994_adc_tm: vadc@3400 {
+                       compatible = "qcom,qpnp-adc-tm";
+                       reg = <0x3400 0x100>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       interrupts =    <0x0 0x34 0x0 IRQ_TYPE_NONE>,
+                                       <0x0 0x34 0x3 IRQ_TYPE_NONE>,
+                                    <0x0 0x34 0x4 IRQ_TYPE_NONE>;
+                       interrupt-names =       "eoc-int-en-set",
+                                               "high-thr-en-set",
+                                               "low-thr-en-set";
+                       qcom,adc-bit-resolution = <15>;
+                       qcom,adc-vdd-reference = <1800>;
+                       qcom,adc_tm-vadc = <&pm8994_vadc>;
+               };
+       };
+};
index 7ef7260..a14a482 100644 (file)
                        qcom,pet-time = <10000>;
                        qcom,ipi-ping;
                };
+
+               spmi_bus: qcom,virtspmi@4400000 {
+                       compatible = "qcom,virtspmi-pmic-arb";
+                       reg = <0x4400000 0x800000>;
+                       reg-names = "core";
+                       #address-cells = <2>;
+                       #size-cells = <0>;
+               };
        };
 };
index fd04dcf..30a45a5 100644 (file)
        status = "okay";
        qcom,no-wakeup-src-in-hostmode;
 };
+
+&qusb_phy0 {
+       status = "okay";
+};
+
+&ssphy {
+       status = "okay";
+};
index 9080549..e2b4ae1 100644 (file)
 &usb2s {
        status = "okay";
 };
+
+&qusb_phy0 {
+       status = "okay";
+};
+
+&qusb_phy1 {
+       status = "okay";
+};
+
+&ssphy {
+       status = "okay";
+};
index d52275e..94cfabf 100644 (file)
                qcom,notify-edges = <&glink_mpss>;
                qcom,xprt = "smem";
        };
+
+       subsys_notif_virt: qcom,subsys_notif_virt@2D000000 {
+               compatible = "qcom,subsys-notif-virt";
+               reg = <0x2D000000 0x10>;
+               reg-names = "vdev_base";
+               adsp {
+                       subsys-name = "adsp";
+                       offset = <0>;
+               };
+               mpss {
+                       subsys-name = "modem";
+                       offset = <8>;
+               };
+       };
 };
 
 &spi_9 {
        status = "okay";
        qcom,no-wakeup-src-in-hostmode;
 };
+
+&qusb_phy0 {
+       status = "okay";
+};
+
+&ssphy {
+       status = "okay";
+};
index 764a79e..b7ede0a 100644 (file)
 
                resets = <&clock_virt QUSB2PHY_PRIM_BCR>;
                reset-names = "phy_reset";
+               status = "disabled";
        };
 
        qusb_phy1: qusb@7412000 {
 
                resets = <&clock_virt QUSB2PHY_SEC_BCR>;
                reset-names = "phy_reset";
+               status = "disabled";
        };
 
        ssphy: ssphy@7410000 {
                         <&clock_virt USB3PHY_PHY_BCR>;
                reset-names = "phy_reset", "phy_phy_reset";
                qcom,disable-autonomous-mode;
+               status = "disabled";
        };
 
        usb_nop_phy: usb_nop_phy {
index 65fba9c..f993b21 100644 (file)
@@ -38,6 +38,7 @@
 #include "vplatform-lfv-ion.dtsi"
 #include "vplatform-lfv-msm8996-pinctrl.dtsi"
 #include "vplatform-lfv-msm8996-blsp.dtsi"
+#include "vplatform-lfv-msm-pm8994.dtsi"
 
 &soc {
        sdhc_2: sdhci@74a4900 {
index 8344a0e..b03fe74 100644 (file)
                        compatible = "samsung,exynos4210-ohci";
                        reg = <0xec300000 0x100>;
                        interrupts = <23>;
+                       interrupt-parent = <&vic1>;
                        clocks = <&clocks CLK_USB_HOST>;
                        clock-names = "usbhost";
                        #address-cells = <1>;
index e488572..3d83992 100644 (file)
                        spi0: spi@e0100000 {
                                status = "okay";
                                num-cs = <3>;
-                               cs-gpios = <&gpio1 7 0>, <&spics 0>, <&spics 1>;
+                               cs-gpios = <&gpio1 7 0>, <&spics 0 0>, <&spics 1 0>;
 
                                stmpe610@0 {
                                        compatible = "st,stmpe610";
index df2232d..6361cbf 100644 (file)
                                reg = <0xb4100000 0x1000>;
                                interrupts = <0 105 0x4>;
                                status = "disabled";
-                               dmas = <&dwdma0 0x600 0 0 1>, /* 0xC << 11 */
-                                       <&dwdma0 0x680 0 1 0>; /* 0xD << 7 */
+                               dmas = <&dwdma0 12 0 1>,
+                                       <&dwdma0 13 1 0>;
                                dma-names = "tx", "rx";
                        };
 
index 14594ce..8fd8a33 100644 (file)
                        reg = <0xb2800000 0x1000>;
                        interrupts = <0 29 0x4>;
                        status = "disabled";
-                       dmas = <&dwdma0 0 0 0 0>;
+                       dmas = <&dwdma0 0 0 0>;
                        dma-names = "data";
                };
 
                                #size-cells = <0>;
                                interrupts = <0 31 0x4>;
                                status = "disabled";
-                               dmas = <&dwdma0 0x2000 0 0 0>, /* 0x4 << 11 */
-                                       <&dwdma0 0x0280 0 0 0>;  /* 0x5 << 7 */
+                               dmas = <&dwdma0 4 0 0>,
+                                       <&dwdma0 5 0 0>;
                                dma-names = "tx", "rx";
                        };
 
index 9f60a7b..bd37903 100644 (file)
                        rtc@fc900000 {
                                compatible = "st,spear600-rtc";
                                reg = <0xfc900000 0x1000>;
+                               interrupt-parent = <&vic0>;
                                interrupts = <10>;
                                status = "disabled";
                        };
index d60f0d8..e4b508c 100644 (file)
@@ -8,6 +8,7 @@
  */
 #include "stih407-clock.dtsi"
 #include "stih407-family.dtsi"
+#include <dt-bindings/gpio/gpio.h>
 / {
        soc {
                sti-display-subsystem {
                                         <&clk_s_d2_quadfs 0>,
                                         <&clk_s_d2_quadfs 1>;
 
-                               hdmi,hpd-gpio = <&pio5 3>;
+                               hdmi,hpd-gpio = <&pio5 3 GPIO_ACTIVE_LOW>;
                                reset-names = "hdmi";
                                resets = <&softreset STIH407_HDMI_TX_PHY_SOFTRESET>;
                                ddc = <&hdmiddc>;
index 4031886..3c32fb8 100644 (file)
@@ -9,6 +9,7 @@
 #include "stih410-clock.dtsi"
 #include "stih407-family.dtsi"
 #include "stih410-pinctrl.dtsi"
+#include <dt-bindings/gpio/gpio.h>
 / {
        aliases {
                bdisp0 = &bdisp0;
                                         <&clk_s_d2_quadfs 0>,
                                         <&clk_s_d2_quadfs 1>;
 
-                               hdmi,hpd-gpio = <&pio5 3>;
+                               hdmi,hpd-gpio = <&pio5 3 GPIO_ACTIVE_LOW>;
                                reset-names = "hdmi";
                                resets = <&softreset STIH407_HDMI_TX_PHY_SOFTRESET>;
                                ddc = <&hdmiddc>;
index 27ed1b1..72aa5ec 100644 (file)
@@ -120,4 +120,11 @@ config CRYPTO_GHASH_ARM_CE
          that uses the 64x64 to 128 bit polynomial multiplication (vmull.p64)
          that is part of the ARMv8 Crypto Extensions
 
+config CRYPTO_SPECK_NEON
+       tristate "NEON accelerated Speck cipher algorithms"
+       depends on KERNEL_MODE_NEON
+       select CRYPTO_BLKCIPHER
+       select CRYPTO_GF128MUL
+       select CRYPTO_SPECK
+
 endif
index fc51507..1d0448a 100644 (file)
@@ -8,6 +8,7 @@ obj-$(CONFIG_CRYPTO_SHA1_ARM) += sha1-arm.o
 obj-$(CONFIG_CRYPTO_SHA1_ARM_NEON) += sha1-arm-neon.o
 obj-$(CONFIG_CRYPTO_SHA256_ARM) += sha256-arm.o
 obj-$(CONFIG_CRYPTO_SHA512_ARM) += sha512-arm.o
+obj-$(CONFIG_CRYPTO_SPECK_NEON) += speck-neon.o
 
 ce-obj-$(CONFIG_CRYPTO_AES_ARM_CE) += aes-arm-ce.o
 ce-obj-$(CONFIG_CRYPTO_SHA1_ARM_CE) += sha1-arm-ce.o
@@ -36,6 +37,7 @@ sha1-arm-ce-y := sha1-ce-core.o sha1-ce-glue.o
 sha2-arm-ce-y  := sha2-ce-core.o sha2-ce-glue.o
 aes-arm-ce-y   := aes-ce-core.o aes-ce-glue.o
 ghash-arm-ce-y := ghash-ce-core.o ghash-ce-glue.o
+speck-neon-y := speck-neon-core.o speck-neon-glue.o
 
 quiet_cmd_perl = PERL    $@
       cmd_perl = $(PERL) $(<) > $(@)
diff --git a/arch/arm/crypto/speck-neon-core.S b/arch/arm/crypto/speck-neon-core.S
new file mode 100644 (file)
index 0000000..3c1e203
--- /dev/null
@@ -0,0 +1,432 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * NEON-accelerated implementation of Speck128-XTS and Speck64-XTS
+ *
+ * Copyright (c) 2018 Google, Inc
+ *
+ * Author: Eric Biggers <ebiggers@google.com>
+ */
+
+#include <linux/linkage.h>
+
+       .text
+       .fpu            neon
+
+       // arguments
+       ROUND_KEYS      .req    r0      // const {u64,u32} *round_keys
+       NROUNDS         .req    r1      // int nrounds
+       DST             .req    r2      // void *dst
+       SRC             .req    r3      // const void *src
+       NBYTES          .req    r4      // unsigned int nbytes
+       TWEAK           .req    r5      // void *tweak
+
+       // registers which hold the data being encrypted/decrypted
+       X0              .req    q0
+       X0_L            .req    d0
+       X0_H            .req    d1
+       Y0              .req    q1
+       Y0_H            .req    d3
+       X1              .req    q2
+       X1_L            .req    d4
+       X1_H            .req    d5
+       Y1              .req    q3
+       Y1_H            .req    d7
+       X2              .req    q4
+       X2_L            .req    d8
+       X2_H            .req    d9
+       Y2              .req    q5
+       Y2_H            .req    d11
+       X3              .req    q6
+       X3_L            .req    d12
+       X3_H            .req    d13
+       Y3              .req    q7
+       Y3_H            .req    d15
+
+       // the round key, duplicated in all lanes
+       ROUND_KEY       .req    q8
+       ROUND_KEY_L     .req    d16
+       ROUND_KEY_H     .req    d17
+
+       // index vector for vtbl-based 8-bit rotates
+       ROTATE_TABLE    .req    d18
+
+       // multiplication table for updating XTS tweaks
+       GF128MUL_TABLE  .req    d19
+       GF64MUL_TABLE   .req    d19
+
+       // current XTS tweak value(s)
+       TWEAKV          .req    q10
+       TWEAKV_L        .req    d20
+       TWEAKV_H        .req    d21
+
+       TMP0            .req    q12
+       TMP0_L          .req    d24
+       TMP0_H          .req    d25
+       TMP1            .req    q13
+       TMP2            .req    q14
+       TMP3            .req    q15
+
+       .align          4
+.Lror64_8_table:
+       .byte           1, 2, 3, 4, 5, 6, 7, 0
+.Lror32_8_table:
+       .byte           1, 2, 3, 0, 5, 6, 7, 4
+.Lrol64_8_table:
+       .byte           7, 0, 1, 2, 3, 4, 5, 6
+.Lrol32_8_table:
+       .byte           3, 0, 1, 2, 7, 4, 5, 6
+.Lgf128mul_table:
+       .byte           0, 0x87
+       .fill           14
+.Lgf64mul_table:
+       .byte           0, 0x1b, (0x1b << 1), (0x1b << 1) ^ 0x1b
+       .fill           12
+
+/*
+ * _speck_round_128bytes() - Speck encryption round on 128 bytes at a time
+ *
+ * Do one Speck encryption round on the 128 bytes (8 blocks for Speck128, 16 for
+ * Speck64) stored in X0-X3 and Y0-Y3, using the round key stored in all lanes
+ * of ROUND_KEY.  'n' is the lane size: 64 for Speck128, or 32 for Speck64.
+ *
+ * The 8-bit rotates are implemented using vtbl instead of vshr + vsli because
+ * the vtbl approach is faster on some processors and the same speed on others.
+ */
+.macro _speck_round_128bytes   n
+
+       // x = ror(x, 8)
+       vtbl.8          X0_L, {X0_L}, ROTATE_TABLE
+       vtbl.8          X0_H, {X0_H}, ROTATE_TABLE
+       vtbl.8          X1_L, {X1_L}, ROTATE_TABLE
+       vtbl.8          X1_H, {X1_H}, ROTATE_TABLE
+       vtbl.8          X2_L, {X2_L}, ROTATE_TABLE
+       vtbl.8          X2_H, {X2_H}, ROTATE_TABLE
+       vtbl.8          X3_L, {X3_L}, ROTATE_TABLE
+       vtbl.8          X3_H, {X3_H}, ROTATE_TABLE
+
+       // x += y
+       vadd.u\n        X0, Y0
+       vadd.u\n        X1, Y1
+       vadd.u\n        X2, Y2
+       vadd.u\n        X3, Y3
+
+       // x ^= k
+       veor            X0, ROUND_KEY
+       veor            X1, ROUND_KEY
+       veor            X2, ROUND_KEY
+       veor            X3, ROUND_KEY
+
+       // y = rol(y, 3)
+       vshl.u\n        TMP0, Y0, #3
+       vshl.u\n        TMP1, Y1, #3
+       vshl.u\n        TMP2, Y2, #3
+       vshl.u\n        TMP3, Y3, #3
+       vsri.u\n        TMP0, Y0, #(\n - 3)
+       vsri.u\n        TMP1, Y1, #(\n - 3)
+       vsri.u\n        TMP2, Y2, #(\n - 3)
+       vsri.u\n        TMP3, Y3, #(\n - 3)
+
+       // y ^= x
+       veor            Y0, TMP0, X0
+       veor            Y1, TMP1, X1
+       veor            Y2, TMP2, X2
+       veor            Y3, TMP3, X3
+.endm
+
+/*
+ * _speck_unround_128bytes() - Speck decryption round on 128 bytes at a time
+ *
+ * This is the inverse of _speck_round_128bytes().
+ */
+.macro _speck_unround_128bytes n
+
+       // y ^= x
+       veor            TMP0, Y0, X0
+       veor            TMP1, Y1, X1
+       veor            TMP2, Y2, X2
+       veor            TMP3, Y3, X3
+
+       // y = ror(y, 3)
+       vshr.u\n        Y0, TMP0, #3
+       vshr.u\n        Y1, TMP1, #3
+       vshr.u\n        Y2, TMP2, #3
+       vshr.u\n        Y3, TMP3, #3
+       vsli.u\n        Y0, TMP0, #(\n - 3)
+       vsli.u\n        Y1, TMP1, #(\n - 3)
+       vsli.u\n        Y2, TMP2, #(\n - 3)
+       vsli.u\n        Y3, TMP3, #(\n - 3)
+
+       // x ^= k
+       veor            X0, ROUND_KEY
+       veor            X1, ROUND_KEY
+       veor            X2, ROUND_KEY
+       veor            X3, ROUND_KEY
+
+       // x -= y
+       vsub.u\n        X0, Y0
+       vsub.u\n        X1, Y1
+       vsub.u\n        X2, Y2
+       vsub.u\n        X3, Y3
+
+       // x = rol(x, 8);
+       vtbl.8          X0_L, {X0_L}, ROTATE_TABLE
+       vtbl.8          X0_H, {X0_H}, ROTATE_TABLE
+       vtbl.8          X1_L, {X1_L}, ROTATE_TABLE
+       vtbl.8          X1_H, {X1_H}, ROTATE_TABLE
+       vtbl.8          X2_L, {X2_L}, ROTATE_TABLE
+       vtbl.8          X2_H, {X2_H}, ROTATE_TABLE
+       vtbl.8          X3_L, {X3_L}, ROTATE_TABLE
+       vtbl.8          X3_H, {X3_H}, ROTATE_TABLE
+.endm
+
+.macro _xts128_precrypt_one    dst_reg, tweak_buf, tmp
+
+       // Load the next source block
+       vld1.8          {\dst_reg}, [SRC]!
+
+       // Save the current tweak in the tweak buffer
+       vst1.8          {TWEAKV}, [\tweak_buf:128]!
+
+       // XOR the next source block with the current tweak
+       veor            \dst_reg, TWEAKV
+
+       /*
+        * Calculate the next tweak by multiplying the current one by x,
+        * modulo p(x) = x^128 + x^7 + x^2 + x + 1.
+        */
+       vshr.u64        \tmp, TWEAKV, #63
+       vshl.u64        TWEAKV, #1
+       veor            TWEAKV_H, \tmp\()_L
+       vtbl.8          \tmp\()_H, {GF128MUL_TABLE}, \tmp\()_H
+       veor            TWEAKV_L, \tmp\()_H
+.endm
+
+.macro _xts64_precrypt_two     dst_reg, tweak_buf, tmp
+
+       // Load the next two source blocks
+       vld1.8          {\dst_reg}, [SRC]!
+
+       // Save the current two tweaks in the tweak buffer
+       vst1.8          {TWEAKV}, [\tweak_buf:128]!
+
+       // XOR the next two source blocks with the current two tweaks
+       veor            \dst_reg, TWEAKV
+
+       /*
+        * Calculate the next two tweaks by multiplying the current ones by x^2,
+        * modulo p(x) = x^64 + x^4 + x^3 + x + 1.
+        */
+       vshr.u64        \tmp, TWEAKV, #62
+       vshl.u64        TWEAKV, #2
+       vtbl.8          \tmp\()_L, {GF64MUL_TABLE}, \tmp\()_L
+       vtbl.8          \tmp\()_H, {GF64MUL_TABLE}, \tmp\()_H
+       veor            TWEAKV, \tmp
+.endm
+
+/*
+ * _speck_xts_crypt() - Speck-XTS encryption/decryption
+ *
+ * Encrypt or decrypt NBYTES bytes of data from the SRC buffer to the DST buffer
+ * using Speck-XTS, specifically the variant with a block size of '2n' and round
+ * count given by NROUNDS.  The expanded round keys are given in ROUND_KEYS, and
+ * the current XTS tweak value is given in TWEAK.  It's assumed that NBYTES is a
+ * nonzero multiple of 128.
+ */
+.macro _speck_xts_crypt        n, decrypting
+       push            {r4-r7}
+       mov             r7, sp
+
+       /*
+        * The first four parameters were passed in registers r0-r3.  Load the
+        * additional parameters, which were passed on the stack.
+        */
+       ldr             NBYTES, [sp, #16]
+       ldr             TWEAK, [sp, #20]
+
+       /*
+        * If decrypting, modify the ROUND_KEYS parameter to point to the last
+        * round key rather than the first, since for decryption the round keys
+        * are used in reverse order.
+        */
+.if \decrypting
+.if \n == 64
+       add             ROUND_KEYS, ROUND_KEYS, NROUNDS, lsl #3
+       sub             ROUND_KEYS, #8
+.else
+       add             ROUND_KEYS, ROUND_KEYS, NROUNDS, lsl #2
+       sub             ROUND_KEYS, #4
+.endif
+.endif
+
+       // Load the index vector for vtbl-based 8-bit rotates
+.if \decrypting
+       ldr             r12, =.Lrol\n\()_8_table
+.else
+       ldr             r12, =.Lror\n\()_8_table
+.endif
+       vld1.8          {ROTATE_TABLE}, [r12:64]
+
+       // One-time XTS preparation
+
+       /*
+        * Allocate stack space to store 128 bytes worth of tweaks.  For
+        * performance, this space is aligned to a 16-byte boundary so that we
+        * can use the load/store instructions that declare 16-byte alignment.
+        */
+       sub             sp, #128
+       bic             sp, #0xf
+
+.if \n == 64
+       // Load first tweak
+       vld1.8          {TWEAKV}, [TWEAK]
+
+       // Load GF(2^128) multiplication table
+       ldr             r12, =.Lgf128mul_table
+       vld1.8          {GF128MUL_TABLE}, [r12:64]
+.else
+       // Load first tweak
+       vld1.8          {TWEAKV_L}, [TWEAK]
+
+       // Load GF(2^64) multiplication table
+       ldr             r12, =.Lgf64mul_table
+       vld1.8          {GF64MUL_TABLE}, [r12:64]
+
+       // Calculate second tweak, packing it together with the first
+       vshr.u64        TMP0_L, TWEAKV_L, #63
+       vtbl.u8         TMP0_L, {GF64MUL_TABLE}, TMP0_L
+       vshl.u64        TWEAKV_H, TWEAKV_L, #1
+       veor            TWEAKV_H, TMP0_L
+.endif
+
+.Lnext_128bytes_\@:
+
+       /*
+        * Load the source blocks into {X,Y}[0-3], XOR them with their XTS tweak
+        * values, and save the tweaks on the stack for later.  Then
+        * de-interleave the 'x' and 'y' elements of each block, i.e. make it so
+        * that the X[0-3] registers contain only the second halves of blocks,
+        * and the Y[0-3] registers contain only the first halves of blocks.
+        * (Speck uses the order (y, x) rather than the more intuitive (x, y).)
+        */
+       mov             r12, sp
+.if \n == 64
+       _xts128_precrypt_one    X0, r12, TMP0
+       _xts128_precrypt_one    Y0, r12, TMP0
+       _xts128_precrypt_one    X1, r12, TMP0
+       _xts128_precrypt_one    Y1, r12, TMP0
+       _xts128_precrypt_one    X2, r12, TMP0
+       _xts128_precrypt_one    Y2, r12, TMP0
+       _xts128_precrypt_one    X3, r12, TMP0
+       _xts128_precrypt_one    Y3, r12, TMP0
+       vswp            X0_L, Y0_H
+       vswp            X1_L, Y1_H
+       vswp            X2_L, Y2_H
+       vswp            X3_L, Y3_H
+.else
+       _xts64_precrypt_two     X0, r12, TMP0
+       _xts64_precrypt_two     Y0, r12, TMP0
+       _xts64_precrypt_two     X1, r12, TMP0
+       _xts64_precrypt_two     Y1, r12, TMP0
+       _xts64_precrypt_two     X2, r12, TMP0
+       _xts64_precrypt_two     Y2, r12, TMP0
+       _xts64_precrypt_two     X3, r12, TMP0
+       _xts64_precrypt_two     Y3, r12, TMP0
+       vuzp.32         Y0, X0
+       vuzp.32         Y1, X1
+       vuzp.32         Y2, X2
+       vuzp.32         Y3, X3
+.endif
+
+       // Do the cipher rounds
+
+       mov             r12, ROUND_KEYS
+       mov             r6, NROUNDS
+
+.Lnext_round_\@:
+.if \decrypting
+.if \n == 64
+       vld1.64         ROUND_KEY_L, [r12]
+       sub             r12, #8
+       vmov            ROUND_KEY_H, ROUND_KEY_L
+.else
+       vld1.32         {ROUND_KEY_L[],ROUND_KEY_H[]}, [r12]
+       sub             r12, #4
+.endif
+       _speck_unround_128bytes \n
+.else
+.if \n == 64
+       vld1.64         ROUND_KEY_L, [r12]!
+       vmov            ROUND_KEY_H, ROUND_KEY_L
+.else
+       vld1.32         {ROUND_KEY_L[],ROUND_KEY_H[]}, [r12]!
+.endif
+       _speck_round_128bytes   \n
+.endif
+       subs            r6, r6, #1
+       bne             .Lnext_round_\@
+
+       // Re-interleave the 'x' and 'y' elements of each block
+.if \n == 64
+       vswp            X0_L, Y0_H
+       vswp            X1_L, Y1_H
+       vswp            X2_L, Y2_H
+       vswp            X3_L, Y3_H
+.else
+       vzip.32         Y0, X0
+       vzip.32         Y1, X1
+       vzip.32         Y2, X2
+       vzip.32         Y3, X3
+.endif
+
+       // XOR the encrypted/decrypted blocks with the tweaks we saved earlier
+       mov             r12, sp
+       vld1.8          {TMP0, TMP1}, [r12:128]!
+       vld1.8          {TMP2, TMP3}, [r12:128]!
+       veor            X0, TMP0
+       veor            Y0, TMP1
+       veor            X1, TMP2
+       veor            Y1, TMP3
+       vld1.8          {TMP0, TMP1}, [r12:128]!
+       vld1.8          {TMP2, TMP3}, [r12:128]!
+       veor            X2, TMP0
+       veor            Y2, TMP1
+       veor            X3, TMP2
+       veor            Y3, TMP3
+
+       // Store the ciphertext in the destination buffer
+       vst1.8          {X0, Y0}, [DST]!
+       vst1.8          {X1, Y1}, [DST]!
+       vst1.8          {X2, Y2}, [DST]!
+       vst1.8          {X3, Y3}, [DST]!
+
+       // Continue if there are more 128-byte chunks remaining, else return
+       subs            NBYTES, #128
+       bne             .Lnext_128bytes_\@
+
+       // Store the next tweak
+.if \n == 64
+       vst1.8          {TWEAKV}, [TWEAK]
+.else
+       vst1.8          {TWEAKV_L}, [TWEAK]
+.endif
+
+       mov             sp, r7
+       pop             {r4-r7}
+       bx              lr
+.endm
+
+ENTRY(speck128_xts_encrypt_neon)
+       _speck_xts_crypt        n=64, decrypting=0
+ENDPROC(speck128_xts_encrypt_neon)
+
+ENTRY(speck128_xts_decrypt_neon)
+       _speck_xts_crypt        n=64, decrypting=1
+ENDPROC(speck128_xts_decrypt_neon)
+
+ENTRY(speck64_xts_encrypt_neon)
+       _speck_xts_crypt        n=32, decrypting=0
+ENDPROC(speck64_xts_encrypt_neon)
+
+ENTRY(speck64_xts_decrypt_neon)
+       _speck_xts_crypt        n=32, decrypting=1
+ENDPROC(speck64_xts_decrypt_neon)
diff --git a/arch/arm/crypto/speck-neon-glue.c b/arch/arm/crypto/speck-neon-glue.c
new file mode 100644 (file)
index 0000000..ea36c3a
--- /dev/null
@@ -0,0 +1,314 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * NEON-accelerated implementation of Speck128-XTS and Speck64-XTS
+ *
+ * Copyright (c) 2018 Google, Inc
+ *
+ * Note: the NIST recommendation for XTS only specifies a 128-bit block size,
+ * but a 64-bit version (needed for Speck64) is fairly straightforward; the math
+ * is just done in GF(2^64) instead of GF(2^128), with the reducing polynomial
+ * x^64 + x^4 + x^3 + x + 1 from the original XEX paper (Rogaway, 2004:
+ * "Efficient Instantiations of Tweakable Blockciphers and Refinements to Modes
+ * OCB and PMAC"), represented as 0x1B.
+ */
+
+#include <asm/hwcap.h>
+#include <asm/neon.h>
+#include <asm/simd.h>
+#include <crypto/algapi.h>
+#include <crypto/gf128mul.h>
+#include <crypto/speck.h>
+#include <crypto/xts.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+/* The assembly functions only handle multiples of 128 bytes */
+#define SPECK_NEON_CHUNK_SIZE  128
+
+/* Speck128 */
+
+struct speck128_xts_tfm_ctx {
+       struct speck128_tfm_ctx main_key;
+       struct speck128_tfm_ctx tweak_key;
+};
+
+asmlinkage void speck128_xts_encrypt_neon(const u64 *round_keys, int nrounds,
+                                         void *dst, const void *src,
+                                         unsigned int nbytes, void *tweak);
+
+asmlinkage void speck128_xts_decrypt_neon(const u64 *round_keys, int nrounds,
+                                         void *dst, const void *src,
+                                         unsigned int nbytes, void *tweak);
+
+typedef void (*speck128_crypt_one_t)(const struct speck128_tfm_ctx *,
+                                    u8 *, const u8 *);
+typedef void (*speck128_xts_crypt_many_t)(const u64 *, int, void *,
+                                         const void *, unsigned int, void *);
+
+static __always_inline int
+__speck128_xts_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                    struct scatterlist *src, unsigned int nbytes,
+                    speck128_crypt_one_t crypt_one,
+                    speck128_xts_crypt_many_t crypt_many)
+{
+       struct crypto_blkcipher *tfm = desc->tfm;
+       const struct speck128_xts_tfm_ctx *ctx = crypto_blkcipher_ctx(tfm);
+       struct blkcipher_walk walk;
+       le128 tweak;
+       int err;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       err = blkcipher_walk_virt_block(desc, &walk, SPECK_NEON_CHUNK_SIZE);
+
+       crypto_speck128_encrypt(&ctx->tweak_key, (u8 *)&tweak, walk.iv);
+
+       while (walk.nbytes > 0) {
+               unsigned int nbytes = walk.nbytes;
+               u8 *dst = walk.dst.virt.addr;
+               const u8 *src = walk.src.virt.addr;
+
+               if (nbytes >= SPECK_NEON_CHUNK_SIZE && may_use_simd()) {
+                       unsigned int count;
+
+                       count = round_down(nbytes, SPECK_NEON_CHUNK_SIZE);
+                       kernel_neon_begin();
+                       (*crypt_many)(ctx->main_key.round_keys,
+                                     ctx->main_key.nrounds,
+                                     dst, src, count, &tweak);
+                       kernel_neon_end();
+                       dst += count;
+                       src += count;
+                       nbytes -= count;
+               }
+
+               /* Handle any remainder with generic code */
+               while (nbytes >= sizeof(tweak)) {
+                       le128_xor((le128 *)dst, (const le128 *)src, &tweak);
+                       (*crypt_one)(&ctx->main_key, dst, dst);
+                       le128_xor((le128 *)dst, (const le128 *)dst, &tweak);
+                       gf128mul_x_ble((be128 *)&tweak, (const be128 *)&tweak);
+
+                       dst += sizeof(tweak);
+                       src += sizeof(tweak);
+                       nbytes -= sizeof(tweak);
+               }
+               err = blkcipher_walk_done(desc, &walk, nbytes);
+       }
+
+       return err;
+}
+
+static int speck128_xts_encrypt(struct blkcipher_desc *desc,
+                               struct scatterlist *dst,
+                               struct scatterlist *src,
+                               unsigned int nbytes)
+{
+       return __speck128_xts_crypt(desc, dst, src, nbytes,
+                                   crypto_speck128_encrypt,
+                                   speck128_xts_encrypt_neon);
+}
+
+static int speck128_xts_decrypt(struct blkcipher_desc *desc,
+                               struct scatterlist *dst,
+                               struct scatterlist *src,
+                               unsigned int nbytes)
+{
+       return __speck128_xts_crypt(desc, dst, src, nbytes,
+                                   crypto_speck128_decrypt,
+                                   speck128_xts_decrypt_neon);
+}
+
+static int speck128_xts_setkey(struct crypto_tfm *tfm, const u8 *key,
+                              unsigned int keylen)
+{
+       struct speck128_xts_tfm_ctx *ctx = crypto_tfm_ctx(tfm);
+       int err;
+
+       if (keylen % 2)
+               return -EINVAL;
+
+       keylen /= 2;
+
+       err = crypto_speck128_setkey(&ctx->main_key, key, keylen);
+       if (err)
+               return err;
+
+       return crypto_speck128_setkey(&ctx->tweak_key, key + keylen, keylen);
+}
+
+/* Speck64 */
+
+struct speck64_xts_tfm_ctx {
+       struct speck64_tfm_ctx main_key;
+       struct speck64_tfm_ctx tweak_key;
+};
+
+asmlinkage void speck64_xts_encrypt_neon(const u32 *round_keys, int nrounds,
+                                        void *dst, const void *src,
+                                        unsigned int nbytes, void *tweak);
+
+asmlinkage void speck64_xts_decrypt_neon(const u32 *round_keys, int nrounds,
+                                        void *dst, const void *src,
+                                        unsigned int nbytes, void *tweak);
+
+typedef void (*speck64_crypt_one_t)(const struct speck64_tfm_ctx *,
+                                   u8 *, const u8 *);
+typedef void (*speck64_xts_crypt_many_t)(const u32 *, int, void *,
+                                        const void *, unsigned int, void *);
+
+static __always_inline int
+__speck64_xts_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                   struct scatterlist *src, unsigned int nbytes,
+                   speck64_crypt_one_t crypt_one,
+                   speck64_xts_crypt_many_t crypt_many)
+{
+       struct crypto_blkcipher *tfm = desc->tfm;
+       const struct speck64_xts_tfm_ctx *ctx = crypto_blkcipher_ctx(tfm);
+       struct blkcipher_walk walk;
+       __le64 tweak;
+       int err;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       err = blkcipher_walk_virt_block(desc, &walk, SPECK_NEON_CHUNK_SIZE);
+
+       crypto_speck64_encrypt(&ctx->tweak_key, (u8 *)&tweak, walk.iv);
+
+       while (walk.nbytes > 0) {
+               unsigned int nbytes = walk.nbytes;
+               u8 *dst = walk.dst.virt.addr;
+               const u8 *src = walk.src.virt.addr;
+
+               if (nbytes >= SPECK_NEON_CHUNK_SIZE && may_use_simd()) {
+                       unsigned int count;
+
+                       count = round_down(nbytes, SPECK_NEON_CHUNK_SIZE);
+                       kernel_neon_begin();
+                       (*crypt_many)(ctx->main_key.round_keys,
+                                     ctx->main_key.nrounds,
+                                     dst, src, count, &tweak);
+                       kernel_neon_end();
+                       dst += count;
+                       src += count;
+                       nbytes -= count;
+               }
+
+               /* Handle any remainder with generic code */
+               while (nbytes >= sizeof(tweak)) {
+                       *(__le64 *)dst = *(__le64 *)src ^ tweak;
+                       (*crypt_one)(&ctx->main_key, dst, dst);
+                       *(__le64 *)dst ^= tweak;
+                       tweak = cpu_to_le64((le64_to_cpu(tweak) << 1) ^
+                                           ((tweak & cpu_to_le64(1ULL << 63)) ?
+                                            0x1B : 0));
+                       dst += sizeof(tweak);
+                       src += sizeof(tweak);
+                       nbytes -= sizeof(tweak);
+               }
+               err = blkcipher_walk_done(desc, &walk, nbytes);
+       }
+
+       return err;
+}
+
+static int speck64_xts_encrypt(struct blkcipher_desc *desc,
+                              struct scatterlist *dst, struct scatterlist *src,
+                              unsigned int nbytes)
+{
+       return __speck64_xts_crypt(desc, dst, src, nbytes,
+                                  crypto_speck64_encrypt,
+                                  speck64_xts_encrypt_neon);
+}
+
+static int speck64_xts_decrypt(struct blkcipher_desc *desc,
+                              struct scatterlist *dst, struct scatterlist *src,
+                              unsigned int nbytes)
+{
+       return __speck64_xts_crypt(desc, dst, src, nbytes,
+                                  crypto_speck64_decrypt,
+                                  speck64_xts_decrypt_neon);
+}
+
+static int speck64_xts_setkey(struct crypto_tfm *tfm, const u8 *key,
+                             unsigned int keylen)
+{
+       struct speck64_xts_tfm_ctx *ctx = crypto_tfm_ctx(tfm);
+       int err;
+
+       if (keylen % 2)
+               return -EINVAL;
+
+       keylen /= 2;
+
+       err = crypto_speck64_setkey(&ctx->main_key, key, keylen);
+       if (err)
+               return err;
+
+       return crypto_speck64_setkey(&ctx->tweak_key, key + keylen, keylen);
+}
+
+static struct crypto_alg speck_algs[] = {
+       {
+               .cra_name               = "xts(speck128)",
+               .cra_driver_name        = "xts-speck128-neon",
+               .cra_priority           = 300,
+               .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+               .cra_blocksize          = SPECK128_BLOCK_SIZE,
+               .cra_type               = &crypto_blkcipher_type,
+               .cra_ctxsize            = sizeof(struct speck128_xts_tfm_ctx),
+               .cra_alignmask          = 7,
+               .cra_module             = THIS_MODULE,
+               .cra_u = {
+                       .blkcipher = {
+                               .min_keysize            = 2 * SPECK128_128_KEY_SIZE,
+                               .max_keysize            = 2 * SPECK128_256_KEY_SIZE,
+                               .ivsize                 = SPECK128_BLOCK_SIZE,
+                               .setkey                 = speck128_xts_setkey,
+                               .encrypt                = speck128_xts_encrypt,
+                               .decrypt                = speck128_xts_decrypt,
+                       }
+               }
+       }, {
+               .cra_name               = "xts(speck64)",
+               .cra_driver_name        = "xts-speck64-neon",
+               .cra_priority           = 300,
+               .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+               .cra_blocksize          = SPECK64_BLOCK_SIZE,
+               .cra_type               = &crypto_blkcipher_type,
+               .cra_ctxsize            = sizeof(struct speck64_xts_tfm_ctx),
+               .cra_alignmask          = 7,
+               .cra_module             = THIS_MODULE,
+               .cra_u = {
+                       .blkcipher = {
+                               .min_keysize            = 2 * SPECK64_96_KEY_SIZE,
+                               .max_keysize            = 2 * SPECK64_128_KEY_SIZE,
+                               .ivsize                 = SPECK64_BLOCK_SIZE,
+                               .setkey                 = speck64_xts_setkey,
+                               .encrypt                = speck64_xts_encrypt,
+                               .decrypt                = speck64_xts_decrypt,
+                       }
+               }
+       }
+};
+
+static int __init speck_neon_module_init(void)
+{
+       if (!(elf_hwcap & HWCAP_NEON))
+               return -ENODEV;
+       return crypto_register_algs(speck_algs, ARRAY_SIZE(speck_algs));
+}
+
+static void __exit speck_neon_module_exit(void)
+{
+       crypto_unregister_algs(speck_algs, ARRAY_SIZE(speck_algs));
+}
+
+module_init(speck_neon_module_init);
+module_exit(speck_neon_module_exit);
+
+MODULE_DESCRIPTION("Speck block cipher (NEON-accelerated)");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Eric Biggers <ebiggers@google.com>");
+MODULE_ALIAS_CRYPTO("xts(speck128)");
+MODULE_ALIAS_CRYPTO("xts-speck128-neon");
+MODULE_ALIAS_CRYPTO("xts(speck64)");
+MODULE_ALIAS_CRYPTO("xts-speck64-neon");
index 0017b3e..e06307a 100644 (file)
@@ -268,9 +268,9 @@ EXPORT_SYMBOL_GPL(thread_notify_head);
 /*
  * Free current thread data structures etc..
  */
-void exit_thread(void)
+void exit_thread(struct task_struct *tsk)
 {
-       thread_notify(THREAD_NOTIFY_EXIT, current_thread_info());
+       thread_notify(THREAD_NOTIFY_EXIT, task_thread_info(tsk));
 }
 
 void flush_thread(void)
index f36b5b1..05b2f82 100644 (file)
@@ -45,7 +45,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 
        ret = kvm_psci_call(vcpu);
        if (ret < 0) {
-               kvm_inject_undefined(vcpu);
+               vcpu_set_reg(vcpu, 0, ~0UL);
                return 1;
        }
 
@@ -54,7 +54,16 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 
 static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
-       kvm_inject_undefined(vcpu);
+       /*
+        * "If an SMC instruction executed at Non-secure EL1 is
+        * trapped to EL2 because HCR_EL2.TSC is 1, the exception is a
+        * Trap exception, not a Secure Monitor Call exception [...]"
+        *
+        * We need to advance the PC after the trap, as it would
+        * otherwise return to the same address...
+        */
+       vcpu_set_reg(vcpu, 0, ~0UL);
+       kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
        return 1;
 }
 
index 5ac122e..9ff9205 100644 (file)
@@ -73,6 +73,25 @@ phys_addr_t omap_secure_ram_mempool_base(void)
        return omap_secure_memblock_base;
 }
 
+u32 omap3_save_secure_ram(void __iomem *addr, int size)
+{
+       u32 ret;
+       u32 param[5];
+
+       if (size != OMAP3_SAVE_SECURE_RAM_SZ)
+               return OMAP3_SAVE_SECURE_RAM_SZ;
+
+       param[0] = 4;           /* Number of arguments */
+       param[1] = __pa(addr);  /* Physical address for saving */
+       param[2] = 0;
+       param[3] = 1;
+       param[4] = 1;
+
+       ret = save_secure_ram_context(__pa(param));
+
+       return ret;
+}
+
 /**
  * rx51_secure_dispatcher: Routine to dispatch secure PPA API calls
  * @idx: The PPA API index
index af2851f..ab6ce25 100644 (file)
@@ -31,6 +31,8 @@
 /* Maximum Secure memory storage size */
 #define OMAP_SECURE_RAM_STORAGE        (88 * SZ_1K)
 
+#define OMAP3_SAVE_SECURE_RAM_SZ       0x803F
+
 /* Secure low power HAL API index */
 #define OMAP4_HAL_SAVESECURERAM_INDEX  0x1a
 #define OMAP4_HAL_SAVEHW_INDEX         0x1b
@@ -64,6 +66,8 @@ extern u32 omap_smc2(u32 id, u32 falg, u32 pargs);
 extern u32 omap_smc3(u32 id, u32 process, u32 flag, u32 pargs);
 extern phys_addr_t omap_secure_ram_mempool_base(void);
 extern int omap_secure_ram_reserve_memblock(void);
+extern u32 save_secure_ram_context(u32 args_pa);
+extern u32 omap3_save_secure_ram(void __iomem *save_regs, int size);
 
 extern u32 rx51_secure_dispatcher(u32 idx, u32 process, u32 flag, u32 nargs,
                                  u32 arg1, u32 arg2, u32 arg3, u32 arg4);
index b668719..8e30772 100644 (file)
@@ -81,10 +81,6 @@ extern unsigned int omap3_do_wfi_sz;
 /* ... and its pointer from SRAM after copy */
 extern void (*omap3_do_wfi_sram)(void);
 
-/* save_secure_ram_context function pointer and size, for copy to SRAM */
-extern int save_secure_ram_context(u32 *addr);
-extern unsigned int save_secure_ram_context_sz;
-
 extern void omap3_save_scratchpad_contents(void);
 
 #define PM_RTA_ERRATUM_i608            (1 << 0)
index 2dbd378..181da20 100644 (file)
@@ -48,6 +48,7 @@
 #include "prm3xxx.h"
 #include "pm.h"
 #include "sdrc.h"
+#include "omap-secure.h"
 #include "sram.h"
 #include "control.h"
 #include "vc.h"
@@ -66,7 +67,6 @@ struct power_state {
 
 static LIST_HEAD(pwrst_list);
 
-static int (*_omap_save_secure_sram)(u32 *addr);
 void (*omap3_do_wfi_sram)(void);
 
 static struct powerdomain *mpu_pwrdm, *neon_pwrdm;
@@ -121,8 +121,8 @@ static void omap3_save_secure_ram_context(void)
                 * will hang the system.
                 */
                pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON);
-               ret = _omap_save_secure_sram((u32 *)(unsigned long)
-                               __pa(omap3_secure_ram_storage));
+               ret = omap3_save_secure_ram(omap3_secure_ram_storage,
+                                           OMAP3_SAVE_SECURE_RAM_SZ);
                pwrdm_set_next_pwrst(mpu_pwrdm, mpu_next_state);
                /* Following is for error tracking, it should not happen */
                if (ret) {
@@ -431,15 +431,10 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
  *
  * The minimum set of functions is pushed to SRAM for execution:
  * - omap3_do_wfi for erratum i581 WA,
- * - save_secure_ram_context for security extensions.
  */
 void omap_push_sram_idle(void)
 {
        omap3_do_wfi_sram = omap_sram_push(omap3_do_wfi, omap3_do_wfi_sz);
-
-       if (omap_type() != OMAP2_DEVICE_TYPE_GP)
-               _omap_save_secure_sram = omap_sram_push(save_secure_ram_context,
-                               save_secure_ram_context_sz);
 }
 
 static void __init pm_errata_configure(void)
@@ -551,7 +546,7 @@ int __init omap3_pm_init(void)
        clkdm_add_wkdep(neon_clkdm, mpu_clkdm);
        if (omap_type() != OMAP2_DEVICE_TYPE_GP) {
                omap3_secure_ram_storage =
-                       kmalloc(0x803F, GFP_KERNEL);
+                       kmalloc(OMAP3_SAVE_SECURE_RAM_SZ, GFP_KERNEL);
                if (!omap3_secure_ram_storage)
                        pr_err("Memory allocation failed when allocating for secure sram context\n");
 
index dcb5001..973bcd7 100644 (file)
@@ -176,17 +176,6 @@ static int am33xx_pwrdm_read_pwrst(struct powerdomain *pwrdm)
        return v;
 }
 
-static int am33xx_pwrdm_read_prev_pwrst(struct powerdomain *pwrdm)
-{
-       u32 v;
-
-       v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs);
-       v &= AM33XX_LASTPOWERSTATEENTERED_MASK;
-       v >>= AM33XX_LASTPOWERSTATEENTERED_SHIFT;
-
-       return v;
-}
-
 static int am33xx_pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm)
 {
        am33xx_prm_rmw_reg_bits(AM33XX_LOWPOWERSTATECHANGE_MASK,
@@ -357,7 +346,6 @@ struct pwrdm_ops am33xx_pwrdm_operations = {
        .pwrdm_set_next_pwrst           = am33xx_pwrdm_set_next_pwrst,
        .pwrdm_read_next_pwrst          = am33xx_pwrdm_read_next_pwrst,
        .pwrdm_read_pwrst               = am33xx_pwrdm_read_pwrst,
-       .pwrdm_read_prev_pwrst          = am33xx_pwrdm_read_prev_pwrst,
        .pwrdm_set_logic_retst          = am33xx_pwrdm_set_logic_retst,
        .pwrdm_read_logic_pwrst         = am33xx_pwrdm_read_logic_pwrst,
        .pwrdm_read_logic_retst         = am33xx_pwrdm_read_logic_retst,
index 1b9f052..3e0d802 100644 (file)
@@ -93,20 +93,13 @@ ENTRY(enable_omap3630_toggle_l2_on_restore)
 ENDPROC(enable_omap3630_toggle_l2_on_restore)
 
 /*
- * Function to call rom code to save secure ram context. This gets
- * relocated to SRAM, so it can be all in .data section. Otherwise
- * we need to initialize api_params separately.
+ * Function to call rom code to save secure ram context.
+ *
+ * r0 = physical address of the parameters
  */
-       .data
-       .align  3
 ENTRY(save_secure_ram_context)
        stmfd   sp!, {r4 - r11, lr}     @ save registers on stack
-       adr     r3, api_params          @ r3 points to parameters
-       str     r0, [r3,#0x4]           @ r0 has sdram address
-       ldr     r12, high_mask
-       and     r3, r3, r12
-       ldr     r12, sram_phy_addr_mask
-       orr     r3, r3, r12
+       mov     r3, r0                  @ physical address of parameters
        mov     r0, #25                 @ set service ID for PPA
        mov     r12, r0                 @ copy secure service ID in r12
        mov     r1, #0                  @ set task id for ROM code in r1
@@ -120,18 +113,7 @@ ENTRY(save_secure_ram_context)
        nop
        nop
        ldmfd   sp!, {r4 - r11, pc}
-       .align
-sram_phy_addr_mask:
-       .word   SRAM_BASE_P
-high_mask:
-       .word   0xffff
-api_params:
-       .word   0x4, 0x0, 0x0, 0x1, 0x1
 ENDPROC(save_secure_ram_context)
-ENTRY(save_secure_ram_context_sz)
-       .word   . - save_secure_ram_context
-
-       .text
 
 /*
  * ======================
index e0a5320..b59a7a2 100644 (file)
@@ -132,3 +132,7 @@ static struct platform_driver tosa_bt_driver = {
        },
 };
 module_platform_driver(tosa_bt_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dmitry Baryshkov");
+MODULE_DESCRIPTION("Bluetooth built-in chip control");
index 0fa4c5f..2d43357 100644 (file)
@@ -12,8 +12,6 @@ menuconfig ARCH_TEGRA
        select ARCH_HAS_RESET_CONTROLLER
        select RESET_CONTROLLER
        select SOC_BUS
-       select USB_ULPI if USB_PHY
-       select USB_ULPI_VIEWPORT if USB_PHY
        help
          This enables support for NVIDIA Tegra based systems.
 
index 2a61e4b..73085d3 100644 (file)
@@ -156,10 +156,6 @@ static void vfp_thread_copy(struct thread_info *thread)
  *   - we could be preempted if tree preempt rcu is enabled, so
  *     it is unsafe to use thread->cpu.
  *  THREAD_NOTIFY_EXIT
- *   - the thread (v) will be running on the local CPU, so
- *     v === current_thread_info()
- *   - thread->cpu is the local CPU number at the time it is accessed,
- *     but may change at any time.
  *   - we could be preempted if tree preempt rcu is enabled, so
  *     it is unsafe to use thread->cpu.
  */
index 67e8111..89e6a3d 100644 (file)
@@ -1147,7 +1147,7 @@ source "fs/Kconfig.binfmt"
 config COMPAT
        bool "Kernel support for 32-bit EL0"
        depends on ARM64_4K_PAGES || EXPERT
-       select COMPAT_BINFMT_ELF
+       select COMPAT_BINFMT_ELF if BINFMT_ELF
        select HAVE_UID16
        select OLD_SIGSUSPEND3
        select COMPAT_OLD_SIGACTION
index b6e5fa3..3206dc4 100644 (file)
@@ -146,8 +146,6 @@ config ARCH_TEGRA_132_SOC
        bool "NVIDIA Tegra132 SoC"
        depends on ARCH_TEGRA
        select PINCTRL_TEGRA124
-       select USB_ULPI if USB_PHY
-       select USB_ULPI_VIEWPORT if USB_PHY
        help
          Enable support for NVIDIA Tegra132 SoC, based on the Denver
          ARMv8 CPU.  The Tegra132 SoC is similar to the Tegra124 SoC,
index 4dd5f93..7f42b64 100644 (file)
@@ -54,6 +54,7 @@
                        reg = <0x000>;
                        enable-method = "psci";
                        cpu-idle-states = <&CPU_SLEEP_0>;
+                       #cooling-cells = <2>;
                };
 
                cpu1: cpu@1 {
@@ -70,6 +71,7 @@
                        reg = <0x100>;
                        enable-method = "psci";
                        cpu-idle-states = <&CPU_SLEEP_0>;
+                       #cooling-cells = <2>;
                };
 
                cpu3: cpu@101 {
index 6e6e691..e47e106 100644 (file)
@@ -205,11 +205,15 @@ CONFIG_I2C_MSM_V2=y
 CONFIG_SPI=y
 CONFIG_SPI_QUP=y
 CONFIG_SPI_SPIDEV=y
+CONFIG_SPMI=y
 CONFIG_PINCTRL_MSM8996=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_QPNP_PIN=y
 CONFIG_POWER_RESET_QCOM=y
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
 CONFIG_WATCHDOG=y
+CONFIG_MFD_SPMI_PMIC=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_STUB=y
 CONFIG_MEDIA_SUPPORT=y
index a60d2ad..446152e 100644 (file)
@@ -208,11 +208,15 @@ CONFIG_SPI=y
 CONFIG_SPI_DEBUG=y
 CONFIG_SPI_QUP=y
 CONFIG_SPI_SPIDEV=y
+CONFIG_SPMI=y
 CONFIG_PINCTRL_MSM8996=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_QPNP_PIN=y
 CONFIG_POWER_RESET_QCOM=y
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
 CONFIG_WATCHDOG=y
+CONFIG_MFD_SPMI_PMIC=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_STUB=y
 CONFIG_MEDIA_SUPPORT=y
index 10bd4c4..44d4c07 100644 (file)
@@ -544,7 +544,6 @@ CONFIG_MSM_SERVICE_NOTIFIER=y
 CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
 CONFIG_MSM_RPM_LOG=y
 CONFIG_MSM_RPM_STATS_LOG=y
-CONFIG_QCOM_SMCINVOKE=y
 CONFIG_MSM_CACHE_M4M_ERP64=y
 CONFIG_MSM_CACHE_M4M_ERP64_PANIC_ON_CE=y
 CONFIG_MSM_CACHE_M4M_ERP64_PANIC_ON_UE=y
index 6cc8fd6..b691690 100644 (file)
@@ -553,7 +553,6 @@ CONFIG_MSM_SERVICE_NOTIFIER=y
 CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
 CONFIG_MSM_RPM_LOG=y
 CONFIG_MSM_RPM_STATS_LOG=y
-CONFIG_QCOM_SMCINVOKE=y
 CONFIG_MSM_CACHE_M4M_ERP64=y
 CONFIG_MSM_CACHE_M4M_ERP64_PANIC_ON_CE=y
 CONFIG_MSM_CACHE_M4M_ERP64_PANIC_ON_UE=y
index 561190d..0bfe1df 100644 (file)
@@ -20,9 +20,6 @@
 
 #include <asm/brk-imm.h>
 
-#ifdef CONFIG_GENERIC_BUG
-#define HAVE_ARCH_BUG
-
 #ifdef CONFIG_DEBUG_BUGVERBOSE
 #define _BUGVERBOSE_LOCATION(file, line) __BUGVERBOSE_LOCATION(file, line)
 #define __BUGVERBOSE_LOCATION(file, line)                              \
 #define _BUGVERBOSE_LOCATION(file, line)
 #endif
 
-#define _BUG_FLAGS(flags) __BUG_FLAGS(flags)
+#ifdef CONFIG_GENERIC_BUG
 
-#define __BUG_FLAGS(flags) asm volatile (              \
+#define __BUG_ENTRY(flags)                             \
                ".pushsection __bug_table,\"a\"\n\t"    \
                ".align 2\n\t"                          \
        "0:     .long 1f - 0b\n\t"                      \
 _BUGVERBOSE_LOCATION(__FILE__, __LINE__)               \
                ".short " #flags "\n\t"                 \
                ".popsection\n"                         \
-                                                       \
-       "1:     brk %[imm]"                             \
-               :: [imm] "i" (BUG_BRK_IMM)              \
-)
+       "1:     "
+#else
+#define __BUG_ENTRY(flags) ""
+#endif
+
+#define __BUG_FLAGS(flags)                             \
+       asm volatile (                                  \
+               __BUG_ENTRY(flags)                      \
+               "brk %[imm]" :: [imm] "i" (BUG_BRK_IMM) \
+       );
 
-#define BUG() do {                             \
-       _BUG_FLAGS(0);                          \
-       unreachable();                          \
+
+#define BUG() do {                                     \
+       __BUG_FLAGS(0);                                 \
+       unreachable();                                  \
 } while (0)
 
-#define __WARN_TAINT(taint) _BUG_FLAGS(BUGFLAG_TAINT(taint))
+#define __WARN_TAINT(taint)                            \
+       __BUG_FLAGS(BUGFLAG_TAINT(taint))
 
-#endif /* ! CONFIG_GENERIC_BUG */
+#define HAVE_ARCH_BUG
 
 #include <asm-generic/bug.h>
 
index f0be31f..86d444f 100644 (file)
@@ -100,6 +100,7 @@ __efistub_memcpy            = KALLSYMS_HIDE(__pi_memcpy);
 __efistub_memmove              = KALLSYMS_HIDE(__pi_memmove);
 __efistub_memset               = KALLSYMS_HIDE(__pi_memset);
 __efistub_strlen               = KALLSYMS_HIDE(__pi_strlen);
+__efistub_strnlen              = KALLSYMS_HIDE(__pi_strnlen);
 __efistub_strcmp               = KALLSYMS_HIDE(__pi_strcmp);
 __efistub_strncmp              = KALLSYMS_HIDE(__pi_strncmp);
 __efistub___flush_dcache_area  = KALLSYMS_HIDE(__pi___flush_dcache_area);
index 6df738c..5dd9b57 100644 (file)
@@ -274,13 +274,6 @@ void show_regs(struct pt_regs * regs)
        __show_regs(regs);
 }
 
-/*
- * Free current thread data structures etc..
- */
-void exit_thread(void)
-{
-}
-
 static void tls_thread_flush(void)
 {
        asm ("msr tpidr_el0, xzr");
index 2ca6657..eae38da 100644 (file)
@@ -168,4 +168,4 @@ CPU_LE( lsr tmp2, tmp2, tmp4 )      /* Shift (tmp1 & 63).  */
 .Lhit_limit:
        mov     len, limit
        ret
-ENDPROC(strnlen)
+ENDPIPROC(strnlen)
index b6878eb..37d9c02 100644 (file)
@@ -4,6 +4,7 @@ config AVR32
        # that we usually don't need on AVR32.
        select EXPERT
        select HAVE_CLK
+       select HAVE_EXIT_THREAD
        select HAVE_OPROFILE
        select HAVE_KPROBES
        select VIRT_TO_BUS
index 42a53e7..68e5b9d 100644 (file)
@@ -62,9 +62,9 @@ void machine_restart(char *cmd)
 /*
  * Free current thread data structures etc
  */
-void exit_thread(void)
+void exit_thread(struct task_struct *tsk)
 {
-       ocd_disable(current);
+       ocd_disable(tsk);
 }
 
 void flush_thread(void)
index 7acd466..0c265ab 100644 (file)
@@ -76,13 +76,6 @@ static inline void release_thread(struct task_struct *dead_task)
 }
 
 /*
- * Free current thread data structures etc..
- */
-static inline void exit_thread(void)
-{
-}
-
-/*
  * Return saved PC of a blocked thread.
  */
 #define thread_saved_pc(tsk)   (tsk->thread.pc)
index 3ae9f5a..0ee7686 100644 (file)
@@ -82,10 +82,6 @@ void flush_thread(void)
 {
 }
 
-void exit_thread(void)
-{
-}
-
 /*
  * Do necessary setup to start up a newly executed thread.
  */
index e086f9e..0885510 100644 (file)
@@ -59,6 +59,7 @@ config CRIS
        select GENERIC_IOMAP
        select MODULES_USE_ELF_RELA
        select CLONE_BACKWARDS2
+       select HAVE_EXIT_THREAD if ETRAX_ARCH_V32
        select OLD_SIGSUSPEND
        select OLD_SIGACTION
        select ARCH_REQUIRE_GPIOLIB
index 02b7834..96e5afe 100644 (file)
@@ -35,15 +35,6 @@ void default_idle(void)
        local_irq_enable();
 }
 
-/*
- * Free current thread data structures etc..
- */
-
-void exit_thread(void)
-{
-       /* Nothing needs to be done.  */
-}
-
 /* if the watchdog is enabled, we can simply disable interrupts and go
  * into an eternal loop, and the watchdog will reset the CPU after 0.1s
  * if on the other hand the watchdog wasn't enabled, we just enable it and wait
index c7ce784..4d1afa9 100644 (file)
@@ -33,9 +33,9 @@ void default_idle(void)
  */
 
 extern void deconfigure_bp(long pid);
-void exit_thread(void)
+void exit_thread(struct task_struct *tsk)
 {
-       deconfigure_bp(current->pid);
+       deconfigure_bp(tsk->pid);
 }
 
 /*
index ae8d423..73f0a79 100644 (file)
@@ -97,13 +97,6 @@ extern asmlinkage void *restore_user_regs(const struct user_context *target, ...
 #define forget_segments()              do { } while (0)
 
 /*
- * Free current thread data structures etc..
- */
-static inline void exit_thread(void)
-{
-}
-
-/*
  * Return saved PC of a blocked thread.
  */
 extern unsigned long thread_saved_pc(struct task_struct *tsk);
index 54e3fd8..111df73 100644 (file)
@@ -111,13 +111,6 @@ static inline void release_thread(struct task_struct *dead_task)
 }
 
 /*
- * Free current thread data structures etc..
- */
-static inline void exit_thread(void)
-{
-}
-
-/*
  * Return saved PC of a blocked thread.
  */
 unsigned long thread_saved_pc(struct task_struct *tsk);
index a9ebd47..d9edfd3 100644 (file)
@@ -137,13 +137,6 @@ void release_thread(struct task_struct *dead_task)
 }
 
 /*
- * Free any architecture-specific thread data structures, etc.
- */
-void exit_thread(void)
-{
-}
-
-/*
  * Some archs flush debug and FPU info here
  */
 void flush_thread(void)
index 7091a36..1678ea3 100644 (file)
@@ -18,6 +18,7 @@ config IA64
        select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI
        select ARCH_MIGHT_HAVE_ACPI_PDC if ACPI
        select HAVE_UNSTABLE_SCHED_CLOCK
+       select HAVE_EXIT_THREAD
        select HAVE_IDE
        select HAVE_OPROFILE
        select HAVE_KPROBES
index 60e02f7..c5d5955 100644 (file)
@@ -4543,8 +4543,8 @@ pfm_context_unload(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg
 
 
 /*
- * called only from exit_thread(): task == current
- * we come here only if current has a context attached (loaded or masked)
+ * called only from exit_thread()
+ * we come here only if the task has a context attached (loaded or masked)
  */
 void
 pfm_exit_thread(struct task_struct *task)
index b515149..aae6c4d 100644 (file)
@@ -570,22 +570,22 @@ flush_thread (void)
 }
 
 /*
- * Clean up state associated with current thread.  This is called when
+ * Clean up state associated with a thread.  This is called when
  * the thread calls exit().
  */
 void
-exit_thread (void)
+exit_thread (struct task_struct *tsk)
 {
 
-       ia64_drop_fpu(current);
+       ia64_drop_fpu(tsk);
 #ifdef CONFIG_PERFMON
        /* if needed, stop monitoring and flush state to perfmon context */
-       if (current->thread.pfm_context)
-               pfm_exit_thread(current);
+       if (tsk->thread.pfm_context)
+               pfm_exit_thread(tsk);
 
        /* free debug register resources */
-       if (current->thread.flags & IA64_THREAD_DBG_VALID)
-               pfm_release_debug_registers(current);
+       if (tsk->thread.flags & IA64_THREAD_DBG_VALID)
+               pfm_release_debug_registers(tsk);
 #endif
 }
 
index e69221d..a88b1f0 100644 (file)
@@ -101,15 +101,6 @@ void show_regs(struct pt_regs * regs)
 #endif
 }
 
-/*
- * Free current thread data structures etc..
- */
-void exit_thread(void)
-{
-       /* Nothing to do. */
-       DPRINTK("pid = %d\n", current->pid);
-}
-
 void flush_thread(void)
 {
        DPRINTK("pid = %d\n", current->pid);
index 20dda1d..a6ce2ec 100644 (file)
@@ -153,13 +153,6 @@ static inline void release_thread(struct task_struct *dead_task)
 {
 }
 
-/*
- * Free current thread data structures etc..
- */
-static inline void exit_thread(void)
-{
-}
-
 extern unsigned long thread_saved_pc(struct task_struct *tsk);
 
 unsigned long get_wchan(struct task_struct *p);
index 0b389a8..6fe012a 100644 (file)
@@ -11,6 +11,7 @@ config METAG
        select HAVE_DEBUG_KMEMLEAK
        select HAVE_DEBUG_STACKOVERFLOW
        select HAVE_DYNAMIC_FTRACE
+       select HAVE_EXIT_THREAD
        select HAVE_FTRACE_MCOUNT_RECORD
        select HAVE_FUNCTION_TRACER
        select HAVE_KERNEL_BZIP2
index 0838ca6..a0333eb 100644 (file)
@@ -134,8 +134,6 @@ static inline void release_thread(struct task_struct *dead_task)
 #define copy_segments(tsk, mm)         do { } while (0)
 #define release_segments(mm)           do { } while (0)
 
-extern void exit_thread(void);
-
 /*
  * Return saved PC of a blocked thread.
  */
index 7f54618..3506279 100644 (file)
@@ -345,10 +345,10 @@ void flush_thread(void)
 /*
  * Free current thread data structures etc.
  */
-void exit_thread(void)
+void exit_thread(struct task_struct *tsk)
 {
-       clear_fpu(&current->thread);
-       clear_dsp(&current->thread);
+       clear_fpu(&tsk->thread);
+       clear_dsp(&tsk->thread);
 }
 
 /* TODO: figure out how to unwind the kernel stack here to figure out
index 497a988..c38d0dd 100644 (file)
@@ -70,11 +70,6 @@ static inline void release_thread(struct task_struct *dead_task)
 {
 }
 
-/* Free all resources held by a thread. */
-static inline void exit_thread(void)
-{
-}
-
 extern unsigned long thread_saved_pc(struct task_struct *t);
 
 extern unsigned long get_wchan(struct task_struct *p);
@@ -127,11 +122,6 @@ static inline void release_thread(struct task_struct *dead_task)
 {
 }
 
-/* Free current thread data structures etc.  */
-static inline void exit_thread(void)
-{
-}
-
 /* Return saved (kernel) PC of a blocked thread.  */
 #  define thread_saved_pc(tsk) \
        ((tsk)->thread.regs ? (tsk)->thread.regs->r15 : 0)
index a96c81d..5631eaa 100644 (file)
@@ -11,6 +11,7 @@ platforms += cavium-octeon
 platforms += cobalt
 platforms += dec
 platforms += emma
+platforms += generic
 platforms += jazz
 platforms += jz4740
 platforms += lantiq
index 8b0424a..2c93e3b 100644 (file)
@@ -64,6 +64,8 @@ config MIPS
        select HAVE_IRQ_TIME_ACCOUNTING
        select GENERIC_TIME_VSYSCALL
        select ARCH_CLOCKSOURCE_DATA
+       select HANDLE_DOMAIN_IRQ
+       select HAVE_EXIT_THREAD
 
 menu "Machine selection"
 
@@ -71,6 +73,57 @@ choice
        prompt "System type"
        default SGI_IP22
 
+config MIPS_GENERIC
+       bool "Generic board-agnostic MIPS kernel"
+       select BOOT_RAW
+       select BUILTIN_DTB
+       select CEVT_R4K
+       select CLKSRC_MIPS_GIC
+       select COMMON_CLK
+       select CPU_MIPSR2_IRQ_VI
+       select CPU_MIPSR2_IRQ_EI
+       select CSRC_R4K
+       select DMA_PERDEV_COHERENT
+       select HW_HAS_PCI
+       select IRQ_MIPS_CPU
+       select LIBFDT
+       select MIPS_CPU_SCACHE
+       select MIPS_GIC
+       select MIPS_L1_CACHE_SHIFT_7
+       select NO_EXCEPT_FILL
+       select PCI_DRIVERS_GENERIC
+       select PINCTRL
+       select SMP_UP if SMP
+       select SYS_HAS_CPU_MIPS32_R1
+       select SYS_HAS_CPU_MIPS32_R2
+       select SYS_HAS_CPU_MIPS32_R6
+       select SYS_HAS_CPU_MIPS64_R1
+       select SYS_HAS_CPU_MIPS64_R2
+       select SYS_HAS_CPU_MIPS64_R6
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_64BIT_KERNEL
+       select SYS_SUPPORTS_BIG_ENDIAN
+       select SYS_SUPPORTS_HIGHMEM
+       select SYS_SUPPORTS_LITTLE_ENDIAN
+       select SYS_SUPPORTS_MICROMIPS
+       select SYS_SUPPORTS_MIPS_CPS
+       select SYS_SUPPORTS_MIPS16
+       select SYS_SUPPORTS_MULTITHREADING
+       select SYS_SUPPORTS_RELOCATABLE
+       select SYS_SUPPORTS_SMARTMIPS
+       select USB_EHCI_BIG_ENDIAN_DESC if BIG_ENDIAN
+       select USB_EHCI_BIG_ENDIAN_MMIO if BIG_ENDIAN
+       select USB_OHCI_BIG_ENDIAN_DESC if BIG_ENDIAN
+       select USB_OHCI_BIG_ENDIAN_MMIO if BIG_ENDIAN
+       select USB_UHCI_BIG_ENDIAN_DESC if BIG_ENDIAN
+       select USB_UHCI_BIG_ENDIAN_MMIO if BIG_ENDIAN
+       select USE_OF
+       help
+         Select this to build a kernel which aims to support multiple boards,
+         generally using a flattened device tree passed from the bootloader
+         using the boot protocol defined in the UHI (Unified Hosting
+         Interface) specification.
+
 config MIPS_ALCHEMY
        bool "Alchemy processor based machines"
        select ARCH_PHYS_ADDR_T_64BIT
@@ -977,6 +1030,7 @@ source "arch/mips/ath79/Kconfig"
 source "arch/mips/bcm47xx/Kconfig"
 source "arch/mips/bcm63xx/Kconfig"
 source "arch/mips/bmips/Kconfig"
+source "arch/mips/generic/Kconfig"
 source "arch/mips/jazz/Kconfig"
 source "arch/mips/jz4740/Kconfig"
 source "arch/mips/lantiq/Kconfig"
@@ -1086,6 +1140,10 @@ config DMA_MAYBE_COHERENT
        select DMA_NONCOHERENT
        bool
 
+config DMA_PERDEV_COHERENT
+       bool
+       select DMA_MAYBE_COHERENT
+
 config DMA_COHERENT
        bool
 
@@ -1981,7 +2039,7 @@ config CPU_SUPPORTS_UNCACHED_ACCELERATED
        bool
 config MIPS_PGD_C0_CONTEXT
        bool
-       default y if 64BIT && CPU_MIPSR2 && !CPU_XLP
+       default y if 64BIT && (CPU_MIPSR2 || CPU_MIPSR6) && !CPU_XLP
 
 #
 # Set to y for ptrace access to watch registers.
@@ -2270,7 +2328,7 @@ config MIPS_CMP
 
 config MIPS_CPS
        bool "MIPS Coherent Processing System support"
-       depends on SYS_SUPPORTS_MIPS_CPS && !CPU_MIPSR6
+       depends on SYS_SUPPORTS_MIPS_CPS
        select MIPS_CM
        select MIPS_CPC
        select MIPS_CPS_PM if HOTPLUG_CPU
@@ -2278,6 +2336,7 @@ config MIPS_CPS
        select SMP
        select SYNC_R4K if (CEVT_R4K || CSRC_R4K)
        select SYS_SUPPORTS_HOTPLUG_CPU
+       select SYS_SUPPORTS_SCHED_SMT if CPU_MIPSR6
        select SYS_SUPPORTS_SMP
        select WEAK_ORDERING
        help
index 252e347..0e4516d 100644 (file)
@@ -138,7 +138,7 @@ cflags-$(CONFIG_CPU_MIPS32_R1)      += $(call cc-option,-march=mips32,-mips32 -U_MIPS
                        -Wa,-mips32 -Wa,--trap
 cflags-$(CONFIG_CPU_MIPS32_R2) += $(call cc-option,-march=mips32r2,-mips32r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \
                        -Wa,-mips32r2 -Wa,--trap
-cflags-$(CONFIG_CPU_MIPS32_R6) += -march=mips32r6 -Wa,--trap
+cflags-$(CONFIG_CPU_MIPS32_R6) += -march=mips32r6 -Wa,--trap -modd-spreg
 cflags-$(CONFIG_CPU_MIPS64_R1) += $(call cc-option,-march=mips64,-mips64 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS64) \
                        -Wa,-mips64 -Wa,--trap
 cflags-$(CONFIG_CPU_MIPS64_R2) += $(call cc-option,-march=mips64r2,-mips64r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS64) \
@@ -263,7 +263,14 @@ KBUILD_CPPFLAGS += -DVMLINUX_LOAD_ADDRESS=$(load-y)
 KBUILD_CPPFLAGS += -DDATAOFFSET=$(if $(dataoffset-y),$(dataoffset-y),0)
 
 bootvars-y     = VMLINUX_LOAD_ADDRESS=$(load-y) \
-                 VMLINUX_ENTRY_ADDRESS=$(entry-y)
+                 VMLINUX_ENTRY_ADDRESS=$(entry-y) \
+                 PLATFORM="$(platform-y)"
+ifdef CONFIG_32BIT
+bootvars-y     += ADDR_BITS=32
+endif
+ifdef CONFIG_64BIT
+bootvars-y     += ADDR_BITS=64
+endif
 
 LDFLAGS                        += -m $(ld-emul)
 
@@ -303,6 +310,11 @@ boot-y                     += uImage.gz
 boot-y                 += uImage.lzma
 boot-y                 += uImage.lzo
 endif
+boot-y                 += vmlinux.itb
+boot-y                 += vmlinux.gz.itb
+boot-y                 += vmlinux.bz2.itb
+boot-y                 += vmlinux.lzma.itb
+boot-y                 += vmlinux.lzo.itb
 
 # compressed boot image targets (arch/mips/boot/compressed/)
 bootz-y                        := vmlinuz
@@ -413,4 +425,54 @@ define archhelp
        echo '  dtbs_install         - Install dtbs to $(INSTALL_DTBS_PATH)'
        echo
        echo '  These will be default as appropriate for a configured platform.'
+       echo
+       echo '  If you are targeting a system supported by generic kernels you may'
+       echo '  configure the kernel for a given architecture target like so:'
+       echo
+       echo '  {micro32,32,64}{r1,r2,r6}{el,}_defconfig <BOARDS="list of boards">'
+       echo
+       echo '  Otherwise, the following default configurations are available:'
 endef
+
+generic_config_dir = $(srctree)/arch/$(ARCH)/configs/generic
+generic_defconfigs :=
+
+#
+# If the user generates a generic kernel configuration without specifying a
+# list of boards to include the config fragments for, default to including all
+# available board config fragments.
+#
+ifeq ($(BOARDS),)
+BOARDS = $(patsubst board-%.config,%,$(notdir $(wildcard $(generic_config_dir)/board-*.config)))
+endif
+
+#
+# Generic kernel configurations which merge generic_defconfig with the
+# appropriate config fragments from arch/mips/configs/generic/, resulting in
+# the ability to easily configure the kernel for a given architecture,
+# endianness & set of boards without duplicating the needed configuration in
+# hundreds of defconfig files.
+#
+define gen_generic_defconfigs
+$(foreach bits,$(1),$(foreach rev,$(2),$(foreach endian,$(3),
+target := $(bits)$(rev)$(filter el,$(endian))_defconfig
+generic_defconfigs += $$(target)
+$$(target): $(generic_config_dir)/$(bits)$(rev).config
+$$(target): $(generic_config_dir)/$(endian).config
+)))
+endef
+
+$(eval $(call gen_generic_defconfigs,32 64,r1 r2 r6,eb el))
+$(eval $(call gen_generic_defconfigs,micro32,r2,eb el))
+
+.PHONY: $(generic_defconfigs)
+$(generic_defconfigs):
+       $(Q)$(CONFIG_SHELL) $(srctree)/scripts/kconfig/merge_config.sh \
+               -m -O $(objtree) $(srctree)/arch/$(ARCH)/configs/generic_defconfig $^ \
+               $(foreach board,$(BOARDS),$(generic_config_dir)/board-$(board).config)
+       $(Q)$(MAKE) olddefconfig
+
+#
+# Prevent generic merge_config rules attempting to merge single fragments
+#
+$(generic_config_dir)/%.config: ;
index 745695d..f2f264b 100644 (file)
@@ -261,7 +261,7 @@ u32 au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid,
        au1x_dma_chan_t *cp;
 
        /*
-        * We do the intialization on the first channel allocation.
+        * We do the initialization on the first channel allocation.
         * We have to wait because of the interrupt handler initialization
         * which can't be done successfully during board set up.
         */
@@ -964,7 +964,7 @@ u32 au1xxx_dbdma_put_dscr(u32 chanid, au1x_ddma_desc_t *dscr)
        dp->dscr_source1 = dscr->dscr_source1;
        dp->dscr_cmd1 = dscr->dscr_cmd1;
        nbytes = dscr->dscr_cmd1;
-       /* Allow the caller to specifiy if an interrupt is generated */
+       /* Allow the caller to specify if an interrupt is generated */
        dp->dscr_cmd0 &= ~DSCR_CMD0_IE;
        dp->dscr_cmd0 |= dscr->dscr_cmd0 | DSCR_CMD0_V;
        ctp->chan_ptr->ddma_dbell = 0;
index 2902138..7faaa6d 100644 (file)
@@ -48,17 +48,17 @@ void __init plat_mem_setup(void)
                clear_c0_config(1 << 19); /* Clear Config[OD] */
 
        hw_coherentio = 0;
-       coherentio = 1;
+       coherentio = IO_COHERENCE_ENABLED;
        switch (alchemy_get_cputype()) {
        case ALCHEMY_CPU_AU1000:
        case ALCHEMY_CPU_AU1500:
        case ALCHEMY_CPU_AU1100:
-               coherentio = 0;
+               coherentio = IO_COHERENCE_DISABLED;
                break;
        case ALCHEMY_CPU_AU1200:
                /* Au1200 AB USB does not support coherent memory */
                if (0 == (read_c0_prid() & PRID_REV_MASK))
-                       coherentio = 0;
+                       coherentio = IO_COHERENCE_DISABLED;
                break;
        }
 
index 5b16d29..a2a8344 100644 (file)
@@ -149,8 +149,8 @@ void __init plat_mem_setup(void)
        /* intended to somewhat resemble ARM; see Documentation/arm/Booting */
        if (fw_arg0 == 0 && fw_arg1 == 0xffffffff)
                dtb = phys_to_virt(fw_arg2);
-       else if (fw_arg0 == -2) /* UHI interface */
-               dtb = (void *)fw_arg1;
+       else if (fw_passed_dtb) /* UHI interface */
+               dtb = (void *)fw_passed_dtb;
        else if (__dtb_start != __dtb_end)
                dtb = (void *)__dtb_start;
        else
index acb1988..2728a9a 100644 (file)
@@ -100,3 +100,69 @@ $(obj)/uImage.lzo: $(obj)/vmlinux.bin.lzo FORCE
 $(obj)/uImage: $(obj)/uImage.$(suffix-y)
        @ln -sf $(notdir $<) $@
        @echo '  Image $@ is ready'
+
+#
+# Flattened Image Tree (.itb) images
+#
+
+targets += vmlinux.itb
+targets += vmlinux.gz.itb
+targets += vmlinux.bz2.itb
+targets += vmlinux.lzma.itb
+targets += vmlinux.lzo.itb
+
+ifeq ($(ADDR_BITS),32)
+       itb_addr_cells = 1
+endif
+ifeq ($(ADDR_BITS),64)
+       itb_addr_cells = 2
+endif
+
+quiet_cmd_cpp_its_S = ITS     $@
+      cmd_cpp_its_S = $(CPP) $(cpp_flags) -P -C -o $@ $< \
+                       -DKERNEL_NAME="\"Linux $(KERNELRELEASE)\"" \
+                       -DVMLINUX_BINARY="\"$(3)\"" \
+                       -DVMLINUX_COMPRESSION="\"$(2)\"" \
+                       -DVMLINUX_LOAD_ADDRESS=$(VMLINUX_LOAD_ADDRESS) \
+                       -DVMLINUX_ENTRY_ADDRESS=$(VMLINUX_ENTRY_ADDRESS) \
+                       -DADDR_BITS=$(ADDR_BITS) \
+                       -DADDR_CELLS=$(itb_addr_cells)
+
+$(obj)/vmlinux.its: $(srctree)/arch/mips/$(PLATFORM)/vmlinux.its.S FORCE
+       $(call if_changed_dep,cpp_its_S,none,vmlinux.bin)
+
+$(obj)/vmlinux.gz.its: $(srctree)/arch/mips/$(PLATFORM)/vmlinux.its.S FORCE
+       $(call if_changed_dep,cpp_its_S,gzip,vmlinux.bin.gz)
+
+$(obj)/vmlinux.bz2.its: $(srctree)/arch/mips/$(PLATFORM)/vmlinux.its.S FORCE
+       $(call if_changed_dep,cpp_its_S,bzip2,vmlinux.bin.bz2)
+
+$(obj)/vmlinux.lzma.its: $(srctree)/arch/mips/$(PLATFORM)/vmlinux.its.S FORCE
+       $(call if_changed_dep,cpp_its_S,lzma,vmlinux.bin.lzma)
+
+$(obj)/vmlinux.lzo.its: $(srctree)/arch/mips/$(PLATFORM)/vmlinux.its.S FORCE
+       $(call if_changed_dep,cpp_its_S,lzo,vmlinux.bin.lzo)
+
+quiet_cmd_itb-image = ITB     $@
+      cmd_itb-image = \
+               env PATH="$(objtree)/scripts/dtc:$(PATH)" \
+               $(CONFIG_SHELL) $(MKIMAGE) \
+               -D "-I dts -O dtb -p 500 \
+                       --include $(objtree)/arch/mips \
+                       --warning no-unit_address_vs_reg" \
+               -f $(2) $@
+
+$(obj)/vmlinux.itb: $(obj)/vmlinux.its $(obj)/vmlinux.bin FORCE
+       $(call if_changed,itb-image,$<)
+
+$(obj)/vmlinux.gz.itb: $(obj)/vmlinux.gz.its $(obj)/vmlinux.bin.gz FORCE
+       $(call if_changed,itb-image,$<)
+
+$(obj)/vmlinux.bz2.itb: $(obj)/vmlinux.bz2.its $(obj)/vmlinux.bin.bz2 FORCE
+       $(call if_changed,itb-image,$<)
+
+$(obj)/vmlinux.lzma.itb: $(obj)/vmlinux.lzma.its $(obj)/vmlinux.bin.lzma FORCE
+       $(call if_changed,itb-image,$<)
+
+$(obj)/vmlinux.lzo.itb: $(obj)/vmlinux.lzo.its $(obj)/vmlinux.bin.lzo FORCE
+       $(call if_changed,itb-image,$<)
index e59d1b7..2f415d9 100644 (file)
@@ -68,7 +68,7 @@ void __cvmx_interrupt_gmxx_rxx_int_en_enable(int index, int block)
                gmx_rx_int_en.s.pause_drp = 1;
                /* Skipping gmx_rx_int_en.s.reserved_16_18 */
                /*gmx_rx_int_en.s.ifgerr = 1; */
-               /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */
+               /*gmx_rx_int_en.s.coldet = 1; // Collision detect */
                /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */
                /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */
                /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */
@@ -89,7 +89,7 @@ void __cvmx_interrupt_gmxx_rxx_int_en_enable(int index, int block)
                /*gmx_rx_int_en.s.phy_spd = 1; */
                /*gmx_rx_int_en.s.phy_link = 1; */
                /*gmx_rx_int_en.s.ifgerr = 1; */
-               /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */
+               /*gmx_rx_int_en.s.coldet = 1; // Collision detect */
                /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */
                /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */
                /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */
@@ -112,7 +112,7 @@ void __cvmx_interrupt_gmxx_rxx_int_en_enable(int index, int block)
                /*gmx_rx_int_en.s.phy_spd = 1; */
                /*gmx_rx_int_en.s.phy_link = 1; */
                /*gmx_rx_int_en.s.ifgerr = 1; */
-               /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */
+               /*gmx_rx_int_en.s.coldet = 1; // Collision detect */
                /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */
                /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */
                /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */
@@ -134,7 +134,7 @@ void __cvmx_interrupt_gmxx_rxx_int_en_enable(int index, int block)
                /*gmx_rx_int_en.s.phy_spd = 1; */
                /*gmx_rx_int_en.s.phy_link = 1; */
                /*gmx_rx_int_en.s.ifgerr = 1; */
-               /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */
+               /*gmx_rx_int_en.s.coldet = 1; // Collision detect */
                /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */
                /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */
                /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */
@@ -156,7 +156,7 @@ void __cvmx_interrupt_gmxx_rxx_int_en_enable(int index, int block)
                /*gmx_rx_int_en.s.phy_spd = 1; */
                /*gmx_rx_int_en.s.phy_link = 1; */
                /*gmx_rx_int_en.s.ifgerr = 1; */
-               /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */
+               /*gmx_rx_int_en.s.coldet = 1; // Collision detect */
                /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */
                /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */
                /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */
@@ -179,7 +179,7 @@ void __cvmx_interrupt_gmxx_rxx_int_en_enable(int index, int block)
                /*gmx_rx_int_en.s.phy_spd = 1; */
                /*gmx_rx_int_en.s.phy_link = 1; */
                /*gmx_rx_int_en.s.ifgerr = 1; */
-               /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */
+               /*gmx_rx_int_en.s.coldet = 1; // Collision detect */
                /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */
                /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */
                /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */
@@ -209,7 +209,7 @@ void __cvmx_interrupt_gmxx_rxx_int_en_enable(int index, int block)
                gmx_rx_int_en.s.pause_drp = 1;
                /* Skipping gmx_rx_int_en.s.reserved_16_18 */
                /*gmx_rx_int_en.s.ifgerr = 1; */
-               /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */
+               /*gmx_rx_int_en.s.coldet = 1; // Collision detect */
                /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */
                /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */
                /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */
index 87be167..676fab5 100644 (file)
@@ -189,7 +189,7 @@ void cvmx_pko_initialize_global(void)
        /*
         * Set the size of the PKO command buffers to an odd number of
         * 64bit words. This allows the normal two word send to stay
-        * aligned and never span a comamnd word buffer.
+        * aligned and never span a command word buffer.
         */
        config.u64 = 0;
        config.s.pool = CVMX_FPA_OUTPUT_BUFFER_POOL;
index b7fa9ae..42412ba 100644 (file)
@@ -331,7 +331,7 @@ static int octeon_update_boot_vector(unsigned int cpu)
        }
 
        if (!(avail_coremask & (1 << coreid))) {
-               /* core not available, assume, that catched by simple-executive */
+               /* core not available, assume, that caught by simple-executive */
                cvmx_write_csr(CVMX_CIU_PP_RST, 1 << coreid);
                cvmx_write_csr(CVMX_CIU_PP_RST, 0);
        }
diff --git a/arch/mips/configs/generic/32r1.config b/arch/mips/configs/generic/32r1.config
new file mode 100644 (file)
index 0000000..a11cd87
--- /dev/null
@@ -0,0 +1,2 @@
+CONFIG_CPU_MIPS32_R1=y
+CONFIG_HIGHMEM=y
diff --git a/arch/mips/configs/generic/32r2.config b/arch/mips/configs/generic/32r2.config
new file mode 100644 (file)
index 0000000..9570672
--- /dev/null
@@ -0,0 +1,3 @@
+CONFIG_CPU_MIPS32_R2=y
+CONFIG_MIPS_O32_FP64_SUPPORT=y
+CONFIG_HIGHMEM=y
diff --git a/arch/mips/configs/generic/32r6.config b/arch/mips/configs/generic/32r6.config
new file mode 100644 (file)
index 0000000..ca606e7
--- /dev/null
@@ -0,0 +1,2 @@
+CONFIG_CPU_MIPS32_R6=y
+CONFIG_HIGHMEM=y
diff --git a/arch/mips/configs/generic/64r1.config b/arch/mips/configs/generic/64r1.config
new file mode 100644 (file)
index 0000000..7c1ea7e
--- /dev/null
@@ -0,0 +1,4 @@
+CONFIG_CPU_MIPS64_R1=y
+CONFIG_64BIT=y
+CONFIG_MIPS32_O32=y
+CONFIG_MIPS32_N32=y
diff --git a/arch/mips/configs/generic/64r2.config b/arch/mips/configs/generic/64r2.config
new file mode 100644 (file)
index 0000000..b4d31ae
--- /dev/null
@@ -0,0 +1,5 @@
+CONFIG_CPU_MIPS64_R2=y
+CONFIG_MIPS_O32_FP64_SUPPORT=y
+CONFIG_64BIT=y
+CONFIG_MIPS32_O32=y
+CONFIG_MIPS32_N32=y
diff --git a/arch/mips/configs/generic/64r6.config b/arch/mips/configs/generic/64r6.config
new file mode 100644 (file)
index 0000000..7cac033
--- /dev/null
@@ -0,0 +1,4 @@
+CONFIG_CPU_MIPS64_R6=y
+CONFIG_64BIT=y
+CONFIG_MIPS32_O32=y
+CONFIG_MIPS32_N32=y
diff --git a/arch/mips/configs/generic/board-ranchu.config b/arch/mips/configs/generic/board-ranchu.config
new file mode 100644 (file)
index 0000000..fee9ad4
--- /dev/null
@@ -0,0 +1,30 @@
+CONFIG_VIRT_BOARD_RANCHU=y
+
+CONFIG_BATTERY_GOLDFISH=y
+CONFIG_FB=y
+CONFIG_FB_GOLDFISH=y
+CONFIG_GOLDFISH=y
+CONFIG_STAGING=y
+CONFIG_GOLDFISH_AUDIO=y
+CONFIG_GOLDFISH_PIC=y
+CONFIG_GOLDFISH_PIPE=y
+CONFIG_GOLDFISH_TTY=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_GOLDFISH=y
+
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_GOLDFISH_EVENTS=y
+
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_SYSCON=y
+CONFIG_POWER_RESET_SYSCON_POWEROFF=y
+
+CONFIG_VIRTIO_BLK=y
+CONFIG_VIRTIO_CONSOLE=y
+CONFIG_VIRTIO_MMIO=y
+CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
+CONFIG_NETDEVICES=y
+CONFIG_VIRTIO_NET=y
diff --git a/arch/mips/configs/generic/eb.config b/arch/mips/configs/generic/eb.config
new file mode 100644 (file)
index 0000000..c5cdc99
--- /dev/null
@@ -0,0 +1 @@
+CONFIG_CPU_BIG_ENDIAN=y
diff --git a/arch/mips/configs/generic/el.config b/arch/mips/configs/generic/el.config
new file mode 100644 (file)
index 0000000..ee43fdb
--- /dev/null
@@ -0,0 +1 @@
+CONFIG_CPU_LITTLE_ENDIAN=y
diff --git a/arch/mips/configs/generic/micro32r2.config b/arch/mips/configs/generic/micro32r2.config
new file mode 100644 (file)
index 0000000..b701fe7
--- /dev/null
@@ -0,0 +1,4 @@
+CONFIG_CPU_MIPS32_R2=y
+CONFIG_CPU_MICROMIPS=y
+CONFIG_MIPS_O32_FP64_SUPPORT=y
+CONFIG_HIGHMEM=y
diff --git a/arch/mips/configs/generic_defconfig b/arch/mips/configs/generic_defconfig
new file mode 100644 (file)
index 0000000..196c14d
--- /dev/null
@@ -0,0 +1,96 @@
+CONFIG_MIPS_GENERIC=y
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_MIPS_CPS=y
+CONFIG_CPU_HAS_MSA=y
+CONFIG_HIGHMEM=y
+CONFIG_NR_CPUS=16
+CONFIG_MIPS_O32_FP64_SUPPORT=y
+CONFIG_SYSVIPC=y
+CONFIG_NO_HZ_IDLE=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_MEMCG=y
+CONFIG_MEMCG_SWAP=y
+CONFIG_BLK_CGROUP=y
+CONFIG_CFS_BANDWIDTH=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_CGROUP_PIDS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_NAMESPACES=y
+CONFIG_USER_NS=y
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_BPF_SYSCALL=y
+CONFIG_USERFAULTFD=y
+CONFIG_EMBEDDED=y
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_CC_STACKPROTECTOR_REGULAR=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_TRIM_UNUSED_KSYMS=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_NETFILTER=y
+# CONFIG_WIRELESS is not set
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_SCSI=y
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_HWMON is not set
+CONFIG_MFD_SYSCON=y
+CONFIG_HID_A4TECH=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_CYPRESS=y
+CONFIG_HID_EZKEY=y
+CONFIG_HID_KENSINGTON=y
+CONFIG_HID_LOGITECH=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MIPS_PLATFORM_DEVICES is not set
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
+CONFIG_FANOTIFY=y
+CONFIG_FUSE_FS=y
+CONFIG_CUSE=y
+CONFIG_OVERLAY_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_V4_1=y
+CONFIG_NFS_V4_2=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_REDUCED=y
+CONFIG_DEBUG_FS=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_FTRACE is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="earlycon"
+# CONFIG_XZ_DEC_X86 is not set
+# CONFIG_XZ_DEC_POWERPC is not set
+# CONFIG_XZ_DEC_IA64 is not set
+# CONFIG_XZ_DEC_ARM is not set
+# CONFIG_XZ_DEC_ARMTHUMB is not set
+# CONFIG_XZ_DEC_SPARC is not set
diff --git a/arch/mips/configs/ranchu32r5_defconfig b/arch/mips/configs/ranchu32r5_defconfig
new file mode 100644 (file)
index 0000000..62287a9
--- /dev/null
@@ -0,0 +1,314 @@
+CONFIG_MIPS_GENERIC=y
+CONFIG_VIRT_BOARD_RANCHU=y
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_CPU_MIPS32_R2=y
+CONFIG_MIPS_CPS=y
+CONFIG_CPU_HAS_MSA=y
+CONFIG_HIGHMEM=y
+CONFIG_KSM=y
+CONFIG_CMA=y
+CONFIG_NR_CPUS=16
+CONFIG_PREEMPT=y
+CONFIG_MIPS_O32_FP64_SUPPORT=y
+# CONFIG_USELIB is not set
+CONFIG_AUDIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_PIDS=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_MEMCG=y
+CONFIG_MEMCG_SWAP=y
+CONFIG_CFS_BANDWIDTH=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_BLK_CGROUP=y
+CONFIG_NAMESPACES=y
+CONFIG_USER_NS=y
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_BPF_SYSCALL=y
+CONFIG_USERFAULTFD=y
+CONFIG_EMBEDDED=y
+CONFIG_PERF_EVENTS=y
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_CC_STACKPROTECTOR_REGULAR=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_PM_DEBUG=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_INET_ESP=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG_DESTROY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_TRACE=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_SECURITY=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_CLS_U32=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_DNS_RESOLVER=y
+CONFIG_CFG80211=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_DMA_CMA=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_VIRTIO_BLK=y
+CONFIG_SCSI=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_UEVENT=y
+CONFIG_DM_VERITY=y
+CONFIG_DM_VERITY_FEC=y
+CONFIG_NETDEVICES=y
+CONFIG_TUN=y
+CONFIG_VIRTIO_NET=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_MPPE=y
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_GOLDFISH_EVENTS=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_TABLET=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_VT is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_GOLDFISH_TTY=y
+# CONFIG_DEVMEM is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_VIRTIO_CONSOLE=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_VIRTIO=y
+CONFIG_BATTERY_GOLDFISH=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_SYSCON=y
+CONFIG_POWER_RESET_SYSCON_POWEROFF=y
+# CONFIG_HWMON is not set
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_FB=y
+CONFIG_FB_GOLDFISH=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_HIDRAW=y
+CONFIG_UHID=y
+CONFIG_HID_A4TECH=y
+CONFIG_HID_ACRUX=y
+CONFIG_HID_ACRUX_FF=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_PRODIKEYS=y
+CONFIG_HID_CYPRESS=y
+CONFIG_HID_DRAGONRISE=y
+CONFIG_DRAGONRISE_FF=y
+CONFIG_HID_EMS_FF=y
+CONFIG_HID_ELECOM=y
+CONFIG_HID_EZKEY=y
+CONFIG_HID_KEYTOUCH=y
+CONFIG_HID_KYE=y
+CONFIG_HID_WALTOP=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_TWINHAN=y
+CONFIG_HID_KENSINGTON=y
+CONFIG_HID_LCPOWER=y
+CONFIG_HID_LOGITECH=y
+CONFIG_HID_LOGITECH_DJ=y
+CONFIG_LOGITECH_FF=y
+CONFIG_LOGIRUMBLEPAD2_FF=y
+CONFIG_LOGIG940_FF=y
+# CONFIG_LOGIWHEELS_FF is not set
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+CONFIG_HID_MULTITOUCH=y
+CONFIG_HID_ORTEK=y
+CONFIG_HID_PANTHERLORD=y
+CONFIG_PANTHERLORD_FF=y
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_PICOLCD=y
+CONFIG_HID_PRIMAX=y
+CONFIG_HID_SAITEK=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SPEEDLINK=y
+CONFIG_HID_SUNPLUS=y
+CONFIG_HID_GREENASIA=y
+CONFIG_GREENASIA_FF=y
+CONFIG_HID_SMARTJOYPLUS=y
+CONFIG_SMARTJOYPLUS_FF=y
+CONFIG_HID_TIVO=y
+CONFIG_HID_TOPSEED=y
+CONFIG_HID_THRUSTMASTER=y
+CONFIG_HID_WACOM=y
+CONFIG_HID_WIIMOTE=y
+CONFIG_HID_ZEROPLUS=y
+CONFIG_HID_ZYDACRON=y
+# CONFIG_USB_SUPPORT is not set
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_GOLDFISH=y
+CONFIG_VIRTIO_MMIO=y
+CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
+CONFIG_STAGING=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_SYNC=y
+CONFIG_ION=y
+CONFIG_GOLDFISH_AUDIO=y
+CONFIG_GOLDFISH_SYNC=y
+# CONFIG_MIPS_PLATFORM_DEVICES is not set
+CONFIG_GOLDFISH=y
+CONFIG_GOLDFISH_PIPE=y
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_GOLDFISH_PIC=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
+CONFIG_FANOTIFY=y
+CONFIG_QUOTA=y
+CONFIG_QFMT_V2=y
+CONFIG_FUSE_FS=y
+CONFIG_CUSE=y
+CONFIG_OVERLAY_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_CONFIGFS_FS=y
+CONFIG_SDCARD_FS=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_REDUCED=y
+CONFIG_DEBUG_FS=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_PANIC_TIMEOUT=5
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+# CONFIG_FTRACE is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="earlycon"
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_SELINUX=y
+# CONFIG_XZ_DEC_X86 is not set
+# CONFIG_XZ_DEC_POWERPC is not set
+# CONFIG_XZ_DEC_IA64 is not set
+# CONFIG_XZ_DEC_ARM is not set
+# CONFIG_XZ_DEC_ARMTHUMB is not set
+# CONFIG_XZ_DEC_SPARC is not set
diff --git a/arch/mips/configs/ranchu32r6_defconfig b/arch/mips/configs/ranchu32r6_defconfig
new file mode 100644 (file)
index 0000000..4df031b
--- /dev/null
@@ -0,0 +1,313 @@
+CONFIG_MIPS_GENERIC=y
+CONFIG_VIRT_BOARD_RANCHU=y
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_CPU_MIPS32_R6=y
+CONFIG_MIPS_CPS=y
+CONFIG_CPU_HAS_MSA=y
+CONFIG_HIGHMEM=y
+CONFIG_KSM=y
+CONFIG_CMA=y
+CONFIG_NR_CPUS=16
+CONFIG_PREEMPT=y
+# CONFIG_USELIB is not set
+CONFIG_AUDIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_PIDS=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_MEMCG=y
+CONFIG_MEMCG_SWAP=y
+CONFIG_CFS_BANDWIDTH=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_BLK_CGROUP=y
+CONFIG_NAMESPACES=y
+CONFIG_USER_NS=y
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_BPF_SYSCALL=y
+CONFIG_USERFAULTFD=y
+CONFIG_EMBEDDED=y
+CONFIG_PERF_EVENTS=y
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_CC_STACKPROTECTOR_REGULAR=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_PM_DEBUG=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_INET_ESP=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG_DESTROY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_TRACE=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_SECURITY=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_CLS_U32=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_DNS_RESOLVER=y
+CONFIG_CFG80211=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_DMA_CMA=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_VIRTIO_BLK=y
+CONFIG_SCSI=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_UEVENT=y
+CONFIG_DM_VERITY=y
+CONFIG_DM_VERITY_FEC=y
+CONFIG_NETDEVICES=y
+CONFIG_TUN=y
+CONFIG_VIRTIO_NET=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_MPPE=y
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_GOLDFISH_EVENTS=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_TABLET=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_VT is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_GOLDFISH_TTY=y
+# CONFIG_DEVMEM is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_VIRTIO_CONSOLE=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_VIRTIO=y
+CONFIG_BATTERY_GOLDFISH=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_SYSCON=y
+CONFIG_POWER_RESET_SYSCON_POWEROFF=y
+# CONFIG_HWMON is not set
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_FB=y
+CONFIG_FB_GOLDFISH=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_HIDRAW=y
+CONFIG_UHID=y
+CONFIG_HID_A4TECH=y
+CONFIG_HID_ACRUX=y
+CONFIG_HID_ACRUX_FF=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_PRODIKEYS=y
+CONFIG_HID_CYPRESS=y
+CONFIG_HID_DRAGONRISE=y
+CONFIG_DRAGONRISE_FF=y
+CONFIG_HID_EMS_FF=y
+CONFIG_HID_ELECOM=y
+CONFIG_HID_EZKEY=y
+CONFIG_HID_KEYTOUCH=y
+CONFIG_HID_KYE=y
+CONFIG_HID_WALTOP=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_TWINHAN=y
+CONFIG_HID_KENSINGTON=y
+CONFIG_HID_LCPOWER=y
+CONFIG_HID_LOGITECH=y
+CONFIG_HID_LOGITECH_DJ=y
+CONFIG_LOGITECH_FF=y
+CONFIG_LOGIRUMBLEPAD2_FF=y
+CONFIG_LOGIG940_FF=y
+# CONFIG_LOGIWHEELS_FF is not set
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+CONFIG_HID_MULTITOUCH=y
+CONFIG_HID_ORTEK=y
+CONFIG_HID_PANTHERLORD=y
+CONFIG_PANTHERLORD_FF=y
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_PICOLCD=y
+CONFIG_HID_PRIMAX=y
+CONFIG_HID_SAITEK=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SPEEDLINK=y
+CONFIG_HID_SUNPLUS=y
+CONFIG_HID_GREENASIA=y
+CONFIG_GREENASIA_FF=y
+CONFIG_HID_SMARTJOYPLUS=y
+CONFIG_SMARTJOYPLUS_FF=y
+CONFIG_HID_TIVO=y
+CONFIG_HID_TOPSEED=y
+CONFIG_HID_THRUSTMASTER=y
+CONFIG_HID_WACOM=y
+CONFIG_HID_WIIMOTE=y
+CONFIG_HID_ZEROPLUS=y
+CONFIG_HID_ZYDACRON=y
+# CONFIG_USB_SUPPORT is not set
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_GOLDFISH=y
+CONFIG_VIRTIO_MMIO=y
+CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
+CONFIG_STAGING=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_SYNC=y
+CONFIG_ION=y
+CONFIG_GOLDFISH_AUDIO=y
+CONFIG_GOLDFISH_SYNC=y
+# CONFIG_MIPS_PLATFORM_DEVICES is not set
+CONFIG_GOLDFISH=y
+CONFIG_GOLDFISH_PIPE=y
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_GOLDFISH_PIC=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
+CONFIG_FANOTIFY=y
+CONFIG_QUOTA=y
+CONFIG_QFMT_V2=y
+CONFIG_FUSE_FS=y
+CONFIG_CUSE=y
+CONFIG_OVERLAY_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_CONFIGFS_FS=y
+CONFIG_SDCARD_FS=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_REDUCED=y
+CONFIG_DEBUG_FS=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_PANIC_TIMEOUT=5
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+# CONFIG_FTRACE is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="earlycon"
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_SELINUX=y
+# CONFIG_XZ_DEC_X86 is not set
+# CONFIG_XZ_DEC_POWERPC is not set
+# CONFIG_XZ_DEC_IA64 is not set
+# CONFIG_XZ_DEC_ARM is not set
+# CONFIG_XZ_DEC_ARMTHUMB is not set
+# CONFIG_XZ_DEC_SPARC is not set
diff --git a/arch/mips/configs/ranchu64_defconfig b/arch/mips/configs/ranchu64_defconfig
new file mode 100644 (file)
index 0000000..35ff353
--- /dev/null
@@ -0,0 +1,315 @@
+CONFIG_MIPS_GENERIC=y
+CONFIG_VIRT_BOARD_RANCHU=y
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_CPU_MIPS64_R6=y
+CONFIG_64BIT=y
+CONFIG_MIPS_CPS=y
+CONFIG_CPU_HAS_MSA=y
+CONFIG_KSM=y
+CONFIG_CMA=y
+CONFIG_NR_CPUS=16
+CONFIG_PREEMPT=y
+# CONFIG_USELIB is not set
+CONFIG_AUDIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_PIDS=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_MEMCG=y
+CONFIG_MEMCG_SWAP=y
+CONFIG_CFS_BANDWIDTH=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_BLK_CGROUP=y
+CONFIG_NAMESPACES=y
+CONFIG_USER_NS=y
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_BPF_SYSCALL=y
+CONFIG_USERFAULTFD=y
+CONFIG_EMBEDDED=y
+CONFIG_PERF_EVENTS=y
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_CC_STACKPROTECTOR_REGULAR=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_MIPS32_O32=y
+CONFIG_MIPS32_N32=y
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_PM_DEBUG=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_INET_ESP=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG_DESTROY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_TRACE=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_SECURITY=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_CLS_U32=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_DNS_RESOLVER=y
+CONFIG_CFG80211=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_DMA_CMA=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_VIRTIO_BLK=y
+CONFIG_SCSI=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_UEVENT=y
+CONFIG_DM_VERITY=y
+CONFIG_DM_VERITY_FEC=y
+CONFIG_NETDEVICES=y
+CONFIG_TUN=y
+CONFIG_VIRTIO_NET=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_MPPE=y
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_GOLDFISH_EVENTS=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_TABLET=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_VT is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_GOLDFISH_TTY=y
+# CONFIG_DEVMEM is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_VIRTIO_CONSOLE=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_VIRTIO=y
+CONFIG_BATTERY_GOLDFISH=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_SYSCON=y
+CONFIG_POWER_RESET_SYSCON_POWEROFF=y
+# CONFIG_HWMON is not set
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_FB=y
+CONFIG_FB_GOLDFISH=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_HIDRAW=y
+CONFIG_UHID=y
+CONFIG_HID_A4TECH=y
+CONFIG_HID_ACRUX=y
+CONFIG_HID_ACRUX_FF=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_PRODIKEYS=y
+CONFIG_HID_CYPRESS=y
+CONFIG_HID_DRAGONRISE=y
+CONFIG_DRAGONRISE_FF=y
+CONFIG_HID_EMS_FF=y
+CONFIG_HID_ELECOM=y
+CONFIG_HID_EZKEY=y
+CONFIG_HID_KEYTOUCH=y
+CONFIG_HID_KYE=y
+CONFIG_HID_WALTOP=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_TWINHAN=y
+CONFIG_HID_KENSINGTON=y
+CONFIG_HID_LCPOWER=y
+CONFIG_HID_LOGITECH=y
+CONFIG_HID_LOGITECH_DJ=y
+CONFIG_LOGITECH_FF=y
+CONFIG_LOGIRUMBLEPAD2_FF=y
+CONFIG_LOGIG940_FF=y
+# CONFIG_LOGIWHEELS_FF is not set
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+CONFIG_HID_MULTITOUCH=y
+CONFIG_HID_ORTEK=y
+CONFIG_HID_PANTHERLORD=y
+CONFIG_PANTHERLORD_FF=y
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_PICOLCD=y
+CONFIG_HID_PRIMAX=y
+CONFIG_HID_SAITEK=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SPEEDLINK=y
+CONFIG_HID_SUNPLUS=y
+CONFIG_HID_GREENASIA=y
+CONFIG_GREENASIA_FF=y
+CONFIG_HID_SMARTJOYPLUS=y
+CONFIG_SMARTJOYPLUS_FF=y
+CONFIG_HID_TIVO=y
+CONFIG_HID_TOPSEED=y
+CONFIG_HID_THRUSTMASTER=y
+CONFIG_HID_WACOM=y
+CONFIG_HID_WIIMOTE=y
+CONFIG_HID_ZEROPLUS=y
+CONFIG_HID_ZYDACRON=y
+# CONFIG_USB_SUPPORT is not set
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_GOLDFISH=y
+CONFIG_VIRTIO_MMIO=y
+CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
+CONFIG_STAGING=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_SYNC=y
+CONFIG_ION=y
+CONFIG_GOLDFISH_AUDIO=y
+CONFIG_GOLDFISH_SYNC=y
+# CONFIG_MIPS_PLATFORM_DEVICES is not set
+CONFIG_GOLDFISH=y
+CONFIG_GOLDFISH_PIPE=y
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_GOLDFISH_PIC=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
+CONFIG_FANOTIFY=y
+CONFIG_QUOTA=y
+CONFIG_QFMT_V2=y
+CONFIG_FUSE_FS=y
+CONFIG_CUSE=y
+CONFIG_OVERLAY_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_CONFIGFS_FS=y
+CONFIG_SDCARD_FS=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_REDUCED=y
+CONFIG_DEBUG_FS=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_PANIC_TIMEOUT=5
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+# CONFIG_FTRACE is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="earlycon"
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_SELINUX=y
+# CONFIG_XZ_DEC_X86 is not set
+# CONFIG_XZ_DEC_POWERPC is not set
+# CONFIG_XZ_DEC_IA64 is not set
+# CONFIG_XZ_DEC_ARM is not set
+# CONFIG_XZ_DEC_ARMTHUMB is not set
+# CONFIG_XZ_DEC_SPARC is not set
diff --git a/arch/mips/configs/ranchu_defconfig b/arch/mips/configs/ranchu_defconfig
new file mode 100644 (file)
index 0000000..266a11b
--- /dev/null
@@ -0,0 +1,312 @@
+CONFIG_MIPS_GENERIC=y
+CONFIG_VIRT_BOARD_RANCHU=y
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_MIPS_CPS=y
+CONFIG_HIGHMEM=y
+CONFIG_KSM=y
+CONFIG_CMA=y
+CONFIG_NR_CPUS=16
+CONFIG_PREEMPT=y
+CONFIG_MIPS_O32_FP64_SUPPORT=y
+# CONFIG_USELIB is not set
+CONFIG_AUDIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_PIDS=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_MEMCG=y
+CONFIG_MEMCG_SWAP=y
+CONFIG_CFS_BANDWIDTH=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_BLK_CGROUP=y
+CONFIG_NAMESPACES=y
+CONFIG_USER_NS=y
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_BPF_SYSCALL=y
+CONFIG_USERFAULTFD=y
+CONFIG_EMBEDDED=y
+CONFIG_PERF_EVENTS=y
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_CC_STACKPROTECTOR_REGULAR=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_PM_DEBUG=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_INET_ESP=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG_DESTROY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_TRACE=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_SECURITY=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_CLS_U32=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_DNS_RESOLVER=y
+CONFIG_CFG80211=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_DMA_CMA=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_VIRTIO_BLK=y
+CONFIG_SCSI=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_UEVENT=y
+CONFIG_DM_VERITY=y
+CONFIG_DM_VERITY_FEC=y
+CONFIG_NETDEVICES=y
+CONFIG_TUN=y
+CONFIG_VIRTIO_NET=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_MPPE=y
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_GOLDFISH_EVENTS=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_TABLET=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_VT is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_GOLDFISH_TTY=y
+# CONFIG_DEVMEM is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_VIRTIO_CONSOLE=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_VIRTIO=y
+CONFIG_BATTERY_GOLDFISH=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_SYSCON=y
+CONFIG_POWER_RESET_SYSCON_POWEROFF=y
+# CONFIG_HWMON is not set
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_FB=y
+CONFIG_FB_GOLDFISH=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_HIDRAW=y
+CONFIG_UHID=y
+CONFIG_HID_A4TECH=y
+CONFIG_HID_ACRUX=y
+CONFIG_HID_ACRUX_FF=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_PRODIKEYS=y
+CONFIG_HID_CYPRESS=y
+CONFIG_HID_DRAGONRISE=y
+CONFIG_DRAGONRISE_FF=y
+CONFIG_HID_EMS_FF=y
+CONFIG_HID_ELECOM=y
+CONFIG_HID_EZKEY=y
+CONFIG_HID_KEYTOUCH=y
+CONFIG_HID_KYE=y
+CONFIG_HID_WALTOP=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_TWINHAN=y
+CONFIG_HID_KENSINGTON=y
+CONFIG_HID_LCPOWER=y
+CONFIG_HID_LOGITECH=y
+CONFIG_HID_LOGITECH_DJ=y
+CONFIG_LOGITECH_FF=y
+CONFIG_LOGIRUMBLEPAD2_FF=y
+CONFIG_LOGIG940_FF=y
+# CONFIG_LOGIWHEELS_FF is not set
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+CONFIG_HID_MULTITOUCH=y
+CONFIG_HID_ORTEK=y
+CONFIG_HID_PANTHERLORD=y
+CONFIG_PANTHERLORD_FF=y
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_PICOLCD=y
+CONFIG_HID_PRIMAX=y
+CONFIG_HID_SAITEK=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SPEEDLINK=y
+CONFIG_HID_SUNPLUS=y
+CONFIG_HID_GREENASIA=y
+CONFIG_GREENASIA_FF=y
+CONFIG_HID_SMARTJOYPLUS=y
+CONFIG_SMARTJOYPLUS_FF=y
+CONFIG_HID_TIVO=y
+CONFIG_HID_TOPSEED=y
+CONFIG_HID_THRUSTMASTER=y
+CONFIG_HID_WACOM=y
+CONFIG_HID_WIIMOTE=y
+CONFIG_HID_ZEROPLUS=y
+CONFIG_HID_ZYDACRON=y
+# CONFIG_USB_SUPPORT is not set
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_GOLDFISH=y
+CONFIG_VIRTIO_MMIO=y
+CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
+CONFIG_STAGING=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_SYNC=y
+CONFIG_ION=y
+CONFIG_GOLDFISH_AUDIO=y
+CONFIG_GOLDFISH_SYNC=y
+# CONFIG_MIPS_PLATFORM_DEVICES is not set
+CONFIG_GOLDFISH=y
+CONFIG_GOLDFISH_PIPE=y
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_GOLDFISH_PIC=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
+CONFIG_FANOTIFY=y
+CONFIG_QUOTA=y
+CONFIG_QFMT_V2=y
+CONFIG_FUSE_FS=y
+CONFIG_CUSE=y
+CONFIG_OVERLAY_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_CONFIGFS_FS=y
+CONFIG_SDCARD_FS=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_REDUCED=y
+CONFIG_DEBUG_FS=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_PANIC_TIMEOUT=5
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+# CONFIG_FTRACE is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="earlycon noexec=on"
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_SELINUX=y
+# CONFIG_XZ_DEC_X86 is not set
+# CONFIG_XZ_DEC_POWERPC is not set
+# CONFIG_XZ_DEC_IA64 is not set
+# CONFIG_XZ_DEC_ARM is not set
+# CONFIG_XZ_DEC_ARMTHUMB is not set
+# CONFIG_XZ_DEC_SPARC is not set
index 554d1da..1910223 100644 (file)
@@ -5,7 +5,7 @@
  * Written by Ralf Baechle and Andreas Busse, modified for DECstation
  * support by Paul Antoine and Harald Koerfgen.
  *
- * completly rewritten:
+ * completely rewritten:
  * Copyright (C) 1998 Harald Koerfgen
  *
  * Rewritten extensively for controller-driven IRQ support
index 5537b94..0d75b5a 100644 (file)
@@ -9,7 +9,7 @@
  * PROM library functions for acquiring/using memory descriptors given to us
  * from the ARCS firmware.  This is only used when CONFIG_ARC_MEMORY is set
  * because on some machines like SGI IP27 the ARC memory configuration data
- * completly bogus and alternate easier to use mechanisms are available.
+ * completely bogus and alternate easier to use mechanisms are available.
  */
 #include <linux/init.h>
 #include <linux/kernel.h>
diff --git a/arch/mips/generic/Kconfig b/arch/mips/generic/Kconfig
new file mode 100644 (file)
index 0000000..80e1c72
--- /dev/null
@@ -0,0 +1,22 @@
+if MIPS_GENERIC
+
+config LEGACY_BOARDS
+       bool
+       help
+         Select this from your board if the board must use a legacy, non-UHI,
+         boot protocol. This will cause the kernel to scan through the list of
+         supported machines calling their detect functions in turn if the
+         kernel is booted without being provided with an FDT via the UHI
+         boot protocol.
+
+config VIRT_BOARD_RANCHU
+       bool "Support Ranchu platform for Android emulator"
+       help
+         This enables support for the platform used by Android emulator.
+
+         Ranchu platform consists of a set of virtual devices. This platform
+         enables emulation of variety of virtual configurations while using
+         Android emulator. Android emulator is based on Qemu, and contains
+         the support for the same set of virtual devices.
+
+endif
diff --git a/arch/mips/generic/Makefile b/arch/mips/generic/Makefile
new file mode 100644 (file)
index 0000000..bdaa5b2
--- /dev/null
@@ -0,0 +1,15 @@
+#
+# Copyright (C) 2016 Imagination Technologies
+# Author: Paul Burton <paul.burton@imgtec.com>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation;  either version 2 of the  License, or (at your
+# option) any later version.
+#
+
+obj-y += init.o
+obj-y += irq.o
+obj-y += proc.o
+
+obj-$(CONFIG_VIRT_BOARD_RANCHU)        += board-ranchu.o
diff --git a/arch/mips/generic/Platform b/arch/mips/generic/Platform
new file mode 100644 (file)
index 0000000..9a30d69
--- /dev/null
@@ -0,0 +1,14 @@
+#
+# Copyright (C) 2016 Imagination Technologies
+# Author: Paul Burton <paul.burton@imgtec.com>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation;  either version 2 of the  License, or (at your
+# option) any later version.
+#
+
+platform-$(CONFIG_MIPS_GENERIC)        += generic/
+cflags-$(CONFIG_MIPS_GENERIC)  += -I$(srctree)/arch/mips/include/asm/mach-generic
+load-$(CONFIG_MIPS_GENERIC)    += 0xffffffff80100000
+all-$(CONFIG_MIPS_GENERIC)     := vmlinux.gz.itb
diff --git a/arch/mips/generic/board-ranchu.c b/arch/mips/generic/board-ranchu.c
new file mode 100644 (file)
index 0000000..ea451b8
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Support code for virtual Ranchu board for MIPS.
+ *
+ * Author: Miodrag Dinic <miodrag.dinic@mips.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/of_address.h>
+#include <linux/types.h>
+
+#include <asm/machine.h>
+#include <asm/mipsregs.h>
+#include <asm/time.h>
+
+#define GOLDFISH_TIMER_LOW             0x00
+#define GOLDFISH_TIMER_HIGH            0x04
+
+static __init u64 read_rtc_time(void __iomem *base)
+{
+       u32 time_low;
+       u32 time_high;
+
+       /*
+        * Reading the low address latches the high value
+        * as well so there is no fear that we may read
+        * inaccurate high value.
+        */
+       time_low = readl(base + GOLDFISH_TIMER_LOW);
+       time_high = readl(base + GOLDFISH_TIMER_HIGH);
+
+       return ((u64)time_high << 32) | time_low;
+}
+
+static __init unsigned int ranchu_measure_hpt_freq(void)
+{
+       u64 rtc_start, rtc_current, rtc_delta;
+       unsigned int start, count;
+       struct device_node *np;
+       void __iomem *rtc_base;
+
+       np = of_find_compatible_node(NULL, NULL, "google,goldfish-rtc");
+       if (!np)
+               panic("%s(): Failed to find 'google,goldfish-rtc' dt node!",
+                     __func__);
+
+       rtc_base = of_iomap(np, 0);
+       if (!rtc_base)
+               panic("%s(): Failed to ioremap Goldfish RTC base!", __func__);
+
+       /*
+        * Poll the nanosecond resolution RTC for one
+        * second to calibrate the CPU frequency.
+        */
+       rtc_start = read_rtc_time(rtc_base);
+       start = read_c0_count();
+
+       do {
+               rtc_current = read_rtc_time(rtc_base);
+               rtc_delta = rtc_current - rtc_start;
+       } while (rtc_delta < NSEC_PER_SEC);
+
+       count = read_c0_count() - start;
+
+       /*
+        * Make sure the frequency will be a round number.
+        * Without this correction, the returned value may vary
+        * between subsequent emulation executions.
+        *
+        * TODO: Set this value using device tree.
+        */
+       count += 5000;
+       count -= count % 10000;
+
+       iounmap(rtc_base);
+
+       return count;
+}
+
+static const struct of_device_id ranchu_of_match[] __initconst = {
+       {
+               .compatible = "mti,ranchu",
+       },
+};
+
+MIPS_MACHINE(ranchu) = {
+       .matches = ranchu_of_match,
+       .measure_hpt_freq = ranchu_measure_hpt_freq,
+};
diff --git a/arch/mips/generic/init.c b/arch/mips/generic/init.c
new file mode 100644 (file)
index 0000000..0ea73e8
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2016 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clocksource.h>
+#include <linux/init.h>
+#include <linux/irqchip.h>
+#include <linux/of_fdt.h>
+#include <linux/of_platform.h>
+
+#include <asm/fw/fw.h>
+#include <asm/irq_cpu.h>
+#include <asm/machine.h>
+#include <asm/mips-cpc.h>
+#include <asm/prom.h>
+#include <asm/smp-ops.h>
+#include <asm/time.h>
+
+static __initdata const void *fdt;
+static __initdata const struct mips_machine *mach;
+static __initdata const void *mach_match_data;
+
+void __init prom_init(void)
+{
+       const struct mips_machine *check_mach;
+       const struct of_device_id *match;
+
+       if ((fw_arg0 == -2) && !fdt_check_header((void *)fw_arg1)) {
+               /*
+                * We booted using the UHI boot protocol, so we have been
+                * provided with the appropriate device tree for the board.
+                * Make use of it & search for any machine struct based upon
+                * the root compatible string.
+                */
+               fdt = (void *)fw_arg1;
+
+               for_each_mips_machine(check_mach) {
+                       match = mips_machine_is_compatible(check_mach, fdt);
+                       if (match) {
+                               mach = check_mach;
+                               mach_match_data = match->data;
+                               break;
+                       }
+               }
+       } else if (IS_ENABLED(CONFIG_LEGACY_BOARDS)) {
+               /*
+                * We weren't booted using the UHI boot protocol, but do
+                * support some number of boards with legacy boot protocols.
+                * Attempt to find the right one.
+                */
+               for_each_mips_machine(check_mach) {
+                       if (!check_mach->detect)
+                               continue;
+
+                       if (!check_mach->detect())
+                               continue;
+
+                       mach = check_mach;
+               }
+
+               /*
+                * If we don't recognise the machine then we can't continue, so
+                * die here.
+                */
+               BUG_ON(!mach);
+
+               /* Retrieve the machine's FDT */
+               fdt = mach->fdt;
+       }
+
+       BUG_ON(!fdt);
+}
+
+void __init *plat_get_fdt(void)
+{
+       return (void *)fdt;
+}
+
+void __init plat_mem_setup(void)
+{
+       if (mach && mach->fixup_fdt)
+               fdt = mach->fixup_fdt(fdt, mach_match_data);
+
+       strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE);
+       __dt_setup_arch((void *)fdt);
+}
+
+void __init device_tree_init(void)
+{
+       int err;
+
+       unflatten_and_copy_device_tree();
+       mips_cpc_probe();
+
+       err = register_cps_smp_ops();
+       if (err)
+               err = register_up_smp_ops();
+}
+
+void __init plat_time_init(void)
+{
+       struct device_node *np;
+       struct clk *clk;
+
+       of_clk_init(NULL);
+
+       if (!cpu_has_counter) {
+               mips_hpt_frequency = 0;
+       } else if (mach && mach->measure_hpt_freq) {
+               mips_hpt_frequency = mach->measure_hpt_freq();
+       } else {
+               np = of_get_cpu_node(0, NULL);
+               if (!np) {
+                       pr_err("Failed to get CPU node\n");
+                       return;
+               }
+
+               clk = of_clk_get(np, 0);
+               if (IS_ERR(clk)) {
+                       pr_err("Failed to get CPU clock: %ld\n", PTR_ERR(clk));
+                       return;
+               }
+
+               mips_hpt_frequency = clk_get_rate(clk);
+               clk_put(clk);
+
+               switch (boot_cpu_type()) {
+               case CPU_20KC:
+               case CPU_25KF:
+                       /* The counter runs at the CPU clock rate */
+                       break;
+               default:
+                       /* The counter runs at half the CPU clock rate */
+                       mips_hpt_frequency /= 2;
+                       break;
+               }
+       }
+
+       clocksource_probe();
+}
+
+void __init arch_init_irq(void)
+{
+       struct device_node *intc_node;
+
+       intc_node = of_find_compatible_node(NULL, NULL,
+                                           "mti,cpu-interrupt-controller");
+       if (!cpu_has_veic && !intc_node)
+               mips_cpu_irq_init();
+
+       irqchip_init();
+}
+
+static int __init publish_devices(void)
+{
+       if (!of_have_populated_dt())
+               panic("Device-tree not present");
+
+       if (of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL))
+               panic("Failed to populate DT");
+
+       return 0;
+}
+arch_initcall(publish_devices);
+
+void __init prom_free_prom_memory(void)
+{
+}
diff --git a/arch/mips/generic/irq.c b/arch/mips/generic/irq.c
new file mode 100644 (file)
index 0000000..14064bd
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2016 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clocksource.h>
+#include <linux/init.h>
+#include <linux/irqchip/mips-gic.h>
+#include <linux/types.h>
+
+#include <asm/irq.h>
+
+int get_c0_fdc_int(void)
+{
+       int mips_cpu_fdc_irq;
+
+       if (cpu_has_veic)
+               panic("Unimplemented!");
+       else if (gic_present)
+               mips_cpu_fdc_irq = gic_get_c0_fdc_int();
+       else if (cp0_fdc_irq >= 0)
+               mips_cpu_fdc_irq = MIPS_CPU_IRQ_BASE + cp0_fdc_irq;
+       else
+               mips_cpu_fdc_irq = -1;
+
+       return mips_cpu_fdc_irq;
+}
+
+int get_c0_perfcount_int(void)
+{
+       int mips_cpu_perf_irq;
+
+       if (cpu_has_veic)
+               panic("Unimplemented!");
+       else if (gic_present)
+               mips_cpu_perf_irq = gic_get_c0_perfcount_int();
+       else if (cp0_perfcount_irq >= 0)
+               mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
+       else
+               mips_cpu_perf_irq = -1;
+
+       return mips_cpu_perf_irq;
+}
+
+unsigned int get_c0_compare_int(void)
+{
+       int mips_cpu_timer_irq;
+
+       if (cpu_has_veic)
+               panic("Unimplemented!");
+       else if (gic_present)
+               mips_cpu_timer_irq = gic_get_c0_compare_int();
+       else
+               mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq;
+
+       return mips_cpu_timer_irq;
+}
diff --git a/arch/mips/generic/proc.c b/arch/mips/generic/proc.c
new file mode 100644 (file)
index 0000000..42b3325
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2016 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/of.h>
+
+#include <asm/bootinfo.h>
+
+const char *get_system_type(void)
+{
+       const char *str;
+       int err;
+
+       err = of_property_read_string(of_root, "model", &str);
+       if (!err)
+               return str;
+
+       err = of_property_read_string_index(of_root, "compatible", 0, &str);
+       if (!err)
+               return str;
+
+       return "Unknown";
+}
diff --git a/arch/mips/generic/vmlinux.its.S b/arch/mips/generic/vmlinux.its.S
new file mode 100644 (file)
index 0000000..f67fbf1
--- /dev/null
@@ -0,0 +1,31 @@
+/dts-v1/;
+
+/ {
+       description = KERNEL_NAME;
+       #address-cells = <ADDR_CELLS>;
+
+       images {
+               kernel@0 {
+                       description = KERNEL_NAME;
+                       data = /incbin/(VMLINUX_BINARY);
+                       type = "kernel";
+                       arch = "mips";
+                       os = "linux";
+                       compression = VMLINUX_COMPRESSION;
+                       load = /bits/ ADDR_BITS <VMLINUX_LOAD_ADDRESS>;
+                       entry = /bits/ ADDR_BITS <VMLINUX_ENTRY_ADDRESS>;
+                       hash@0 {
+                               algo = "sha1";
+                       };
+               };
+       };
+
+       configurations {
+               default = "conf@default";
+
+               conf@default {
+                       description = "Generic Linux kernel";
+                       kernel = "kernel@0";
+               };
+       };
+};
index b603804..6effbf5 100644 (file)
@@ -127,6 +127,10 @@ extern char arcs_cmdline[COMMAND_LINE_SIZE];
  */
 extern unsigned long fw_arg0, fw_arg1, fw_arg2, fw_arg3;
 
+#ifdef CONFIG_USE_OF
+extern unsigned long fw_passed_dtb;
+#endif
+
 /*
  * Platform memory detection hook called by setup_arch
  */
index d1e04c9..57cdc5b 100644 (file)
 #define cpu_has_mipsmt         (cpu_data[0].ases & MIPS_ASE_MIPSMT)
 #endif
 
+#ifndef cpu_has_vp
+#define cpu_has_vp             (cpu_data[0].options & MIPS_CPU_VP)
+#endif
+
 #ifndef cpu_has_userlocal
 #define cpu_has_userlocal      (cpu_data[0].options & MIPS_CPU_ULRI)
 #endif
 # define cpu_has_small_pages   (cpu_data[0].options & MIPS_CPU_SP)
 #endif
 
+#ifndef cpu_has_nan_legacy
+#define cpu_has_nan_legacy     (cpu_data[0].options & MIPS_CPU_NAN_LEGACY)
+#endif
+#ifndef cpu_has_nan_2008
+#define cpu_has_nan_2008       (cpu_data[0].options & MIPS_CPU_NAN_2008)
+#endif
+
 #endif /* __ASM_CPU_FEATURES_H */
index e7dc785..aa526c3 100644 (file)
@@ -68,7 +68,7 @@ struct cpuinfo_mips {
 #ifdef CONFIG_64BIT
        int                     vmbits; /* Virtual memory size in bits */
 #endif
-#ifdef CONFIG_MIPS_MT_SMP
+#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_CPU_MIPSR6)
        /*
         * There is not necessarily a 1:1 mapping of VPE num to CPU number
         * in particular on multi-core systems.
@@ -125,7 +125,7 @@ struct proc_cpuinfo_notifier_args {
        unsigned long n;
 };
 
-#ifdef CONFIG_MIPS_MT_SMP
+#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_CPU_MIPSR6)
 # define cpu_vpe_id(cpuinfo)   ((cpuinfo)->vpe_id)
 #else
 # define cpu_vpe_id(cpuinfo)   ({ (void)cpuinfo; 0; })
index 82ad15f..82a26ed 100644 (file)
@@ -386,6 +386,9 @@ enum cpu_type_enum {
 #define MIPS_CPU_BP_GHIST      0x8000000000ull /* R12K+ Branch Prediction Global History */
 #define MIPS_CPU_SP            0x10000000000ull /* Small (1KB) page support */
 #define MIPS_CPU_FTLB          0x20000000000ull /* CPU has Fixed-page-size TLB */
+#define MIPS_CPU_NAN_LEGACY    0x40000000000ull /* Legacy NaN implemented */
+#define MIPS_CPU_NAN_2008      0x80000000000ull /* 2008 NaN implemented */
+#define MIPS_CPU_VP            0x100000000000ull /* MIPSr6 Virtual Processors (multi-threading) */
 
 /*
  * CPU ASE encodings
index c94fafb..21c2082 100644 (file)
@@ -11,6 +11,11 @@ struct dma_map_ops;
 struct dev_archdata {
        /* DMA operations on that device */
        struct dma_map_ops *dma_ops;
+
+#ifdef CONFIG_DMA_PERDEV_COHERENT
+       /* Non-zero if DMA is coherent with CPU caches */
+       bool dma_coherent;
+#endif
 };
 
 struct pdev_archdata {
index bc5e85d..72d0eab 100644 (file)
@@ -9,14 +9,22 @@
 #ifndef __ASM_DMA_COHERENCE_H
 #define __ASM_DMA_COHERENCE_H
 
-#ifdef CONFIG_DMA_MAYBE_COHERENT
-extern int coherentio;
+enum coherent_io_user_state {
+       IO_COHERENCE_DEFAULT,
+       IO_COHERENCE_ENABLED,
+       IO_COHERENCE_DISABLED,
+};
+
+#if defined(CONFIG_DMA_PERDEV_COHERENT)
+/* Don't provide (hw_)coherentio to avoid misuse */
+#elif defined(CONFIG_DMA_MAYBE_COHERENT)
+extern enum coherent_io_user_state coherentio;
 extern int hw_coherentio;
 #else
 #ifdef CONFIG_DMA_COHERENT
-#define coherentio     1
+#define coherentio     IO_COHERENCE_ENABLED
 #else
-#define coherentio     0
+#define coherentio     IO_COHERENCE_DISABLED
 #endif
 #define hw_coherentio  0
 #endif /* CONFIG_DMA_MAYBE_COHERENT */
index e604f76..9532369 100644 (file)
@@ -34,4 +34,14 @@ static inline void dma_mark_clean(void *addr, size_t size) {}
 extern void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
               enum dma_data_direction direction);
 
+#define arch_setup_dma_ops arch_setup_dma_ops
+static inline void arch_setup_dma_ops(struct device *dev, u64 dma_base,
+                                     u64 size, const struct iommu_ops *iommu,
+                                     bool coherent)
+{
+#ifdef CONFIG_DMA_PERDEV_COHERENT
+       dev->archdata.dma_coherent = coherent;
+#endif
+}
+
 #endif /* _ASM_DMA_MAPPING_H */
diff --git a/arch/mips/include/asm/dsemul.h b/arch/mips/include/asm/dsemul.h
new file mode 100644 (file)
index 0000000..a6e0678
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2016 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __MIPS_ASM_DSEMUL_H__
+#define __MIPS_ASM_DSEMUL_H__
+
+#include <asm/break.h>
+#include <asm/inst.h>
+
+/* Break instruction with special math emu break code set */
+#define BREAK_MATH(micromips)  (((micromips) ? 0x7 : 0xd) | (BRK_MEMU << 16))
+
+/* When used as a frame index, indicates the lack of a frame */
+#define BD_EMUFRAME_NONE       ((int)BIT(31))
+
+struct mm_struct;
+struct pt_regs;
+struct task_struct;
+
+/**
+ * mips_dsemul() - 'Emulate' an instruction from a branch delay slot
+ * @regs:      User thread register context.
+ * @ir:                The instruction to be 'emulated'.
+ * @branch_pc: The PC of the branch instruction.
+ * @cont_pc:   The PC to continue at following 'emulation'.
+ *
+ * Emulate or execute an arbitrary MIPS instruction within the context of
+ * the current user thread. This is used primarily to handle instructions
+ * in the delay slots of emulated branch instructions, for example FP
+ * branch instructions on systems without an FPU.
+ *
+ * Return: Zero on success, negative if ir is a NOP, signal number on failure.
+ */
+extern int mips_dsemul(struct pt_regs *regs, mips_instruction ir,
+                      unsigned long branch_pc, unsigned long cont_pc);
+
+/**
+ * do_dsemulret() - Return from a delay slot 'emulation' frame
+ * @xcp:       User thread register context.
+ *
+ * Call in response to the BRK_MEMU break instruction used to return to
+ * the kernel from branch delay slot 'emulation' frames following a call
+ * to mips_dsemul(). Restores the user thread PC to the value that was
+ * passed as the cpc parameter to mips_dsemul().
+ *
+ * Return: True if an emulation frame was returned from, else false.
+ */
+extern bool do_dsemulret(struct pt_regs *xcp);
+
+/**
+ * dsemul_thread_cleanup() - Cleanup thread 'emulation' frame
+ * @tsk: The task structure associated with the thread
+ *
+ * If the thread @tsk has a branch delay slot 'emulation' frame
+ * allocated to it then free that frame.
+ *
+ * Return: True if a frame was freed, else false.
+ */
+extern bool dsemul_thread_cleanup(struct task_struct *tsk);
+
+/**
+ * dsemul_thread_rollback() - Rollback from an 'emulation' frame
+ * @regs:      User thread register context.
+ *
+ * If the current thread, whose register context is represented by @regs,
+ * is executing within a delay slot 'emulation' frame then exit that
+ * frame. The PC will be rolled back to the branch if the instruction
+ * that was being 'emulated' has not yet executed, or advanced to the
+ * continuation PC if it has.
+ *
+ * Return: True if a frame was exited, else false.
+ */
+extern bool dsemul_thread_rollback(struct pt_regs *regs);
+
+/**
+ * dsemul_mm_cleanup() - Cleanup per-mm delay slot 'emulation' state
+ * @mm:                The struct mm_struct to cleanup state for.
+ *
+ * Cleanup state for the given @mm, ensuring that any memory allocated
+ * for delay slot 'emulation' book-keeping is freed. This is to be called
+ * before @mm is freed in order to avoid memory leaks.
+ */
+extern void dsemul_mm_cleanup(struct mm_struct *mm);
+
+#endif /* __MIPS_ASM_DSEMUL_H__ */
index b01a6ff..dc72fdc 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/fs.h>
 #include <uapi/linux/elf.h>
 
-#include <asm/cpu-info.h>
 #include <asm/current.h>
 
 /* ELF header e_flags defines. */
@@ -44,6 +43,7 @@
 #define EF_MIPS_OPTIONS_FIRST  0x00000080
 #define EF_MIPS_32BITMODE      0x00000100
 #define EF_MIPS_FP64           0x00000200
+#define EF_MIPS_NAN2008                0x00000400
 #define EF_MIPS_ABI            0x0000f000
 #define EF_MIPS_ARCH           0xf0000000
 
@@ -305,7 +305,7 @@ do {                                                                        \
                                                                        \
        current->thread.abi = &mips_abi;                                \
                                                                        \
-       current->thread.fpu.fcr31 = boot_cpu_data.fpu_csr31;            \
+       mips_set_personality_nan(state);                                \
 } while (0)
 
 #endif /* CONFIG_32BIT */
@@ -367,7 +367,7 @@ do {                                                                        \
        else                                                            \
                current->thread.abi = &mips_abi;                        \
                                                                        \
-       current->thread.fpu.fcr31 = boot_cpu_data.fpu_csr31;            \
+       mips_set_personality_nan(state);                                \
                                                                        \
        p = personality(current->personality);                          \
        if (p != PER_LINUX32 && p != PER_LINUX)                         \
@@ -432,6 +432,7 @@ extern int arch_setup_additional_pages(struct linux_binprm *bprm,
                                       int uses_interp);
 
 struct arch_elf_state {
+       int nan_2008;
        int fp_abi;
        int interp_fp_abi;
        int overall_fp_mode;
@@ -440,17 +441,26 @@ struct arch_elf_state {
 #define MIPS_ABI_FP_UNKNOWN    (-1)    /* Unknown FP ABI (kernel internal) */
 
 #define INIT_ARCH_ELF_STATE {                  \
+       .nan_2008 = -1,                         \
        .fp_abi = MIPS_ABI_FP_UNKNOWN,          \
        .interp_fp_abi = MIPS_ABI_FP_UNKNOWN,   \
        .overall_fp_mode = -1,                  \
 }
 
+/* Whether to accept legacy-NaN and 2008-NaN user binaries.  */
+extern bool mips_use_nan_legacy;
+extern bool mips_use_nan_2008;
+
 extern int arch_elf_pt_proc(void *ehdr, void *phdr, struct file *elf,
                            bool is_interp, struct arch_elf_state *state);
 
-extern int arch_check_elf(void *ehdr, bool has_interpreter,
+extern int arch_check_elf(void *ehdr, bool has_interpreter, void *interp_ehdr,
                          struct arch_elf_state *state);
 
+extern void mips_set_personality_nan(struct arch_elf_state *state);
 extern void mips_set_personality_fp(struct arch_elf_state *state);
 
+#define elf_read_implies_exec(ex, stk) mips_elf_read_implies_exec(&(ex), stk)
+extern int mips_elf_read_implies_exec(void *elf_ex, int exstack);
+
 #endif /* _ASM_ELF_H */
index 2f021cd..c7544de 100644 (file)
@@ -24,7 +24,7 @@
 #define _ASM_FPU_EMULATOR_H
 
 #include <linux/sched.h>
-#include <asm/break.h>
+#include <asm/dsemul.h>
 #include <asm/thread_info.h>
 #include <asm/inst.h>
 #include <asm/local.h>
@@ -36,6 +36,7 @@ struct mips_fpu_emulator_stats {
        unsigned long emulated;
        unsigned long loads;
        unsigned long stores;
+       unsigned long branches;
        unsigned long cp1ops;
        unsigned long cp1xops;
        unsigned long errors;
@@ -45,6 +46,121 @@ struct mips_fpu_emulator_stats {
        unsigned long ieee754_zerodiv;
        unsigned long ieee754_invalidop;
        unsigned long ds_emul;
+
+       unsigned long abs_s;
+       unsigned long abs_d;
+       unsigned long add_s;
+       unsigned long add_d;
+       unsigned long bc1eqz;
+       unsigned long bc1nez;
+       unsigned long ceil_w_s;
+       unsigned long ceil_w_d;
+       unsigned long ceil_l_s;
+       unsigned long ceil_l_d;
+       unsigned long class_s;
+       unsigned long class_d;
+       unsigned long cmp_af_s;
+       unsigned long cmp_af_d;
+       unsigned long cmp_eq_s;
+       unsigned long cmp_eq_d;
+       unsigned long cmp_le_s;
+       unsigned long cmp_le_d;
+       unsigned long cmp_lt_s;
+       unsigned long cmp_lt_d;
+       unsigned long cmp_ne_s;
+       unsigned long cmp_ne_d;
+       unsigned long cmp_or_s;
+       unsigned long cmp_or_d;
+       unsigned long cmp_ueq_s;
+       unsigned long cmp_ueq_d;
+       unsigned long cmp_ule_s;
+       unsigned long cmp_ule_d;
+       unsigned long cmp_ult_s;
+       unsigned long cmp_ult_d;
+       unsigned long cmp_un_s;
+       unsigned long cmp_un_d;
+       unsigned long cmp_une_s;
+       unsigned long cmp_une_d;
+       unsigned long cmp_saf_s;
+       unsigned long cmp_saf_d;
+       unsigned long cmp_seq_s;
+       unsigned long cmp_seq_d;
+       unsigned long cmp_sle_s;
+       unsigned long cmp_sle_d;
+       unsigned long cmp_slt_s;
+       unsigned long cmp_slt_d;
+       unsigned long cmp_sne_s;
+       unsigned long cmp_sne_d;
+       unsigned long cmp_sor_s;
+       unsigned long cmp_sor_d;
+       unsigned long cmp_sueq_s;
+       unsigned long cmp_sueq_d;
+       unsigned long cmp_sule_s;
+       unsigned long cmp_sule_d;
+       unsigned long cmp_sult_s;
+       unsigned long cmp_sult_d;
+       unsigned long cmp_sun_s;
+       unsigned long cmp_sun_d;
+       unsigned long cmp_sune_s;
+       unsigned long cmp_sune_d;
+       unsigned long cvt_d_l;
+       unsigned long cvt_d_s;
+       unsigned long cvt_d_w;
+       unsigned long cvt_l_s;
+       unsigned long cvt_l_d;
+       unsigned long cvt_s_d;
+       unsigned long cvt_s_l;
+       unsigned long cvt_s_w;
+       unsigned long cvt_w_s;
+       unsigned long cvt_w_d;
+       unsigned long div_s;
+       unsigned long div_d;
+       unsigned long floor_w_s;
+       unsigned long floor_w_d;
+       unsigned long floor_l_s;
+       unsigned long floor_l_d;
+       unsigned long maddf_s;
+       unsigned long maddf_d;
+       unsigned long max_s;
+       unsigned long max_d;
+       unsigned long maxa_s;
+       unsigned long maxa_d;
+       unsigned long min_s;
+       unsigned long min_d;
+       unsigned long mina_s;
+       unsigned long mina_d;
+       unsigned long mov_s;
+       unsigned long mov_d;
+       unsigned long msubf_s;
+       unsigned long msubf_d;
+       unsigned long mul_s;
+       unsigned long mul_d;
+       unsigned long neg_s;
+       unsigned long neg_d;
+       unsigned long recip_s;
+       unsigned long recip_d;
+       unsigned long rint_s;
+       unsigned long rint_d;
+       unsigned long round_w_s;
+       unsigned long round_w_d;
+       unsigned long round_l_s;
+       unsigned long round_l_d;
+       unsigned long rsqrt_s;
+       unsigned long rsqrt_d;
+       unsigned long sel_s;
+       unsigned long sel_d;
+       unsigned long seleqz_s;
+       unsigned long seleqz_d;
+       unsigned long selnez_s;
+       unsigned long selnez_d;
+       unsigned long sqrt_s;
+       unsigned long sqrt_d;
+       unsigned long sub_s;
+       unsigned long sub_d;
+       unsigned long trunc_w_s;
+       unsigned long trunc_w_d;
+       unsigned long trunc_l_s;
+       unsigned long trunc_l_d;
 };
 
 DECLARE_PER_CPU(struct mips_fpu_emulator_stats, fpuemustats);
@@ -60,27 +176,18 @@ do {                                                                       \
 #define MIPS_FPU_EMU_INC_STATS(M) do { } while (0)
 #endif /* CONFIG_DEBUG_FS */
 
-extern int mips_dsemul(struct pt_regs *regs, mips_instruction ir,
-       unsigned long cpc);
-extern int do_dsemulret(struct pt_regs *xcp);
 extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
                                    struct mips_fpu_struct *ctx, int has_fpu,
                                    void *__user *fault_addr);
+void force_fcr31_sig(unsigned long fcr31, void __user *fault_addr,
+                    struct task_struct *tsk);
 int process_fpemu_return(int sig, void __user *fault_addr,
                         unsigned long fcr31);
+int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
+                 unsigned long *contpc);
 int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                     unsigned long *contpc);
 
-/*
- * Instruction inserted following the badinst to further tag the sequence
- */
-#define BD_COOKIE 0x0000bd36   /* tne $0, $0 with baggage */
-
-/*
- * Break instruction with special math emu break code set
- */
-#define BREAK_MATH (0x0000000d | (BRK_MEMU << 16))
-
 #define SIGNALLING_NAN 0x7ff800007ff80000LL
 
 static inline void fpu_emulator_init_fpu(void)
@@ -92,4 +199,15 @@ static inline void fpu_emulator_init_fpu(void)
                set_fpr64(&t->thread.fpu.fpr[i], 0, SIGNALLING_NAN);
 }
 
+/*
+ * Mask the FCSR Cause bits according to the Enable bits, observing
+ * that Unimplemented is always enabled.
+ */
+static inline unsigned long mask_fcr31_x(unsigned long fcr31)
+{
+       return fcr31 & (FPU_CSR_UNI_X |
+                       ((fcr31 & FPU_CSR_ALL_E) <<
+                        (ffs(FPU_CSR_ALL_X) - ffs(FPU_CSR_ALL_E))));
+}
+
 #endif /* _ASM_FPU_EMULATOR_H */
index 33bd2a0..8c48d6d 100644 (file)
@@ -18,4 +18,14 @@ static inline struct pt_regs *get_irq_regs(void)
        return current_thread_info()->regs;
 }
 
+static inline struct pt_regs *set_irq_regs(struct pt_regs *new_regs)
+{
+       struct pt_regs *old_regs;
+
+       old_regs = get_irq_regs();
+       current_thread_info()->regs = new_regs;
+
+       return old_regs;
+}
+
 #endif /* __ASM_IRQ_REGS_H */
index ca8077a..456ddba 100644 (file)
@@ -100,7 +100,7 @@ typedef volatile struct au1xxx_ddma_desc {
        u32     dscr_nxtptr;            /* Next descriptor pointer (mostly) */
        /*
         * First 32 bytes are HW specific!!!
-        * Lets have some SW data following -- make sure it's 32 bytes.
+        * Let's have some SW data following -- make sure it's 32 bytes.
         */
        u32     sw_status;
        u32     sw_context;
index cf92fe7..c4873e8 100644 (file)
@@ -141,7 +141,7 @@ octeon_main_processor:
 .endm
 
 /*
- * Do SMP slave processor setup necessary before we can savely execute C code.
+ * Do SMP slave processor setup necessary before we can safely execute C code.
  */
        .macro  smp_slave_setup
        .endm
index 0f8a354..61addb1 100644 (file)
@@ -49,7 +49,19 @@ static inline int plat_dma_supported(struct device *dev, u64 mask)
 
 static inline int plat_device_is_coherent(struct device *dev)
 {
-       return coherentio;
+#ifdef CONFIG_DMA_PERDEV_COHERENT
+       return dev->archdata.dma_coherent;
+#else
+       switch (coherentio) {
+       default:
+       case IO_COHERENCE_DEFAULT:
+               return hw_coherentio;
+       case IO_COHERENCE_ENABLED:
+               return 1;
+       case IO_COHERENCE_DISABLED:
+               return 0;
+       }
+#endif
 }
 
 #ifndef plat_post_dma_flush
index 13b0751..a229297 100644 (file)
@@ -16,7 +16,7 @@
        .endm
 
 /*
- * Do SMP slave processor setup necessary before we can savely execute C code.
+ * Do SMP slave processor setup necessary before we can safely execute C code.
  */
        .macro  smp_slave_setup
        .endm
index cf4384b..b0b7261 100644 (file)
@@ -11,7 +11,7 @@
 #define __ASM_MACH_IP27_IRQ_H
 
 /*
- * A hardwired interrupt number is completly stupid for this system - a
+ * A hardwired interrupt number is completely stupid for this system - a
  * large configuration might have thousands if not tenthousands of
  * interrupts.
  */
index b087cb8..f992c1d 100644 (file)
@@ -81,7 +81,7 @@
        .endm
 
 /*
- * Do SMP slave processor setup necessary before we can savely execute C code.
+ * Do SMP slave processor setup necessary before we can safely execute C code.
  */
        .macro  smp_slave_setup
        GET_NASID_ASM   t1
index bf8c3e1..7c7708a 100644 (file)
@@ -27,7 +27,7 @@ enum jz_gpio_function {
 
 /*
  Usually a driver for a SoC component has to request several gpio pins and
- configure them as funcion pins.
+ configure them as function pins.
  jz_gpio_bulk_request can be used to ease this process.
  Usually one would do something like:
 
index 98d6a2f..6425041 100644 (file)
@@ -22,7 +22,7 @@
 
 /*
  * during early_printk no ioremap possible at this early stage
- * lets use KSEG1 instead
+ * let's use KSEG1 instead
  */
 #define LTQ_ASC0_BASE_ADDR     0x1E100C00
 #define LTQ_EARLY_ASC          KSEG1ADDR(LTQ_ASC0_BASE_ADDR)
index dd6005b..b230347 100644 (file)
@@ -75,7 +75,7 @@ extern __iomem void *ltq_cgu_membase;
 
 /*
  * during early_printk no ioremap is possible
- * lets use KSEG1 instead
+ * let's use KSEG1 instead
  */
 #define LTQ_ASC1_BASE_ADDR     0x1E100C00
 #define LTQ_EARLY_ASC          KSEG1ADDR(LTQ_ASC1_BASE_ADDR)
diff --git a/arch/mips/include/asm/machine.h b/arch/mips/include/asm/machine.h
new file mode 100644 (file)
index 0000000..6b444cd
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __MIPS_ASM_MACHINE_H__
+#define __MIPS_ASM_MACHINE_H__
+
+#include <linux/libfdt.h>
+#include <linux/of.h>
+
+struct mips_machine {
+       const struct of_device_id *matches;
+       const void *fdt;
+       bool (*detect)(void);
+       const void *(*fixup_fdt)(const void *fdt, const void *match_data);
+       unsigned int (*measure_hpt_freq)(void);
+};
+
+extern long __mips_machines_start;
+extern long __mips_machines_end;
+
+#define MIPS_MACHINE(name)                                             \
+       static const struct mips_machine __mips_mach_##name             \
+               __used __section(.mips.machines.init)
+
+#define for_each_mips_machine(mach)                                    \
+       for ((mach) = (struct mips_machine *)&__mips_machines_start;    \
+            (mach) < (struct mips_machine *)&__mips_machines_end;      \
+            (mach)++)
+
+/**
+ * mips_machine_is_compatible() - check if a machine is compatible with an FDT
+ * @mach: the machine struct to check
+ * @fdt: the FDT to check for compatibility with
+ *
+ * Check whether the given machine @mach is compatible with the given flattened
+ * device tree @fdt, based upon the compatibility property of the root node.
+ *
+ * Return: the device id matched if any, else NULL
+ */
+static inline const struct of_device_id *
+mips_machine_is_compatible(const struct mips_machine *mach, const void *fdt)
+{
+       const struct of_device_id *match;
+
+       if (!mach->matches)
+               return NULL;
+
+       for (match = mach->matches; match->compatible; match++) {
+               if (fdt_node_check_compatible(fdt, 0, match->compatible) == 0)
+                       return match;
+       }
+
+       return NULL;
+}
+
+#endif /* __MIPS_ASM_MACHINE_H__ */
index b836dde..70ad1c7 100644 (file)
@@ -28,7 +28,7 @@ extern void __iomem *mips_cm_l2sync_base;
  * This function returns the physical base address of the Coherence Manager
  * global control block, or 0 if no Coherence Manager is present. It provides
  * a default implementation which reads the CMGCRBase register where available,
- * and may be overriden by platforms which determine this address in a
+ * and may be overridden by platforms which determine this address in a
  * different way by defining a function with the same prototype except for the
  * name mips_cm_phys_base (without underscores).
  */
@@ -208,6 +208,7 @@ BUILD_CM_RW(l2_config,              MIPS_CM_GCB_OFS + 0x130)
 BUILD_CM_RW(sys_config2,       MIPS_CM_GCB_OFS + 0x150)
 BUILD_CM_RW(l2_pft_control,    MIPS_CM_GCB_OFS + 0x300)
 BUILD_CM_RW(l2_pft_control_b,  MIPS_CM_GCB_OFS + 0x308)
+BUILD_CM_RW(bev_base,          MIPS_CM_GCB_OFS + 0x680)
 
 /* Core Local & Core Other register accessor functions */
 BUILD_CM_Cx_RW(reset_release,  0x00)
@@ -457,7 +458,10 @@ static inline unsigned int mips_cm_max_vp_width(void)
        if (mips_cm_revision() >= CM_REV_CM3)
                return read_gcr_sys_config2() & CM_GCR_SYS_CONFIG2_MAXVPW_MSK;
 
-       return smp_num_siblings;
+       if (config_enabled(CONFIG_SMP))
+               return smp_num_siblings;
+
+       return 1;
 }
 
 /**
index e090352..8c519f9 100644 (file)
@@ -106,6 +106,9 @@ BUILD_CPC_R_(revision,              MIPS_CPC_GCB_OFS + 0x20)
 BUILD_CPC_Cx_RW(cmd,           0x00)
 BUILD_CPC_Cx_RW(stat_conf,     0x08)
 BUILD_CPC_Cx_RW(other,         0x10)
+BUILD_CPC_Cx_RW(vp_stop,       0x20)
+BUILD_CPC_Cx_RW(vp_run,                0x28)
+BUILD_CPC_Cx_RW(vp_running,    0x30)
 
 /* CPC_Cx_CMD register fields */
 #define CPC_Cx_CMD_SHF                         0
index 4b89f28..20621e1 100644 (file)
@@ -52,7 +52,7 @@ do {                                                                  \
        __this_cpu_inc(mipsr2emustats.M);                               \
        err = __get_user(nir, (u32 __user *)regs->cp0_epc);             \
        if (!err) {                                                     \
-               if (nir == BREAK_MATH)                                  \
+               if (nir == BREAK_MATH(0))                               \
                        __this_cpu_inc(mipsr2bdemustats.M);             \
        }                                                               \
        preempt_enable();                                               \
@@ -79,7 +79,7 @@ struct r2_decoder_table {
 };
 
 
-extern void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
+extern void do_trap_or_bp(struct pt_regs *regs, unsigned int code, int si_code,
                          const char *str);
 
 #ifndef CONFIG_MIPSR2_TO_R6_EMULATOR
index e43aca1..c785da1 100644 (file)
 #define MIPS_CONF5_MRP         (_ULCAST_(1) << 3)
 #define MIPS_CONF5_LLB         (_ULCAST_(1) << 4)
 #define MIPS_CONF5_MVH         (_ULCAST_(1) << 5)
+#define MIPS_CONF5_VP          (_ULCAST_(1) << 7)
 #define MIPS_CONF5_FRE         (_ULCAST_(1) << 8)
 #define MIPS_CONF5_UFE         (_ULCAST_(1) << 9)
 #define MIPS_CONF5_MSAEN       (_ULCAST_(1) << 27)
index 1afa1f9..f6ba08d 100644 (file)
@@ -2,11 +2,20 @@
 #define __ASM_MMU_H
 
 #include <linux/atomic.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
 
 typedef struct {
        unsigned long asid[NR_CPUS];
        void *vdso;
        atomic_t fp_mode_switching;
+
+       /* lock to be held whilst modifying fp_bd_emupage_allocmap */
+       spinlock_t bd_emupage_lock;
+       /* bitmap tracking allocation of fp_bd_emupage */
+       unsigned long *bd_emupage_allocmap;
+       /* wait queue for threads requiring an emuframe */
+       wait_queue_head_t bd_emupage_queue;
 } mm_context_t;
 
 #endif /* __ASM_MMU_H */
index 45914b5..3a7761f 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/smp.h>
 #include <linux/slab.h>
 #include <asm/cacheflush.h>
+#include <asm/dsemul.h>
 #include <asm/hazards.h>
 #include <asm/tlbflush.h>
 #include <asm-generic/mm_hooks.h>
@@ -133,6 +134,10 @@ init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 
        atomic_set(&mm->context.fp_mode_switching, 0);
 
+       mm->context.bd_emupage_allocmap = NULL;
+       spin_lock_init(&mm->context.bd_emupage_lock);
+       init_waitqueue_head(&mm->context.bd_emupage_queue);
+
        return 0;
 }
 
@@ -167,6 +172,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
  */
 static inline void destroy_context(struct mm_struct *mm)
 {
+       dsemul_mm_cleanup(mm);
 }
 
 #define deactivate_mm(tsk, mm) do { } while (0)
index f7dd17d..f4f1996 100644 (file)
@@ -33,7 +33,7 @@
 /* Packet buffers */
 #define CVMX_FPA_PACKET_POOL               (0)
 #define CVMX_FPA_PACKET_POOL_SIZE          CVMX_FPA_POOL_0_SIZE
-/* Work queue entrys */
+/* Work queue entries */
 #define CVMX_FPA_WQE_POOL                  (1)
 #define CVMX_FPA_WQE_POOL_SIZE             CVMX_FPA_POOL_1_SIZE
 /* PKO queue command buffers */
index 774bb45..56e3436 100644 (file)
@@ -189,7 +189,7 @@ static inline uint64_t cvmx_ptr_to_phys(void *ptr)
 static inline void *cvmx_phys_to_ptr(uint64_t physical_address)
 {
        if (sizeof(void *) == 8) {
-               /* Just set the top bit, avoiding any TLB uglyness */
+               /* Just set the top bit, avoiding any TLB ugliness */
                return CASTPTR(void,
                               CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
                                            physical_address));
index 21ed715..74cb004 100644 (file)
@@ -229,8 +229,10 @@ extern int __virt_addr_valid(const volatile void *kaddr);
 #define virt_addr_valid(kaddr)                                         \
        __virt_addr_valid((const volatile void *) (kaddr))
 
-#define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
-                                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+#define VM_DATA_DEFAULT_FLAGS \
+       (VM_READ | VM_WRITE | \
+        ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \
+        VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
 #define UNCAC_ADDR(addr)       ((addr) - PAGE_OFFSET + UNCAC_BASE)
 #define CAC_ADDR(addr)         ((addr) - UNCAC_BASE + PAGE_OFFSET)
index 8d7a63b..3206245 100644 (file)
@@ -269,16 +269,16 @@ typedef struct bridge_err_cmdword_s {
        union {
                u32             cmd_word;
                struct {
-                       u32     didn:4,         /* Destination ID */
-                               sidn:4,         /* Source ID      */
-                               pactyp:4,       /* Packet type    */
-                               tnum:5,         /* Trans Number   */
-                               coh:1,          /* Coh Transacti  */
-                               ds:2,           /* Data size      */
-                               gbr:1,          /* GBR enable     */
-                               vbpm:1,         /* VBPM message   */
+                       u32     didn:4,         /* Destination ID  */
+                               sidn:4,         /* Source ID       */
+                               pactyp:4,       /* Packet type     */
+                               tnum:5,         /* Trans Number    */
+                               coh:1,          /* Coh Transaction */
+                               ds:2,           /* Data size       */
+                               gbr:1,          /* GBR enable      */
+                               vbpm:1,         /* VBPM message    */
                                error:1,        /* Error occurred  */
-                               barr:1,         /* Barrier op     */
+                               barr:1,         /* Barrier op      */
                                rsvd:8;
                } berr_st;
        } berr_un;
index 041153f..25eef1d 100644 (file)
 #ifndef _ASM_PROCESSOR_H
 #define _ASM_PROCESSOR_H
 
+#include <linux/atomic.h>
 #include <linux/cpumask.h>
 #include <linux/threads.h>
 
 #include <asm/cachectl.h>
 #include <asm/cpu.h>
 #include <asm/cpu-info.h>
+#include <asm/dsemul.h>
 #include <asm/mipsregs.h>
 #include <asm/prefetch.h>
 
@@ -74,7 +76,11 @@ extern unsigned int vced_count, vcei_count;
 
 #endif
 
-#define STACK_TOP      (TASK_SIZE & PAGE_MASK)
+/*
+ * One page above the stack is used for branch delay slot "emulation".
+ * See dsemul.c for details.
+ */
+#define STACK_TOP      ((TASK_SIZE & PAGE_MASK) - PAGE_SIZE)
 
 /*
  * This decides where the kernel will search for a free chunk of vm
@@ -252,6 +258,12 @@ struct thread_struct {
 
        /* Saved fpu/fpu emulator stuff. */
        struct mips_fpu_struct fpu FPU_ALIGN;
+       /* Assigned branch delay slot 'emulation' frame */
+       atomic_t bd_emu_frame;
+       /* PC of the branch from a branch delay slot 'emulation' */
+       unsigned long bd_emu_branch_pc;
+       /* PC to continue from following a branch delay slot 'emulation' */
+       unsigned long bd_emu_cont_pc;
 #ifdef CONFIG_MIPS_MT_FPAFF
        /* Emulated instruction count */
        unsigned long emulated_fp;
@@ -319,6 +331,10 @@ struct thread_struct {
         * FPU affinity state (null if not FPAFF)               \
         */                                                     \
        FPAFF_INIT                                              \
+       /* Delay slot emulation */                              \
+       .bd_emu_frame = ATOMIC_INIT(BD_EMUFRAME_NONE),          \
+       .bd_emu_branch_pc = 0,                                  \
+       .bd_emu_cont_pc = 0,                                    \
        /*                                                      \
         * Saved DSP stuff                                      \
         */                                                     \
@@ -355,6 +371,10 @@ extern unsigned long thread_saved_pc(struct task_struct *tsk);
  */
 extern void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp);
 
+static inline void flush_thread(void)
+{
+}
+
 unsigned long get_wchan(struct task_struct *p);
 
 #define __KSTK_TOS(tsk) ((unsigned long)task_stack_page(tsk) + \
index 38902bf..667ca3c 100644 (file)
@@ -210,7 +210,11 @@ static inline void protected_writeback_dcache_line(unsigned long addr)
 
 static inline void protected_writeback_scache_line(unsigned long addr)
 {
+#ifdef CONFIG_EVA
+       protected_cachee_op(Hit_Writeback_Inv_SD, addr);
+#else
        protected_cache_op(Hit_Writeback_Inv_SD, addr);
+#endif
 }
 
 /*
index 59920b3..4a9c990 100644 (file)
@@ -147,7 +147,7 @@ struct hpc3_ethregs {
 #define HPC3_EPCFG_P1   0x000f /* Cycles to spend in P1 state for PIO */
 #define HPC3_EPCFG_P2   0x00f0 /* Cycles to spend in P2 state for PIO */
 #define HPC3_EPCFG_P3   0x0f00 /* Cycles to spend in P3 state for PIO */
-#define HPC3_EPCFG_TST  0x1000 /* Diagnistic ram test feature bit */
+#define HPC3_EPCFG_TST  0x1000 /* Diagnostic ram test feature bit */
 
        u32 _unused2[0x1000/4 - 8];     /* padding */
 
index 26ddfff..105a947 100644 (file)
@@ -144,7 +144,7 @@ struct linux_tinfo {
 struct linux_vdirent {
        ULONG namelen;
        unsigned char attr;
-       char fname[32]; /* XXX imperical, should be a define */
+       char fname[32]; /* XXX empirical, should be a define */
 };
 
 /* Other stuff for files. */
@@ -179,7 +179,7 @@ struct linux_finfo {
        enum linux_devtypes   dtype;
        unsigned long         namelen;
        unsigned char         attr;
-       char                  name[32]; /* XXX imperical, should be define */
+       char                  name[32]; /* XXX empirical, should be define */
 };
 
 /* This describes the vector containing function pointers to the ARC
index 326c16e..2ae1f61 100644 (file)
@@ -29,7 +29,7 @@ extern struct core_boot_config *mips_cps_core_bootcfg;
 extern void mips_cps_core_entry(void);
 extern void mips_cps_core_init(void);
 
-extern struct vpe_boot_config *mips_cps_boot_vpes(void);
+extern void mips_cps_boot_vpes(struct core_boot_config *cfg, unsigned vpe);
 
 extern void mips_cps_pm_save(void);
 extern void mips_cps_pm_restore(void);
index e33f036..feb3851 100644 (file)
@@ -355,7 +355,7 @@ struct ioc3_etxd {
 #define SSCR_PAUSE_STATE 0x40000000    /* sets when PAUSE takes effect */
 #define SSCR_RESET     0x80000000      /* reset DMA channels */
 
-/* all producer/comsumer pointers are the same bitfield */
+/* all producer/consumer pointers are the same bitfield */
 #define PROD_CONS_PTR_4K 0x00000ff8    /* for 4K buffers */
 #define PROD_CONS_PTR_1K 0x000003f8    /* for 1K buffers */
 #define PROD_CONS_PTR_OFF 3
index 5998b13..57ece90 100644 (file)
@@ -628,7 +628,7 @@ typedef union h1_icrbb_u {
 /*
  * Values for field imsgtype
  */
-#define IIO_ICRB_IMSGT_XTALK   0       /* Incoming Meessage from Xtalk */
+#define IIO_ICRB_IMSGT_XTALK   0       /* Incoming Message from Xtalk */
 #define IIO_ICRB_IMSGT_BTE     1       /* Incoming message from BTE    */
 #define IIO_ICRB_IMSGT_SN0NET  2       /* Incoming message from SN0 net */
 #define IIO_ICRB_IMSGT_CRB     3       /* Incoming message from CRB ???  */
index ebb5c0f..c0ae279 100644 (file)
@@ -76,6 +76,22 @@ do { if (cpu_has_rw_llb) {                                           \
 } while (0)
 
 /*
+ * Check FCSR for any unmasked exceptions pending set with `ptrace',
+ * clear them and send a signal.
+ */
+#define __sanitize_fcr31(next)                                         \
+do {                                                                   \
+       unsigned long fcr31 = mask_fcr31_x(next->thread.fpu.fcr31);     \
+       void __user *pc;                                                \
+                                                                       \
+       if (unlikely(fcr31)) {                                          \
+               pc = (void __user *)task_pt_regs(next)->cp0_epc;        \
+               next->thread.fpu.fcr31 &= ~fcr31;                       \
+               force_fcr31_sig(fcr31, pc, next);                       \
+       }                                                               \
+} while (0)
+
+/*
  * For newly created kernel threads switch_to() will return to
  * ret_from_kernel_thread, newly created user threads to ret_from_fork.
  * That is, everything following resume() will be skipped for new threads.
@@ -85,6 +101,8 @@ do { if (cpu_has_rw_llb) {                                           \
 do {                                                                   \
        __mips_mt_fpaff_switch_to(prev);                                \
        lose_fpu_inatomic(1, prev);                                     \
+       if (tsk_used_math(next))                                        \
+               __sanitize_fcr31(next);                                 \
        if (cpu_has_dsp) {                                              \
                __save_dsp(prev);                                       \
                __restore_dsp(next);                                    \
index c74c32c..b6e20f3 100644 (file)
@@ -96,7 +96,7 @@ static inline bool eva_kernel_access(void)
 }
 
 /*
- * Is a address valid? This does a straighforward calculation rather
+ * Is a address valid? This does a straightforward calculation rather
  * than tests.
  *
  * Address valid if:
index 8f4ca5d..b7cd6cf 100644 (file)
@@ -79,8 +79,8 @@ union mips_vdso_data {
        struct {
                u64 xtime_sec;
                u64 xtime_nsec;
-               u32 wall_to_mono_sec;
-               u32 wall_to_mono_nsec;
+               u64 wall_to_mono_sec;
+               u64 wall_to_mono_nsec;
                u32 seq_count;
                u32 cs_shift;
                u8 clock_mode;
index 9b44d5a..bd817e6 100644 (file)
 enum major_op {
        spec_op, bcond_op, j_op, jal_op,
        beq_op, bne_op, blez_op, bgtz_op,
-       addi_op, cbcond0_op = addi_op, addiu_op, slti_op, sltiu_op,
+       addi_op, pop10_op = addi_op, addiu_op, slti_op, sltiu_op,
        andi_op, ori_op, xori_op, lui_op,
        cop0_op, cop1_op, cop2_op, cop1x_op,
        beql_op, bnel_op, blezl_op, bgtzl_op,
-       daddi_op, cbcond1_op = daddi_op, daddiu_op, ldl_op, ldr_op,
+       daddi_op, pop30_op = daddi_op, daddiu_op, ldl_op, ldr_op,
        spec2_op, jalx_op, mdmx_op, msa_op = mdmx_op, spec3_op,
        lb_op, lh_op, lwl_op, lw_op,
        lbu_op, lhu_op, lwr_op, lwu_op,
        sb_op, sh_op, swl_op, sw_op,
        sdl_op, sdr_op, swr_op, cache_op,
        ll_op, lwc1_op, lwc2_op, bc6_op = lwc2_op, pref_op,
-       lld_op, ldc1_op, ldc2_op, beqzcjic_op = ldc2_op, ld_op,
+       lld_op, ldc1_op, ldc2_op, pop66_op = ldc2_op, ld_op,
        sc_op, swc1_op, swc2_op, balc6_op = swc2_op, major_3b_op,
-       scd_op, sdc1_op, sdc2_op, bnezcjialc_op = sdc2_op, sd_op
+       scd_op, sdc1_op, sdc2_op, pop76_op = sdc2_op, sd_op
 };
 
 /*
@@ -166,6 +166,7 @@ enum cop1_sdw_func {
        fceill_op    =  0x0a, ffloorl_op   =  0x0b,
        fround_op    =  0x0c, ftrunc_op    =  0x0d,
        fceil_op     =  0x0e, ffloor_op    =  0x0f,
+       fsel_op      =  0x10,
        fmovc_op     =  0x11, fmovz_op     =  0x12,
        fmovn_op     =  0x13, fseleqz_op   =  0x14,
        frecip_op    =  0x15, frsqrt_op    =  0x16,
@@ -644,6 +645,16 @@ struct msa_mi10_format {           /* MSA MI10 */
        ;))))))
 };
 
+struct dsp_format {            /* SPEC3 DSP format instructions */
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int base : 5,
+       __BITFIELD_FIELD(unsigned int index : 5,
+       __BITFIELD_FIELD(unsigned int rd : 5,
+       __BITFIELD_FIELD(unsigned int op : 5,
+       __BITFIELD_FIELD(unsigned int func : 6,
+       ;))))))
+};
+
 struct spec3_format {   /* SPEC3 */
        __BITFIELD_FIELD(unsigned int opcode:6,
        __BITFIELD_FIELD(unsigned int rs:5,
@@ -799,6 +810,13 @@ struct mm_x_format {               /* Scaled indexed load format (microMIPS) */
        ;)))))
 };
 
+struct mm_a_format {           /* ADDIUPC format (microMIPS) */
+       __BITFIELD_FIELD(unsigned int opcode : 6,
+       __BITFIELD_FIELD(unsigned int rs : 3,
+       __BITFIELD_FIELD(signed int simmediate : 23,
+       ;)))
+};
+
 /*
  * microMIPS instruction formats (16-bit length)
  */
@@ -925,6 +943,7 @@ union mips_instruction {
        struct b_format b_format;
        struct ps_format ps_format;
        struct v_format v_format;
+       struct dsp_format dsp_format;
        struct spec3_format spec3_format;
        struct fb_format fb_format;
        struct fp0_format fp0_format;
@@ -940,6 +959,7 @@ union mips_instruction {
        struct mm_i_format mm_i_format;
        struct mm_m_format mm_m_format;
        struct mm_x_format mm_x_format;
+       struct mm_a_format mm_a_format;
        struct mm_b0_format mm_b0_format;
        struct mm_b1_format mm_b1_format;
        struct mm16_m_format mm16_m_format ;
index 1188e00..9fd86df 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Support for n32 Linux/MIPS ELF binaries.
+ * Author: Ralf Baechle (ralf@linux-mips.org)
  *
  * Copyright (C) 1999, 2001 Ralf Baechle
  * Copyright (C) 1999, 2001 Silicon Graphics, Inc.
@@ -51,7 +52,6 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
 #define ELF_ET_DYN_BASE                (TASK32_SIZE / 3 * 2)
 
 #include <asm/processor.h>
-#include <linux/module.h>
 #include <linux/elfcore.h>
 #include <linux/compat.h>
 #include <linux/math64.h>
@@ -110,12 +110,6 @@ jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value)
 
 #define ELF_CORE_EFLAGS EF_MIPS_ABI2
 
-MODULE_DESCRIPTION("Binary format loader for compatibility with n32 Linux/MIPS binaries");
-MODULE_AUTHOR("Ralf Baechle (ralf@linux-mips.org)");
-
-#undef MODULE_DESCRIPTION
-#undef MODULE_AUTHOR
-
 #undef TASK_SIZE
 #define TASK_SIZE TASK_SIZE32
 
index 9287678..bccbc01 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Support for o32 Linux/MIPS ELF binaries.
+ * Author: Ralf Baechle (ralf@linux-mips.org)
  *
  * Copyright (C) 1999, 2001 Ralf Baechle
  * Copyright (C) 1999, 2001 Silicon Graphics, Inc.
@@ -72,7 +73,6 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
 
 #include <asm/processor.h>
 
-#include <linux/module.h>
 #include <linux/elfcore.h>
 #include <linux/compat.h>
 #include <linux/math64.h>
@@ -129,12 +129,6 @@ jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value)
        value->tv_usec = rem / NSEC_PER_USEC;
 }
 
-MODULE_DESCRIPTION("Binary format loader for compatibility with o32 Linux/MIPS binaries");
-MODULE_AUTHOR("Ralf Baechle (ralf@linux-mips.org)");
-
-#undef MODULE_DESCRIPTION
-#undef MODULE_AUTHOR
-
 #undef TASK_SIZE
 #define TASK_SIZE TASK_SIZE32
 
index 71e8f4c..56f166a 100644 (file)
@@ -9,7 +9,7 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <asm/branch.h>
 #include <asm/cpu.h>
 #include <asm/cpu-features.h>
@@ -479,7 +479,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
                        /*
                         * OK we are here either because we hit a NAL
                         * instruction or because we are emulating an
-                        * old bltzal{,l} one. Lets figure out what the
+                        * old bltzal{,l} one. Let's figure out what the
                         * case really is.
                         */
                        if (!insn.i_format.rs) {
@@ -511,7 +511,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
                        /*
                         * OK we are here either because we hit a BAL
                         * instruction or because we are emulating an
-                        * old bgezal{,l} one. Lets figure out what the
+                        * old bgezal{,l} one. Let's figure out what the
                         * case really is.
                         */
                        if (!insn.i_format.rs) {
@@ -799,7 +799,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
                epc += 4 + (insn.i_format.simmediate << 2);
                regs->cp0_epc = epc;
                break;
-       case beqzcjic_op:
+       case pop66_op:
                if (!cpu_has_mips_r6) {
                        ret = -SIGILL;
                        break;
@@ -807,7 +807,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
                /* Compact branch: BEQZC || JIC */
                regs->cp0_epc += 8;
                break;
-       case bnezcjialc_op:
+       case pop76_op:
                if (!cpu_has_mips_r6) {
                        ret = -SIGILL;
                        break;
@@ -820,8 +820,8 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
                regs->cp0_epc += 8;
                break;
 #endif
-       case cbcond0_op:
-       case cbcond1_op:
+       case pop10_op:
+       case pop30_op:
                /* Only valid for MIPS R6 */
                if (!cpu_has_mips_r6) {
                        ret = -SIGILL;
index ac81edd..6829ee2 100644 (file)
 #include <asm/mipsmtregs.h>
 #include <asm/pm.h>
 
+#define GCR_CPC_BASE_OFS       0x0088
 #define GCR_CL_COHERENCE_OFS   0x2008
 #define GCR_CL_ID_OFS          0x2028
 
+#define CPC_CL_VC_STOP_OFS     0x2020
+#define CPC_CL_VC_RUN_OFS      0x2028
+
 .extern mips_cm_base
 
 .set noreorder
         nop
        .endm
 
+       /*
+        * Set dest to non-zero if the core supports MIPSr6 multithreading
+        * (ie. VPs), else zero. If MIPSr6 multithreading is not supported then
+        * branch to nomt.
+        */
+       .macro  has_vp  dest, nomt
+       mfc0    \dest, CP0_CONFIG, 1
+       bgez    \dest, \nomt
+        mfc0   \dest, CP0_CONFIG, 2
+       bgez    \dest, \nomt
+        mfc0   \dest, CP0_CONFIG, 3
+       bgez    \dest, \nomt
+        mfc0   \dest, CP0_CONFIG, 4
+       bgez    \dest, \nomt
+        mfc0   \dest, CP0_CONFIG, 5
+       andi    \dest, \dest, MIPS_CONF5_VP
+       beqz    \dest, \nomt
+        nop
+       .endm
+
+       /* Calculate an uncached address for the CM GCRs */
+       .macro  cmgcrb  dest
+       .set    push
+       .set    noat
+       MFC0    $1, CP0_CMGCRBASE
+       PTR_SLL $1, $1, 4
+       PTR_LI  \dest, UNCAC_BASE
+       PTR_ADDU \dest, \dest, $1
+       .set    pop
+       .endm
+
 .section .text.cps-vec
 .balign 0x1000
 
@@ -90,120 +125,64 @@ not_nmi:
        li      t0, ST0_CU1 | ST0_CU0 | ST0_BEV | STATUS_BITDEPS
        mtc0    t0, CP0_STATUS
 
-       /*
-        * Clear the bits used to index the caches. Note that the architecture
-        * dictates that writing to any of TagLo or TagHi selects 0 or 2 should
-        * be valid for all MIPS32 CPUs, even those for which said writes are
-        * unnecessary.
-        */
-       mtc0    zero, CP0_TAGLO, 0
-       mtc0    zero, CP0_TAGHI, 0
-       mtc0    zero, CP0_TAGLO, 2
-       mtc0    zero, CP0_TAGHI, 2
-       ehb
-
-       /* Primary cache configuration is indicated by Config1 */
-       mfc0    v0, CP0_CONFIG, 1
-
-       /* Detect I-cache line size */
-       _EXT    t0, v0, MIPS_CONF1_IL_SHF, MIPS_CONF1_IL_SZ
-       beqz    t0, icache_done
-        li     t1, 2
-       sllv    t0, t1, t0
-
-       /* Detect I-cache size */
-       _EXT    t1, v0, MIPS_CONF1_IS_SHF, MIPS_CONF1_IS_SZ
-       xori    t2, t1, 0x7
-       beqz    t2, 1f
-        li     t3, 32
-       addiu   t1, t1, 1
-       sllv    t1, t3, t1
-1:     /* At this point t1 == I-cache sets per way */
-       _EXT    t2, v0, MIPS_CONF1_IA_SHF, MIPS_CONF1_IA_SZ
-       addiu   t2, t2, 1
-       mul     t1, t1, t0
-       mul     t1, t1, t2
-
-       li      a0, CKSEG0
-       PTR_ADD a1, a0, t1
-1:     cache   Index_Store_Tag_I, 0(a0)
-       PTR_ADD a0, a0, t0
-       bne     a0, a1, 1b
+       /* Skip cache & coherence setup if we're already coherent */
+       cmgcrb  v1
+       lw      s7, GCR_CL_COHERENCE_OFS(v1)
+       bnez    s7, 1f
         nop
-icache_done:
 
-       /* Detect D-cache line size */
-       _EXT    t0, v0, MIPS_CONF1_DL_SHF, MIPS_CONF1_DL_SZ
-       beqz    t0, dcache_done
-        li     t1, 2
-       sllv    t0, t1, t0
-
-       /* Detect D-cache size */
-       _EXT    t1, v0, MIPS_CONF1_DS_SHF, MIPS_CONF1_DS_SZ
-       xori    t2, t1, 0x7
-       beqz    t2, 1f
-        li     t3, 32
-       addiu   t1, t1, 1
-       sllv    t1, t3, t1
-1:     /* At this point t1 == D-cache sets per way */
-       _EXT    t2, v0, MIPS_CONF1_DA_SHF, MIPS_CONF1_DA_SZ
-       addiu   t2, t2, 1
-       mul     t1, t1, t0
-       mul     t1, t1, t2
+       /* Initialize the L1 caches */
+       jal     mips_cps_cache_init
+        nop
 
-       li      a0, CKSEG0
-       PTR_ADDU a1, a0, t1
-       PTR_SUBU a1, a1, t0
-1:     cache   Index_Store_Tag_D, 0(a0)
-       bne     a0, a1, 1b
-        PTR_ADD a0, a0, t0
-dcache_done:
+       /* Enter the coherent domain */
+       li      t0, 0xff
+       sw      t0, GCR_CL_COHERENCE_OFS(v1)
+       ehb
 
        /* Set Kseg0 CCA to that in s0 */
-       mfc0    t0, CP0_CONFIG
+1:     mfc0    t0, CP0_CONFIG
        ori     t0, 0x7
        xori    t0, 0x7
        or      t0, t0, s0
        mtc0    t0, CP0_CONFIG
        ehb
 
-       /* Calculate an uncached address for the CM GCRs */
-       MFC0    v1, CP0_CMGCRBASE
-       PTR_SLL v1, v1, 4
-       PTR_LI  t0, UNCAC_BASE
-       PTR_ADDU v1, v1, t0
-
-       /* Enter the coherent domain */
-       li      t0, 0xff
-       sw      t0, GCR_CL_COHERENCE_OFS(v1)
-       ehb
-
        /* Jump to kseg0 */
        PTR_LA  t0, 1f
        jr      t0
         nop
 
        /*
-        * We're up, cached & coherent. Perform any further required core-level
-        * initialisation.
+        * We're up, cached & coherent. Perform any EVA initialization necessary
+        * before we access memory.
         */
-1:     jal     mips_cps_core_init
+1:     eva_init
+
+       /* Retrieve boot configuration pointers */
+       jal     mips_cps_get_bootcfg
+        nop
+
+       /* Skip core-level init if we started up coherent */
+       bnez    s7, 1f
         nop
 
-       /* Do any EVA initialization if necessary */
-       eva_init
+       /* Perform any further required core-level initialisation */
+       jal     mips_cps_core_init
+        nop
 
        /*
         * Boot any other VPEs within this core that should be online, and
         * deactivate this VPE if it should be offline.
         */
+       move    a1, t9
        jal     mips_cps_boot_vpes
-        nop
+        move   a0, v0
 
        /* Off we go! */
-       PTR_L   t1, VPEBOOTCFG_PC(v0)
-       PTR_L   gp, VPEBOOTCFG_GP(v0)
-       PTR_L   sp, VPEBOOTCFG_SP(v0)
+1:     PTR_L   t1, VPEBOOTCFG_PC(v1)
+       PTR_L   gp, VPEBOOTCFG_GP(v1)
+       PTR_L   sp, VPEBOOTCFG_SP(v1)
        jr      t1
         nop
        END(mips_cps_core_entry)
@@ -245,7 +224,6 @@ LEAF(excep_intex)
 
 .org 0x480
 LEAF(excep_ejtag)
-       DUMP_EXCEP("EJTAG")
        PTR_LA  k0, ejtag_debug_handler
        jr      k0
         nop
@@ -323,22 +301,35 @@ LEAF(mips_cps_core_init)
         nop
        END(mips_cps_core_init)
 
-LEAF(mips_cps_boot_vpes)
-       /* Retrieve CM base address */
-       PTR_LA  t0, mips_cm_base
-       PTR_L   t0, 0(t0)
-
+/**
+ * mips_cps_get_bootcfg() - retrieve boot configuration pointers
+ *
+ * Returns: pointer to struct core_boot_config in v0, pointer to
+ *          struct vpe_boot_config in v1, VPE ID in t9
+ */
+LEAF(mips_cps_get_bootcfg)
        /* Calculate a pointer to this cores struct core_boot_config */
+       cmgcrb  t0
        lw      t0, GCR_CL_ID_OFS(t0)
        li      t1, COREBOOTCFG_SIZE
        mul     t0, t0, t1
        PTR_LA  t1, mips_cps_core_bootcfg
        PTR_L   t1, 0(t1)
-       PTR_ADDU t0, t0, t1
+       PTR_ADDU v0, t0, t1
 
        /* Calculate this VPEs ID. If the core doesn't support MT use 0 */
        li      t9, 0
-#ifdef CONFIG_MIPS_MT_SMP
+#if defined(CONFIG_CPU_MIPSR6)
+       has_vp  ta2, 1f
+
+       /*
+        * Assume non-contiguous numbering. Perhaps some day we'll need
+        * to handle contiguous VP numbering, but no such systems yet
+        * exist.
+        */
+       mfc0    t9, $3, 1
+       andi    t9, t9, 0xff
+#elif defined(CONFIG_MIPS_MT_SMP)
        has_mt  ta2, 1f
 
        /* Find the number of VPEs present in the core */
@@ -362,22 +353,47 @@ LEAF(mips_cps_boot_vpes)
 
 1:     /* Calculate a pointer to this VPEs struct vpe_boot_config */
        li      t1, VPEBOOTCFG_SIZE
-       mul     v0, t9, t1
-       PTR_L   ta3, COREBOOTCFG_VPECONFIG(t0)
-       PTR_ADDU v0, v0, ta3
-
-#ifdef CONFIG_MIPS_MT_SMP
+       mul     v1, t9, t1
+       PTR_L   ta3, COREBOOTCFG_VPECONFIG(v0)
+       PTR_ADDU v1, v1, ta3
 
-       /* If the core doesn't support MT then return */
-       bnez    ta2, 1f
-        nop
        jr      ra
         nop
+       END(mips_cps_get_bootcfg)
+
+LEAF(mips_cps_boot_vpes)
+       PTR_L   ta2, COREBOOTCFG_VPEMASK(a0)
+       PTR_L   ta3, COREBOOTCFG_VPECONFIG(a0)
+
+#if defined(CONFIG_CPU_MIPSR6)
+
+       has_vp  t0, 5f
+
+       /* Find base address of CPC */
+       cmgcrb  t3
+       PTR_L   t1, GCR_CPC_BASE_OFS(t3)
+       PTR_LI  t2, ~0x7fff
+       and     t1, t1, t2
+       PTR_LI  t2, UNCAC_BASE
+       PTR_ADD t1, t1, t2
+
+       /* Start any other VPs that ought to be running */
+       PTR_S   ta2, CPC_CL_VC_RUN_OFS(t1)
+
+       /* Ensure this VP stops running if it shouldn't be */
+       not     ta2
+       PTR_S   ta2, CPC_CL_VC_STOP_OFS(t1)
+       ehb
+
+#elif defined(CONFIG_MIPS_MT)
 
        .set    push
        .set    mt
 
-1:     /* Enter VPE configuration state */
+       /* If the core doesn't support MT then return */
+       has_mt  t0, 5f
+
+       /* Enter VPE configuration state */
        dvpe
        PTR_LA  t1, 1f
        jr.hb   t1
@@ -388,7 +404,6 @@ LEAF(mips_cps_boot_vpes)
        ehb
 
        /* Loop through each VPE */
-       PTR_L   ta2, COREBOOTCFG_VPEMASK(t0)
        move    t8, ta2
        li      ta1, 0
 
@@ -465,7 +480,7 @@ LEAF(mips_cps_boot_vpes)
 
        /* Check whether this VPE is meant to be running */
        li      t0, 1
-       sll     t0, t0, t9
+       sll     t0, t0, a1
        and     t0, t0, t8
        bnez    t0, 2f
         nop
@@ -482,10 +497,84 @@ LEAF(mips_cps_boot_vpes)
 #endif /* CONFIG_MIPS_MT_SMP */
 
        /* Return */
-       jr      ra
+5:     jr      ra
         nop
        END(mips_cps_boot_vpes)
 
+LEAF(mips_cps_cache_init)
+       /*
+        * Clear the bits used to index the caches. Note that the architecture
+        * dictates that writing to any of TagLo or TagHi selects 0 or 2 should
+        * be valid for all MIPS32 CPUs, even those for which said writes are
+        * unnecessary.
+        */
+       mtc0    zero, CP0_TAGLO, 0
+       mtc0    zero, CP0_TAGHI, 0
+       mtc0    zero, CP0_TAGLO, 2
+       mtc0    zero, CP0_TAGHI, 2
+       ehb
+
+       /* Primary cache configuration is indicated by Config1 */
+       mfc0    v0, CP0_CONFIG, 1
+
+       /* Detect I-cache line size */
+       _EXT    t0, v0, MIPS_CONF1_IL_SHF, MIPS_CONF1_IL_SZ
+       beqz    t0, icache_done
+        li     t1, 2
+       sllv    t0, t1, t0
+
+       /* Detect I-cache size */
+       _EXT    t1, v0, MIPS_CONF1_IS_SHF, MIPS_CONF1_IS_SZ
+       xori    t2, t1, 0x7
+       beqz    t2, 1f
+        li     t3, 32
+       addiu   t1, t1, 1
+       sllv    t1, t3, t1
+1:     /* At this point t1 == I-cache sets per way */
+       _EXT    t2, v0, MIPS_CONF1_IA_SHF, MIPS_CONF1_IA_SZ
+       addiu   t2, t2, 1
+       mul     t1, t1, t0
+       mul     t1, t1, t2
+
+       li      a0, CKSEG0
+       PTR_ADD a1, a0, t1
+1:     cache   Index_Store_Tag_I, 0(a0)
+       PTR_ADD a0, a0, t0
+       bne     a0, a1, 1b
+        nop
+icache_done:
+
+       /* Detect D-cache line size */
+       _EXT    t0, v0, MIPS_CONF1_DL_SHF, MIPS_CONF1_DL_SZ
+       beqz    t0, dcache_done
+        li     t1, 2
+       sllv    t0, t1, t0
+
+       /* Detect D-cache size */
+       _EXT    t1, v0, MIPS_CONF1_DS_SHF, MIPS_CONF1_DS_SZ
+       xori    t2, t1, 0x7
+       beqz    t2, 1f
+        li     t3, 32
+       addiu   t1, t1, 1
+       sllv    t1, t3, t1
+1:     /* At this point t1 == D-cache sets per way */
+       _EXT    t2, v0, MIPS_CONF1_DA_SHF, MIPS_CONF1_DA_SZ
+       addiu   t2, t2, 1
+       mul     t1, t1, t0
+       mul     t1, t1, t2
+
+       li      a0, CKSEG0
+       PTR_ADDU a1, a0, t1
+       PTR_SUBU a1, a1, t0
+1:     cache   Index_Store_Tag_D, 0(a0)
+       bne     a0, a1, 1b
+        PTR_ADD a0, a0, t0
+dcache_done:
+
+       jr      ra
+        nop
+       END(mips_cps_cache_init)
+
 #if defined(CONFIG_MIPS_CPS_PM) && defined(CONFIG_CPU_PM)
 
        /* Calculate a pointer to this CPUs struct mips_static_suspend_state */
index 6b90644..e38442d 100644 (file)
@@ -99,6 +99,161 @@ static inline void cpu_set_fpu_fcsr_mask(struct cpuinfo_mips *c)
 }
 
 /*
+ * Determine the IEEE 754 NaN encodings and ABS.fmt/NEG.fmt execution modes
+ * supported by FPU hardware.
+ */
+static void cpu_set_fpu_2008(struct cpuinfo_mips *c)
+{
+       if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 |
+                           MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 |
+                           MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) {
+               unsigned long sr, fir, fcsr, fcsr0, fcsr1;
+
+               sr = read_c0_status();
+               __enable_fpu(FPU_AS_IS);
+
+               fir = read_32bit_cp1_register(CP1_REVISION);
+               if (fir & MIPS_FPIR_HAS2008) {
+                       fcsr = read_32bit_cp1_register(CP1_STATUS);
+
+                       fcsr0 = fcsr & ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008);
+                       write_32bit_cp1_register(CP1_STATUS, fcsr0);
+                       fcsr0 = read_32bit_cp1_register(CP1_STATUS);
+
+                       fcsr1 = fcsr | FPU_CSR_ABS2008 | FPU_CSR_NAN2008;
+                       write_32bit_cp1_register(CP1_STATUS, fcsr1);
+                       fcsr1 = read_32bit_cp1_register(CP1_STATUS);
+
+                       write_32bit_cp1_register(CP1_STATUS, fcsr);
+
+                       if (!(fcsr0 & FPU_CSR_NAN2008))
+                               c->options |= MIPS_CPU_NAN_LEGACY;
+                       if (fcsr1 & FPU_CSR_NAN2008)
+                               c->options |= MIPS_CPU_NAN_2008;
+
+                       if ((fcsr0 ^ fcsr1) & FPU_CSR_ABS2008)
+                               c->fpu_msk31 &= ~FPU_CSR_ABS2008;
+                       else
+                               c->fpu_csr31 |= fcsr & FPU_CSR_ABS2008;
+
+                       if ((fcsr0 ^ fcsr1) & FPU_CSR_NAN2008)
+                               c->fpu_msk31 &= ~FPU_CSR_NAN2008;
+                       else
+                               c->fpu_csr31 |= fcsr & FPU_CSR_NAN2008;
+               } else {
+                       c->options |= MIPS_CPU_NAN_LEGACY;
+               }
+
+               write_c0_status(sr);
+       } else {
+               c->options |= MIPS_CPU_NAN_LEGACY;
+       }
+}
+
+/*
+ * IEEE 754 conformance mode to use.  Affects the NaN encoding and the
+ * ABS.fmt/NEG.fmt execution mode.
+ */
+static enum { STRICT, LEGACY, STD2008, RELAXED } ieee754 = STRICT;
+
+/*
+ * Set the IEEE 754 NaN encodings and the ABS.fmt/NEG.fmt execution modes
+ * to support by the FPU emulator according to the IEEE 754 conformance
+ * mode selected.  Note that "relaxed" straps the emulator so that it
+ * allows 2008-NaN binaries even for legacy processors.
+ */
+static void cpu_set_nofpu_2008(struct cpuinfo_mips *c)
+{
+       c->options &= ~(MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY);
+       c->fpu_csr31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008);
+       c->fpu_msk31 &= ~(FPU_CSR_ABS2008 | FPU_CSR_NAN2008);
+
+       switch (ieee754) {
+       case STRICT:
+               if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 |
+                                   MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 |
+                                   MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)) {
+                       c->options |= MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY;
+               } else {
+                       c->options |= MIPS_CPU_NAN_LEGACY;
+                       c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008;
+               }
+               break;
+       case LEGACY:
+               c->options |= MIPS_CPU_NAN_LEGACY;
+               c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008;
+               break;
+       case STD2008:
+               c->options |= MIPS_CPU_NAN_2008;
+               c->fpu_csr31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008;
+               c->fpu_msk31 |= FPU_CSR_ABS2008 | FPU_CSR_NAN2008;
+               break;
+       case RELAXED:
+               c->options |= MIPS_CPU_NAN_2008 | MIPS_CPU_NAN_LEGACY;
+               break;
+       }
+}
+
+/*
+ * Override the IEEE 754 NaN encoding and ABS.fmt/NEG.fmt execution mode
+ * according to the "ieee754=" parameter.
+ */
+static void cpu_set_nan_2008(struct cpuinfo_mips *c)
+{
+       switch (ieee754) {
+       case STRICT:
+               mips_use_nan_legacy = !!cpu_has_nan_legacy;
+               mips_use_nan_2008 = !!cpu_has_nan_2008;
+               break;
+       case LEGACY:
+               mips_use_nan_legacy = !!cpu_has_nan_legacy;
+               mips_use_nan_2008 = !cpu_has_nan_legacy;
+               break;
+       case STD2008:
+               mips_use_nan_legacy = !cpu_has_nan_2008;
+               mips_use_nan_2008 = !!cpu_has_nan_2008;
+               break;
+       case RELAXED:
+               mips_use_nan_legacy = true;
+               mips_use_nan_2008 = true;
+               break;
+       }
+}
+
+/*
+ * IEEE 754 NaN encoding and ABS.fmt/NEG.fmt execution mode override
+ * settings:
+ *
+ * strict:  accept binaries that request a NaN encoding supported by the FPU
+ * legacy:  only accept legacy-NaN binaries
+ * 2008:    only accept 2008-NaN binaries
+ * relaxed: accept any binaries regardless of whether supported by the FPU
+ */
+static int __init ieee754_setup(char *s)
+{
+       if (!s)
+               return -1;
+       else if (!strcmp(s, "strict"))
+               ieee754 = STRICT;
+       else if (!strcmp(s, "legacy"))
+               ieee754 = LEGACY;
+       else if (!strcmp(s, "2008"))
+               ieee754 = STD2008;
+       else if (!strcmp(s, "relaxed"))
+               ieee754 = RELAXED;
+       else
+               return -1;
+
+       if (!(boot_cpu_data.options & MIPS_CPU_FPU))
+               cpu_set_nofpu_2008(&boot_cpu_data);
+       cpu_set_nan_2008(&boot_cpu_data);
+
+       return 0;
+}
+
+early_param("ieee754", ieee754_setup);
+
+/*
  * Set the FIR feature flags for the FPU emulator.
  */
 static void cpu_set_nofpu_id(struct cpuinfo_mips *c)
@@ -113,6 +268,8 @@ static void cpu_set_nofpu_id(struct cpuinfo_mips *c)
        if (c->isa_level & (MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 |
                            MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6))
                value |= MIPS_FPIR_F64 | MIPS_FPIR_L | MIPS_FPIR_W;
+       if (c->options & MIPS_CPU_NAN_2008)
+               value |= MIPS_FPIR_HAS2008;
        c->fpu_id = value;
 }
 
@@ -137,6 +294,8 @@ static void cpu_set_fpu_opts(struct cpuinfo_mips *c)
        }
 
        cpu_set_fpu_fcsr_mask(c);
+       cpu_set_fpu_2008(c);
+       cpu_set_nan_2008(c);
 }
 
 /*
@@ -147,6 +306,8 @@ static void cpu_set_nofpu_opts(struct cpuinfo_mips *c)
        c->options &= ~MIPS_CPU_FPU;
        c->fpu_msk31 = mips_nofpu_msk31;
 
+       cpu_set_nofpu_2008(c);
+       cpu_set_nan_2008(c);
        cpu_set_nofpu_id(c);
 }
 
@@ -635,6 +796,8 @@ static inline unsigned int decode_config5(struct cpuinfo_mips *c)
        if (config5 & MIPS_CONF5_MVH)
                c->options |= MIPS_CPU_XPA;
 #endif
+       if (cpu_has_mips_r6 && (config5 & MIPS_CONF5_VP))
+               c->options |= MIPS_CPU_VP;
 
        return config5 & MIPS_CONF_M;
 }
index 3afffc3..624e15d 100644 (file)
@@ -8,9 +8,18 @@
  * option) any later version.
  */
 
+#include <linux/binfmts.h>
 #include <linux/elf.h>
+#include <linux/export.h>
 #include <linux/sched.h>
 
+#include <asm/cpu-features.h>
+#include <asm/cpu-info.h>
+
+/* Whether to accept legacy-NaN and 2008-NaN user binaries.  */
+bool mips_use_nan_legacy;
+bool mips_use_nan_2008;
+
 /* FPU modes */
 enum {
        FP_FRE,
@@ -68,15 +77,23 @@ static struct mode_req none_req = { true, true, false, true, true };
 int arch_elf_pt_proc(void *_ehdr, void *_phdr, struct file *elf,
                     bool is_interp, struct arch_elf_state *state)
 {
-       struct elf32_hdr *ehdr32 = _ehdr;
+       union {
+               struct elf32_hdr e32;
+               struct elf64_hdr e64;
+       } *ehdr = _ehdr;
        struct elf32_phdr *phdr32 = _phdr;
        struct elf64_phdr *phdr64 = _phdr;
        struct mips_elf_abiflags_v0 abiflags;
+       bool elf32;
+       u32 flags;
        int ret;
 
-       /* Lets see if this is an O32 ELF */
-       if (ehdr32->e_ident[EI_CLASS] == ELFCLASS32) {
-               if (ehdr32->e_flags & EF_MIPS_FP64) {
+       elf32 = ehdr->e32.e_ident[EI_CLASS] == ELFCLASS32;
+       flags = elf32 ? ehdr->e32.e_flags : ehdr->e64.e_flags;
+
+       /* Let's see if this is an O32 ELF */
+       if (elf32) {
+               if (flags & EF_MIPS_FP64) {
                        /*
                         * Set MIPS_ABI_FP_OLD_64 for EF_MIPS_FP64. We will override it
                         * later if needed
@@ -120,13 +137,50 @@ int arch_elf_pt_proc(void *_ehdr, void *_phdr, struct file *elf,
        return 0;
 }
 
-int arch_check_elf(void *_ehdr, bool has_interpreter,
+int arch_check_elf(void *_ehdr, bool has_interpreter, void *_interp_ehdr,
                   struct arch_elf_state *state)
 {
-       struct elf32_hdr *ehdr = _ehdr;
+       union {
+               struct elf32_hdr e32;
+               struct elf64_hdr e64;
+       } *ehdr = _ehdr;
+       union {
+               struct elf32_hdr e32;
+               struct elf64_hdr e64;
+       } *iehdr = _interp_ehdr;
        struct mode_req prog_req, interp_req;
        int fp_abi, interp_fp_abi, abi0, abi1, max_abi;
-       bool is_mips64;
+       bool elf32;
+       u32 flags;
+
+       elf32 = ehdr->e32.e_ident[EI_CLASS] == ELFCLASS32;
+       flags = elf32 ? ehdr->e32.e_flags : ehdr->e64.e_flags;
+
+       /*
+        * Determine the NaN personality, reject the binary if not allowed.
+        * Also ensure that any interpreter matches the executable.
+        */
+       if (flags & EF_MIPS_NAN2008) {
+               if (mips_use_nan_2008)
+                       state->nan_2008 = 1;
+               else
+                       return -ENOEXEC;
+       } else {
+               if (mips_use_nan_legacy)
+                       state->nan_2008 = 0;
+               else
+                       return -ENOEXEC;
+       }
+       if (has_interpreter) {
+               bool ielf32;
+               u32 iflags;
+
+               ielf32 = iehdr->e32.e_ident[EI_CLASS] == ELFCLASS32;
+               iflags = ielf32 ? iehdr->e32.e_flags : iehdr->e64.e_flags;
+
+               if ((flags ^ iflags) & EF_MIPS_NAN2008)
+                       return -ELIBBAD;
+       }
 
        if (!config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT))
                return 0;
@@ -142,21 +196,18 @@ int arch_check_elf(void *_ehdr, bool has_interpreter,
                abi0 = abi1 = fp_abi;
        }
 
-       is_mips64 = (ehdr->e_ident[EI_CLASS] == ELFCLASS64) ||
-                   (ehdr->e_flags & EF_MIPS_ABI2);
+       if (elf32 && !(flags & EF_MIPS_ABI2)) {
+               /* Default to a mode capable of running code expecting FR=0 */
+               state->overall_fp_mode = cpu_has_mips_r6 ? FP_FRE : FP_FR0;
 
-       if (is_mips64) {
+               /* Allow all ABIs we know about */
+               max_abi = MIPS_ABI_FP_64A;
+       } else {
                /* MIPS64 code always uses FR=1, thus the default is easy */
                state->overall_fp_mode = FP_FR1;
 
                /* Disallow access to the various FPXX & FP64 ABIs */
                max_abi = MIPS_ABI_FP_SOFT;
-       } else {
-               /* Default to a mode capable of running code expecting FR=0 */
-               state->overall_fp_mode = cpu_has_mips_r6 ? FP_FRE : FP_FR0;
-
-               /* Allow all ABIs we know about */
-               max_abi = MIPS_ABI_FP_64A;
        }
 
        if ((abi0 > max_abi && abi0 != MIPS_ABI_FP_UNKNOWN) ||
@@ -254,3 +305,91 @@ void mips_set_personality_fp(struct arch_elf_state *state)
                BUG();
        }
 }
+
+/*
+ * Select the IEEE 754 NaN encoding and ABS.fmt/NEG.fmt execution mode
+ * in FCSR according to the ELF NaN personality.
+ */
+void mips_set_personality_nan(struct arch_elf_state *state)
+{
+       struct cpuinfo_mips *c = &boot_cpu_data;
+       struct task_struct *t = current;
+
+       t->thread.fpu.fcr31 = c->fpu_csr31;
+       switch (state->nan_2008) {
+       case 0:
+               break;
+       case 1:
+               if (!(c->fpu_msk31 & FPU_CSR_NAN2008))
+                       t->thread.fpu.fcr31 |= FPU_CSR_NAN2008;
+               if (!(c->fpu_msk31 & FPU_CSR_ABS2008))
+                       t->thread.fpu.fcr31 |= FPU_CSR_ABS2008;
+               break;
+       default:
+               BUG();
+       }
+}
+
+static int noexec = EXSTACK_DEFAULT;
+
+/*
+ * kernel parameter: noexec=on|off
+ *
+ * Force indicating stack and heap as non-executable or
+ * executable regardless of PT_GNU_STACK entry or CPU XI
+ * (execute inhibit) support. Valid valuess are: on, off.
+ *
+ * noexec=on:  force indicating non-executable
+ *             stack and heap
+ * noexec=off: force indicating executable
+ *             stack and heap
+ *
+ * If this parameter is omitted, stack and heap will be
+ * indicated non-executable or executable as they are
+ * actually set up, which depends on PT_GNU_STACK entry
+ * and possibly other factors (for instance, CPU XI
+ * support).
+ *
+ * NOTE: Using noexec=on on a system without CPU XI
+ * support is not recommended since there is no actual
+ * HW support that provide non-executable stack/heap.
+ * Use only for debugging purposes and not in a
+ * production environment.
+ */
+static int __init noexec_setup(char *str)
+{
+       if (!strcmp(str, "on"))
+               noexec = EXSTACK_DISABLE_X;
+       else if (!strcmp(str, "off"))
+               noexec = EXSTACK_ENABLE_X;
+       else
+               pr_err("Malformed noexec format! noexec=on|off\n");
+
+       return 1;
+}
+__setup("noexec=", noexec_setup);
+
+int mips_elf_read_implies_exec(void *elf_ex, int exstack)
+{
+       switch (noexec) {
+       case EXSTACK_DISABLE_X:
+               return 0;
+       case EXSTACK_ENABLE_X:
+               return 1;
+       default:
+               break;
+       }
+
+       if (exstack != EXSTACK_DISABLE_X) {
+               /* The binary doesn't request a non-executable stack */
+               return 1;
+       }
+
+       if (!cpu_has_rixi) {
+               /* The CPU doesn't support non-executable memory */
+               return 1;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(mips_elf_read_implies_exec);
index 4e4cc5b..462989e 100644 (file)
@@ -94,21 +94,24 @@ NESTED(kernel_entry, 16, sp)                        # kernel entry point
        jr      t0
 0:
 
+#ifdef CONFIG_USE_OF
 #ifdef CONFIG_MIPS_RAW_APPENDED_DTB
-       PTR_LA          t0, __appended_dtb
+       PTR_LA          t2, __appended_dtb
 
 #ifdef CONFIG_CPU_BIG_ENDIAN
        li              t1, 0xd00dfeed
 #else
        li              t1, 0xedfe0dd0
 #endif
-       lw              t2, (t0)
-       bne             t1, t2, not_found
-        nop
+       lw              t0, (t2)
+       beq             t0, t1, dtb_found
+#endif
+       li              t1, -2
+       beq             a0, t1, dtb_found
+       move            t2, a1
 
-       move            a1, t0
-       PTR_LI          a0, -2
-not_found:
+       li              t2, 0
+dtb_found:
 #endif
        PTR_LA          t0, __bss_start         # clear .bss
        LONG_S          zero, (t0)
@@ -123,6 +126,10 @@ not_found:
        LONG_S          a2, fw_arg2
        LONG_S          a3, fw_arg3
 
+#ifdef CONFIG_USE_OF
+       LONG_S          t2, fw_passed_dtb
+#endif
+
        MTC0            zero, CP0_CONTEXT       # clear context register
        PTR_LA          $28, init_thread_union
        /* Set the SP after an empty pt_regs.  */
index 0b29646..50fb625 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/utsname.h>
 #include <linux/personality.h>
 #include <linux/dnotify.h>
-#include <linux/module.h>
 #include <linux/binfmts.h>
 #include <linux/security.h>
 #include <linux/compat.h>
index 1448c1f..36bd476 100644 (file)
@@ -24,7 +24,7 @@ static char *cm2_tr[8] = {
        "0x04", "cpc", "0x06", "0x07"
 };
 
-/* CM3 Tag ECC transation type */
+/* CM3 Tag ECC transaction type */
 static char *cm3_tr[16] = {
        [0x0] = "ReqNoData",
        [0x1] = "0x1",
@@ -265,15 +265,34 @@ void mips_cm_lock_other(unsigned int core, unsigned int vp)
        u32 val;
 
        preempt_disable();
-       curr_core = current_cpu_data.core;
-       spin_lock_irqsave(&per_cpu(cm_core_lock, curr_core),
-                         per_cpu(cm_core_lock_flags, curr_core));
 
        if (mips_cm_revision() >= CM_REV_CM3) {
                val = core << CM3_GCR_Cx_OTHER_CORE_SHF;
                val |= vp << CM3_GCR_Cx_OTHER_VP_SHF;
+
+               /*
+                * We need to disable interrupts in SMP systems in order to
+                * ensure that we don't interrupt the caller with code which
+                * may modify the redirect register. We do so here in a
+                * slightly obscure way by using a spin lock, since this has
+                * the neat property of also catching any nested uses of
+                * mips_cm_lock_other() leading to a deadlock or a nice warning
+                * with lockdep enabled.
+                */
+               spin_lock_irqsave(this_cpu_ptr(&cm_core_lock),
+                                 *this_cpu_ptr(&cm_core_lock_flags));
        } else {
-               BUG_ON(vp != 0);
+               WARN_ON(vp != 0);
+
+               /*
+                * We only have a GCR_CL_OTHER per core in systems with
+                * CM 2.5 & older, so have to ensure other VP(E)s don't
+                * race with us.
+                */
+               curr_core = current_cpu_data.core;
+               spin_lock_irqsave(&per_cpu(cm_core_lock, curr_core),
+                                 per_cpu(cm_core_lock_flags, curr_core));
+
                val = core << CM_GCR_Cx_OTHER_CORENUM_SHF;
        }
 
@@ -288,10 +307,17 @@ void mips_cm_lock_other(unsigned int core, unsigned int vp)
 
 void mips_cm_unlock_other(void)
 {
-       unsigned curr_core = current_cpu_data.core;
+       unsigned int curr_core;
+
+       if (mips_cm_revision() < CM_REV_CM3) {
+               curr_core = current_cpu_data.core;
+               spin_unlock_irqrestore(&per_cpu(cm_core_lock, curr_core),
+                                      per_cpu(cm_core_lock_flags, curr_core));
+       } else {
+               spin_unlock_irqrestore(this_cpu_ptr(&cm_core_lock),
+                                      *this_cpu_ptr(&cm_core_lock_flags));
+       }
 
-       spin_unlock_irqrestore(&per_cpu(cm_core_lock, curr_core),
-                              per_cpu(cm_core_lock_flags, curr_core));
        preempt_enable();
 }
 
index 566b8d2..3491ee0 100644 (file)
@@ -10,6 +10,8 @@
 
 #include <linux/errno.h>
 #include <linux/percpu.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/spinlock.h>
 
 #include <asm/mips-cm.h>
@@ -21,6 +23,22 @@ static DEFINE_PER_CPU_ALIGNED(spinlock_t, cpc_core_lock);
 
 static DEFINE_PER_CPU_ALIGNED(unsigned long, cpc_core_lock_flags);
 
+phys_addr_t __weak mips_cpc_default_phys_base(void)
+{
+       struct device_node *cpc_node;
+       struct resource res;
+       int err;
+
+       cpc_node = of_find_compatible_node(of_root, NULL, "mti,mips-cpc");
+       if (cpc_node) {
+               err = of_address_to_resource(cpc_node, 0, &res);
+               if (!err)
+                       return res.start;
+       }
+
+       return 0;
+}
+
 /**
  * mips_cpc_phys_base - retrieve the physical base address of the CPC
  *
@@ -43,8 +61,12 @@ static phys_addr_t mips_cpc_phys_base(void)
        if (cpc_base & CM_GCR_CPC_BASE_CPCEN_MSK)
                return cpc_base & CM_GCR_CPC_BASE_CPCBASE_MSK;
 
-       /* Otherwise, give it the default address & enable it */
+       /* Otherwise, use the default address */
        cpc_base = mips_cpc_default_phys_base();
+       if (!cpc_base)
+               return cpc_base;
+
+       /* Enable the CPC, mapped at the default address */
        write_gcr_cpc_base(cpc_base | CM_GCR_CPC_BASE_CPCEN_MSK);
        return cpc_base;
 }
index e338406..d7fbcc5 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/debugfs.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/ptrace.h>
 #include <linux/seq_file.h>
 
@@ -283,7 +282,7 @@ static int jr_func(struct pt_regs *regs, u32 ir)
                err = mipsr6_emul(regs, nir);
                if (err > 0) {
                        regs->cp0_epc = nepc;
-                       err = mips_dsemul(regs, nir, cepc);
+                       err = mips_dsemul(regs, nir, epc, cepc);
                        if (err == SIGILL)
                                err = SIGEMT;
                        MIPS_R2_STATS(dsemul);
@@ -900,7 +899,7 @@ static inline int mipsr2_find_op_func(struct pt_regs *regs, u32 inst,
  * mipsr2_decoder: Decode and emulate a MIPS R2 instruction
  * @regs: Process register set
  * @inst: Instruction to decode and emulate
- * @fcr31: Floating Point Control and Status Register returned
+ * @fcr31: Floating Point Control and Status Register Cause bits returned
  */
 int mipsr2_decoder(struct pt_regs *regs, u32 inst, unsigned long *fcr31)
 {
@@ -941,42 +940,42 @@ repeat:
                switch (rt) {
                case tgei_op:
                        if ((long)regs->regs[rs] >= MIPSInst_SIMM(inst))
-                               do_trap_or_bp(regs, 0, "TGEI");
+                               do_trap_or_bp(regs, 0, 0, "TGEI");
 
                        MIPS_R2_STATS(traps);
 
                        break;
                case tgeiu_op:
                        if (regs->regs[rs] >= MIPSInst_UIMM(inst))
-                               do_trap_or_bp(regs, 0, "TGEIU");
+                               do_trap_or_bp(regs, 0, 0, "TGEIU");
 
                        MIPS_R2_STATS(traps);
 
                        break;
                case tlti_op:
                        if ((long)regs->regs[rs] < MIPSInst_SIMM(inst))
-                               do_trap_or_bp(regs, 0, "TLTI");
+                               do_trap_or_bp(regs, 0, 0, "TLTI");
 
                        MIPS_R2_STATS(traps);
 
                        break;
                case tltiu_op:
                        if (regs->regs[rs] < MIPSInst_UIMM(inst))
-                               do_trap_or_bp(regs, 0, "TLTIU");
+                               do_trap_or_bp(regs, 0, 0, "TLTIU");
 
                        MIPS_R2_STATS(traps);
 
                        break;
                case teqi_op:
                        if (regs->regs[rs] == MIPSInst_SIMM(inst))
-                               do_trap_or_bp(regs, 0, "TEQI");
+                               do_trap_or_bp(regs, 0, 0, "TEQI");
 
                        MIPS_R2_STATS(traps);
 
                        break;
                case tnei_op:
                        if (regs->regs[rs] != MIPSInst_SIMM(inst))
-                               do_trap_or_bp(regs, 0, "TNEI");
+                               do_trap_or_bp(regs, 0, 0, "TNEI");
 
                        MIPS_R2_STATS(traps);
 
@@ -1033,7 +1032,7 @@ repeat:
                        if (nir) {
                                err = mipsr6_emul(regs, nir);
                                if (err > 0) {
-                                       err = mips_dsemul(regs, nir, cpc);
+                                       err = mips_dsemul(regs, nir, epc, cpc);
                                        if (err == SIGILL)
                                                err = SIGEMT;
                                        MIPS_R2_STATS(dsemul);
@@ -1082,7 +1081,7 @@ repeat:
                        if (nir) {
                                err = mipsr6_emul(regs, nir);
                                if (err > 0) {
-                                       err = mips_dsemul(regs, nir, cpc);
+                                       err = mips_dsemul(regs, nir, epc, cpc);
                                        if (err == SIGILL)
                                                err = SIGEMT;
                                        MIPS_R2_STATS(dsemul);
@@ -1097,10 +1096,20 @@ repeat:
                }
                break;
 
-       case beql_op:
-       case bnel_op:
        case blezl_op:
        case bgtzl_op:
+               /*
+                * For BLEZL and BGTZL, rt field must be set to 0. If this
+                * is not the case, this may be an encoding of a MIPS R6
+                * instruction, so return to CPU execution if this occurs
+                */
+               if (MIPSInst_RT(inst)) {
+                       err = SIGILL;
+                       break;
+               }
+               /* fall through */
+       case beql_op:
+       case bnel_op:
                if (delay_slot(regs)) {
                        err = SIGILL;
                        break;
@@ -1149,7 +1158,7 @@ repeat:
                if (nir) {
                        err = mipsr6_emul(regs, nir);
                        if (err > 0) {
-                               err = mips_dsemul(regs, nir, cpc);
+                               err = mips_dsemul(regs, nir, epc, cpc);
                                if (err == SIGILL)
                                        err = SIGEMT;
                                MIPS_R2_STATS(dsemul);
@@ -1173,13 +1182,13 @@ fpu_emul:
 
                err = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 0,
                                               &fault_addr);
-               *fcr31 = current->thread.fpu.fcr31;
 
                /*
-                * We can't allow the emulated instruction to leave any of
-                * the cause bits set in $fcr31.
+                * We can't allow the emulated instruction to leave any
+                * enabled Cause bits set in $fcr31.
                 */
-               current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
+               *fcr31 = res = mask_fcr31_x(current->thread.fpu.fcr31);
+               current->thread.fpu.fcr31 &= ~res;
 
                /*
                 * this is a tricky issue - lose_fpu() uses LL/SC atomics
@@ -2204,7 +2213,7 @@ fpu_emul:
        }
 
        /*
-        * Lets not return to userland just yet. It's constly and
+        * Let's not return to userland just yet. It's costly and
         * it's likely we have more R2 instructions to emulate
         */
        if (!err && (pass++ < MIPS_R2_EMUL_TOTAL_PASS)) {
@@ -2330,6 +2339,8 @@ static int mipsr2_stats_clear_show(struct seq_file *s, void *unused)
        __this_cpu_write((mipsr2bremustats).bgezl, 0);
        __this_cpu_write((mipsr2bremustats).bltzll, 0);
        __this_cpu_write((mipsr2bremustats).bgezll, 0);
+       __this_cpu_write((mipsr2bremustats).bltzall, 0);
+       __this_cpu_write((mipsr2bremustats).bgezall, 0);
        __this_cpu_write((mipsr2bremustats).bltzal, 0);
        __this_cpu_write((mipsr2bremustats).bgezal, 0);
        __this_cpu_write((mipsr2bremustats).beql, 0);
index d7b8dd4..9bc1191 100644 (file)
@@ -530,7 +530,7 @@ static void mipspmu_enable(struct pmu *pmu)
 
 /*
  * MIPS performance counters can be per-TC. The control registers can
- * not be directly accessed accross CPUs. Hence if we want to do global
+ * not be directly accessed across CPUs. Hence if we want to do global
  * control, we need cross CPU calls. on_each_cpu() can help us, but we
  * can not make sure this function is called with interrupts enabled. So
  * here we pause local counters and then grab a rwlock and leave the
index 0b3e58a..a3b6020 100644 (file)
@@ -223,11 +223,18 @@ static void __init cps_gen_cache_routine(u32 **pp, struct uasm_label **pl,
        uasm_build_label(pl, *pp, lbl);
 
        /* Generate the cache ops */
-       for (i = 0; i < unroll_lines; i++)
-               uasm_i_cache(pp, op, i * cache->linesz, t0);
+       for (i = 0; i < unroll_lines; i++) {
+               if (cpu_has_mips_r6) {
+                       uasm_i_cache(pp, op, 0, t0);
+                       uasm_i_addiu(pp, t0, t0, cache->linesz);
+               } else {
+                       uasm_i_cache(pp, op, i * cache->linesz, t0);
+               }
+       }
 
-       /* Update the base address */
-       uasm_i_addiu(pp, t0, t0, unroll_lines * cache->linesz);
+       if (!cpu_has_mips_r6)
+               /* Update the base address */
+               uasm_i_addiu(pp, t0, t0, unroll_lines * cache->linesz);
 
        /* Loop if we haven't reached the end address yet */
        uasm_il_bne(pp, pr, t0, t1, lbl);
@@ -264,14 +271,9 @@ static int __init cps_gen_flush_fsb(u32 **pp, struct uasm_label **pl,
                /* On older ones it's unavailable */
                return -1;
 
-       /* CPUs which do not require the workaround */
-       case CPU_P5600:
-       case CPU_I6400:
-               return 0;
-
        default:
-               WARN_ONCE(1, "pm-cps: FSB flush unsupported for this CPU\n");
-               return -1;
+               /* Assume that the CPU does not need this workaround */
+               return 0;
        }
 
        /*
@@ -471,7 +473,7 @@ static void * __init cps_gen_entry_code(unsigned cpu, enum cps_pm_state state)
        /*
         * Disable all but self interventions. The load from COHCTL is defined
         * by the interAptiv & proAptiv SUMs as ensuring that the operation
-        * resulting from the preceeding store is complete.
+        * resulting from the preceding store is complete.
         */
        uasm_i_addiu(&p, t0, zero, 1 << cpu_data[cpu].core);
        uasm_i_sw(&p, t0, 0, r_pcohctl);
index fcbc4e5..fe61ce7 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/asm.h>
 #include <asm/bootinfo.h>
 #include <asm/cpu.h>
+#include <asm/dsemul.h>
 #include <asm/dsp.h>
 #include <asm/fpu.h>
 #include <asm/irq.h>
@@ -64,22 +65,23 @@ void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
        status = regs->cp0_status & ~(ST0_CU0|ST0_CU1|ST0_FR|KU_MASK);
        status |= KU_USER;
        regs->cp0_status = status;
+       lose_fpu(0);
+       clear_thread_flag(TIF_MSA_CTX_LIVE);
        clear_used_math();
-       clear_fpu_owner();
+       atomic_set(&current->thread.bd_emu_frame, BD_EMUFRAME_NONE);
        init_dsp();
-       clear_thread_flag(TIF_USEDMSA);
-       clear_thread_flag(TIF_MSA_CTX_LIVE);
-       disable_msa();
        regs->cp0_epc = pc;
        regs->regs[29] = sp;
 }
 
-void exit_thread(void)
-{
-}
-
-void flush_thread(void)
+void exit_thread(struct task_struct *tsk)
 {
+       /*
+        * User threads may have allocated a delay slot emulation frame.
+        * If so, clean up that allocation.
+        */
+       if (!(current->flags & PF_KTHREAD))
+               dsemul_thread_cleanup(tsk);
 }
 
 int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
@@ -168,6 +170,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
        clear_tsk_thread_flag(p, TIF_FPUBOUND);
 #endif /* CONFIG_MIPS_MT_FPAFF */
 
+       atomic_set(&p->thread.bd_emu_frame, BD_EMUFRAME_NONE);
+
        if (clone_flags & CLONE_SETTLS)
                ti->tp_value = regs->regs[7];
 
@@ -708,7 +712,7 @@ int mips_set_process_fp_mode(struct task_struct *task, unsigned int value)
         * allows us to only worry about whether an FP mode switch is in
         * progress when FP is first used in a tasks time slice. Pretty much all
         * of the mode switch overhead can thus be confined to cases where mode
-        * switches are actually occuring. That is, to here. However for the
+        * switches are actually occurring. That is, to here. However for the
         * thread performing the mode switch it may take a while...
         */
        if (num_online_cpus() > 1) {
index c3d2d2c..0f0030e 100644 (file)
@@ -79,16 +79,15 @@ void ptrace_disable(struct task_struct *child)
 }
 
 /*
- * Poke at FCSR according to its mask.  Don't set the cause bits as
- * this is currently not handled correctly in FP context restoration
- * and will cause an oops if a corresponding enable bit is set.
+ * Poke at FCSR according to its mask.  Set the Cause bits even
+ * if a corresponding Enable bit is set.  This will be noticed at
+ * the time the thread is switched to and SIGFPE thrown accordingly.
  */
 static void ptrace_setfcr31(struct task_struct *child, u32 value)
 {
        u32 fcr31;
        u32 mask;
 
-       value &= ~FPU_CSR_ALL_X;
        fcr31 = child->thread.fpu.fcr31;
        mask = boot_cpu_data.fpu_msk31;
        child->thread.fpu.fcr31 = (value & ~mask) | (fcr31 & mask);
index 4f9f1ae..34fd37e 100644 (file)
@@ -597,6 +597,46 @@ static int __init early_parse_mem(char *p)
 }
 early_param("mem", early_parse_mem);
 
+static int __init early_parse_memmap(char *p)
+{
+       char *oldp;
+       u64 start_at, mem_size;
+
+       if (!p)
+               return -EINVAL;
+
+       if (!strncmp(p, "exactmap", 8)) {
+               pr_err("\"memmap=exactmap\" invalid on MIPS\n");
+               return 0;
+       }
+
+       oldp = p;
+       mem_size = memparse(p, &p);
+       if (p == oldp)
+               return -EINVAL;
+
+       if (*p == '@') {
+               start_at = memparse(p+1, &p);
+               add_memory_region(start_at, mem_size, BOOT_MEM_RAM);
+       } else if (*p == '#') {
+               pr_err("\"memmap=nn#ss\" (force ACPI data) invalid on MIPS\n");
+               return -EINVAL;
+       } else if (*p == '$') {
+               start_at = memparse(p+1, &p);
+               add_memory_region(start_at, mem_size, BOOT_MEM_RESERVED);
+       } else {
+               pr_err("\"memmap\" invalid format!\n");
+               return -EINVAL;
+       }
+
+       if (*p == '\0') {
+               usermem = 1;
+               return 0;
+       } else
+               return -EINVAL;
+}
+early_param("memmap", early_parse_memmap);
+
 #ifdef CONFIG_PROC_VMCORE
 unsigned long setup_elfcorehdr, setup_elfcorehdr_size;
 static int __init early_parse_elfcorehdr(char *p)
@@ -857,6 +897,7 @@ static inline void prefill_possible_map(void) {}
 void __init setup_arch(char **cmdline_p)
 {
        cpu_probe();
+       mips_cm_probe();
        prom_init();
 
        setup_early_fdc_console();
@@ -886,6 +927,10 @@ void __init setup_arch(char **cmdline_p)
 unsigned long kernelsp[NR_CPUS];
 unsigned long fw_arg0, fw_arg1, fw_arg2, fw_arg3;
 
+#ifdef CONFIG_USE_OF
+unsigned long fw_passed_dtb;
+#endif
+
 #ifdef CONFIG_DEBUG_FS
 struct dentry *mips_debugfs_dir;
 static int __init debugfs_mips(void)
index 9e35b6b..129be97 100644 (file)
@@ -772,6 +772,14 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
        struct mips_abi *abi = current->thread.abi;
        void *vdso = current->mm->context.vdso;
 
+       /*
+        * If we were emulating a delay slot instruction, exit that frame such
+        * that addresses in the sigframe are as expected for userland and we
+        * don't have a problem if we reuse the thread's frame for an
+        * instruction within the signal handler.
+        */
+       dsemul_thread_rollback(regs);
+
        if (regs->regs[0]) {
                switch(regs->regs[2]) {
                case ERESTART_RESTARTBLOCK:
index e04c805..1b78309 100644 (file)
 #include <asm/time.h>
 #include <asm/uasm.h>
 
+static bool threads_disabled;
 static DECLARE_BITMAP(core_power, NR_CPUS);
 
 struct core_boot_config *mips_cps_core_bootcfg;
 
+static int __init setup_nothreads(char *s)
+{
+       threads_disabled = true;
+       return 0;
+}
+early_param("nothreads", setup_nothreads);
+
 static unsigned core_vpe_count(unsigned core)
 {
        unsigned cfg;
 
-       if (!config_enabled(CONFIG_MIPS_MT_SMP) || !cpu_has_mipsmt)
+       if (threads_disabled)
+               return 1;
+
+       if ((!config_enabled(CONFIG_MIPS_MT_SMP) || !cpu_has_mipsmt)
+               && (!config_enabled(CONFIG_CPU_MIPSR6) || !cpu_has_vp))
                return 1;
 
        mips_cm_lock_other(core, 0);
@@ -47,11 +59,12 @@ static unsigned core_vpe_count(unsigned core)
 static void __init cps_smp_setup(void)
 {
        unsigned int ncores, nvpes, core_vpes;
+       unsigned long core_entry;
        int c, v;
 
        /* Detect & record VPE topology */
        ncores = mips_cm_numcores();
-       pr_info("VPE topology ");
+       pr_info("%s topology ", cpu_has_mips_r6 ? "VP" : "VPE");
        for (c = nvpes = 0; c < ncores; c++) {
                core_vpes = core_vpe_count(c);
                pr_cont("%c%u", c ? ',' : '{', core_vpes);
@@ -62,7 +75,7 @@ static void __init cps_smp_setup(void)
 
                for (v = 0; v < min_t(int, core_vpes, NR_CPUS - nvpes); v++) {
                        cpu_data[nvpes + v].core = c;
-#ifdef CONFIG_MIPS_MT_SMP
+#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_CPU_MIPSR6)
                        cpu_data[nvpes + v].vpe_id = v;
 #endif
                }
@@ -91,6 +104,11 @@ static void __init cps_smp_setup(void)
        /* Make core 0 coherent with everything */
        write_gcr_cl_coherence(0xff);
 
+       if (mips_cm_revision() >= CM_REV_CM3) {
+               core_entry = CKSEG1ADDR((unsigned long)mips_cps_core_entry);
+               write_gcr_bev_base(core_entry);
+       }
+
 #ifdef CONFIG_MIPS_MT_FPAFF
        /* If we have an FPU, enroll ourselves in the FPU-full mask */
        if (cpu_has_fpu)
@@ -122,9 +140,11 @@ static void __init cps_prepare_cpus(unsigned int max_cpus)
 
        /* Warn the user if the CCA prevents multi-core */
        ncores = mips_cm_numcores();
-       if (cca_unsuitable && ncores > 1) {
-               pr_warn("Using only one core due to unsuitable CCA 0x%x\n",
-                       cca);
+       if ((cca_unsuitable || cpu_has_dc_aliases) && ncores > 1) {
+               pr_warn("Using only one core due to %s%s%s\n",
+                       cca_unsuitable ? "unsuitable CCA" : "",
+                       (cca_unsuitable && cpu_has_dc_aliases) ? " & " : "",
+                       cpu_has_dc_aliases ? "dcache aliasing" : "");
 
                for_each_present_cpu(c) {
                        if (cpu_data[c].core)
@@ -210,6 +230,18 @@ static void boot_core(unsigned core)
        if (mips_cpc_present()) {
                /* Reset the core */
                mips_cpc_lock_other(core);
+
+               if (mips_cm_revision() >= CM_REV_CM3) {
+                       /* Run VP0 following the reset */
+                       write_cpc_co_vp_run(0x1);
+
+                       /*
+                        * Ensure that the VP_RUN register is written before the
+                        * core leaves reset.
+                        */
+                       wmb();
+               }
+
                write_cpc_co_cmd(CPC_Cx_CMD_RESET);
 
                timeout = 100;
@@ -247,7 +279,10 @@ static void boot_core(unsigned core)
 
 static void remote_vpe_boot(void *dummy)
 {
-       mips_cps_boot_vpes();
+       unsigned core = current_cpu_data.core;
+       struct core_boot_config *core_cfg = &mips_cps_core_bootcfg[core];
+
+       mips_cps_boot_vpes(core_cfg, cpu_vpe_id(&current_cpu_data));
 }
 
 static void cps_boot_secondary(int cpu, struct task_struct *idle)
@@ -256,6 +291,7 @@ static void cps_boot_secondary(int cpu, struct task_struct *idle)
        unsigned vpe_id = cpu_vpe_id(&cpu_data[cpu]);
        struct core_boot_config *core_cfg = &mips_cps_core_bootcfg[core];
        struct vpe_boot_config *vpe_cfg = &core_cfg->vpe_config[vpe_id];
+       unsigned long core_entry;
        unsigned int remote;
        int err;
 
@@ -273,6 +309,13 @@ static void cps_boot_secondary(int cpu, struct task_struct *idle)
                goto out;
        }
 
+       if (cpu_has_vp) {
+               mips_cm_lock_other(core, vpe_id);
+               core_entry = CKSEG1ADDR((unsigned long)mips_cps_core_entry);
+               write_gcr_co_reset_base(core_entry);
+               mips_cm_unlock_other();
+       }
+
        if (core != current_cpu_data.core) {
                /* Boot a VPE on another powered up core */
                for (remote = 0; remote < NR_CPUS; remote++) {
@@ -290,10 +333,10 @@ static void cps_boot_secondary(int cpu, struct task_struct *idle)
                goto out;
        }
 
-       BUG_ON(!cpu_has_mipsmt);
+       BUG_ON(!cpu_has_mipsmt && !cpu_has_vp);
 
        /* Boot a VPE on this core */
-       mips_cps_boot_vpes();
+       mips_cps_boot_vpes(core_cfg, vpe_id);
 out:
        preempt_enable();
 }
@@ -304,6 +347,17 @@ static void cps_init_secondary(void)
        if (cpu_has_mipsmt)
                dmt();
 
+       if (mips_cm_revision() >= CM_REV_CM3) {
+               unsigned ident = gic_read_local_vp_id();
+
+               /*
+                * Ensure that our calculation of the VP ID matches up with
+                * what the GIC reports, otherwise we'll have configured
+                * interrupts incorrectly.
+                */
+               BUG_ON(ident != mips_cm_vp_id(smp_processor_id()));
+       }
+
        change_c0_status(ST0_IM, STATUSF_IP2 | STATUSF_IP3 | STATUSF_IP4 |
                                 STATUSF_IP5 | STATUSF_IP6 | STATUSF_IP7);
 }
@@ -352,14 +406,16 @@ static enum {
 
 void play_dead(void)
 {
-       unsigned cpu, core;
+       unsigned int cpu, core, vpe_id;
 
        local_irq_disable();
        idle_task_exit();
        cpu = smp_processor_id();
        cpu_death = CPU_DEATH_POWER;
 
-       if (cpu_has_mipsmt) {
+       pr_debug("CPU%d going offline\n", cpu);
+
+       if (cpu_has_mipsmt || cpu_has_vp) {
                core = cpu_data[cpu].core;
 
                /* Look for another online VPE within the core */
@@ -380,10 +436,21 @@ void play_dead(void)
        complete(&cpu_death_chosen);
 
        if (cpu_death == CPU_DEATH_HALT) {
-               /* Halt this TC */
-               write_c0_tchalt(TCHALT_H);
-               instruction_hazard();
+               vpe_id = cpu_vpe_id(&cpu_data[cpu]);
+
+               pr_debug("Halting core %d VP%d\n", core, vpe_id);
+               if (cpu_has_mipsmt) {
+                       /* Halt this TC */
+                       write_c0_tchalt(TCHALT_H);
+                       instruction_hazard();
+               } else if (cpu_has_vp) {
+                       write_cpc_cl_vp_stop(1 << vpe_id);
+
+                       /* Ensure that the VP_STOP register is written */
+                       wmb();
+               }
        } else {
+               pr_debug("Gating power to core %d\n", core);
                /* Power down the core */
                cps_pm_enter_state(CPS_PM_POWER_GATED);
        }
@@ -410,6 +477,8 @@ static void wait_for_sibling_halt(void *ptr_cpu)
 static void cps_cpu_die(unsigned int cpu)
 {
        unsigned core = cpu_data[cpu].core;
+       unsigned int vpe_id = cpu_vpe_id(&cpu_data[cpu]);
+       ktime_t fail_time;
        unsigned stat;
        int err;
 
@@ -437,14 +506,36 @@ static void cps_cpu_die(unsigned int cpu)
                 * state, the latter happening when a JTAG probe is connected
                 * in which case the CPC will refuse to power down the core.
                 */
+               fail_time = ktime_add_ms(ktime_get(), 2000);
                do {
+                       mips_cm_lock_other(core, 0);
                        mips_cpc_lock_other(core);
                        stat = read_cpc_co_stat_conf();
                        stat &= CPC_Cx_STAT_CONF_SEQSTATE_MSK;
                        mips_cpc_unlock_other();
-               } while (stat != CPC_Cx_STAT_CONF_SEQSTATE_D0 &&
-                        stat != CPC_Cx_STAT_CONF_SEQSTATE_D2 &&
-                        stat != CPC_Cx_STAT_CONF_SEQSTATE_U2);
+                       mips_cm_unlock_other();
+
+                       if (stat == CPC_Cx_STAT_CONF_SEQSTATE_D0 ||
+                           stat == CPC_Cx_STAT_CONF_SEQSTATE_D2 ||
+                           stat == CPC_Cx_STAT_CONF_SEQSTATE_U2)
+                               break;
+
+                       /*
+                        * The core ought to have powered down, but didn't &
+                        * now we don't really know what state it's in. It's
+                        * likely that its _pwr_up pin has been wired to logic
+                        * 1 & it powered back up as soon as we powered it
+                        * down...
+                        *
+                        * The best we can do is warn the user & continue in
+                        * the hope that the core is doing nothing harmful &
+                        * might behave properly if we online it later.
+                        */
+                       if (WARN(ktime_after(ktime_get(), fail_time),
+                                "CPU%u hasn't powered down, seq. state %u\n",
+                                cpu, stat >> CPC_Cx_STAT_CONF_SEQSTATE_SHF))
+                               break;
+               } while (1);
 
                /* Indicate the core is powered off */
                bitmap_clear(core_power, core, 1);
@@ -458,6 +549,12 @@ static void cps_cpu_die(unsigned int cpu)
                                               (void *)(unsigned long)cpu, 1);
                if (err)
                        panic("Failed to call remote sibling CPU\n");
+       } else if (cpu_has_vp) {
+               do {
+                       mips_cm_lock_other(core, vpe_id);
+                       stat = read_cpc_co_vp_running();
+                       mips_cm_unlock_other();
+               } while (stat & (1 << vpe_id));
        }
 }
 
index 4af08c1..1ef11f4 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/smp.h>
 #include <linux/spinlock.h>
 #include <linux/threads.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/time.h>
 #include <linux/timex.h>
 #include <linux/sched.h>
index 31ca2ed..e23f477 100644 (file)
@@ -56,6 +56,7 @@
 #include <asm/pgtable.h>
 #include <asm/ptrace.h>
 #include <asm/sections.h>
+#include <asm/siginfo.h>
 #include <asm/tlbdebug.h>
 #include <asm/traps.h>
 #include <asm/uaccess.h>
@@ -705,6 +706,32 @@ asmlinkage void do_ov(struct pt_regs *regs)
        exception_exit(prev_state);
 }
 
+/*
+ * Send SIGFPE according to FCSR Cause bits, which must have already
+ * been masked against Enable bits.  This is impotant as Inexact can
+ * happen together with Overflow or Underflow, and `ptrace' can set
+ * any bits.
+ */
+void force_fcr31_sig(unsigned long fcr31, void __user *fault_addr,
+                    struct task_struct *tsk)
+{
+       struct siginfo si = { .si_addr = fault_addr, .si_signo = SIGFPE };
+
+       if (fcr31 & FPU_CSR_INV_X)
+               si.si_code = FPE_FLTINV;
+       else if (fcr31 & FPU_CSR_DIV_X)
+               si.si_code = FPE_FLTDIV;
+       else if (fcr31 & FPU_CSR_OVF_X)
+               si.si_code = FPE_FLTOVF;
+       else if (fcr31 & FPU_CSR_UDF_X)
+               si.si_code = FPE_FLTUND;
+       else if (fcr31 & FPU_CSR_INE_X)
+               si.si_code = FPE_FLTRES;
+       else
+               si.si_code = __SI_FAULT;
+       force_sig_info(SIGFPE, &si, tsk);
+}
+
 int process_fpemu_return(int sig, void __user *fault_addr, unsigned long fcr31)
 {
        struct siginfo si = { 0 };
@@ -714,27 +741,7 @@ int process_fpemu_return(int sig, void __user *fault_addr, unsigned long fcr31)
                return 0;
 
        case SIGFPE:
-               si.si_addr = fault_addr;
-               si.si_signo = sig;
-               /*
-                * Inexact can happen together with Overflow or Underflow.
-                * Respect the mask to deliver the correct exception.
-                */
-               fcr31 &= (fcr31 & FPU_CSR_ALL_E) <<
-                        (ffs(FPU_CSR_ALL_X) - ffs(FPU_CSR_ALL_E));
-               if (fcr31 & FPU_CSR_INV_X)
-                       si.si_code = FPE_FLTINV;
-               else if (fcr31 & FPU_CSR_DIV_X)
-                       si.si_code = FPE_FLTDIV;
-               else if (fcr31 & FPU_CSR_OVF_X)
-                       si.si_code = FPE_FLTOVF;
-               else if (fcr31 & FPU_CSR_UDF_X)
-                       si.si_code = FPE_FLTUND;
-               else if (fcr31 & FPU_CSR_INE_X)
-                       si.si_code = FPE_FLTRES;
-               else
-                       si.si_code = __SI_FAULT;
-               force_sig_info(sig, &si, current);
+               force_fcr31_sig(fcr31, fault_addr, current);
                return 1;
 
        case SIGBUS:
@@ -797,13 +804,13 @@ static int simulate_fp(struct pt_regs *regs, unsigned int opcode,
        /* Run the emulator */
        sig = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1,
                                       &fault_addr);
-       fcr31 = current->thread.fpu.fcr31;
 
        /*
-        * We can't allow the emulated instruction to leave any of
-        * the cause bits set in $fcr31.
+        * We can't allow the emulated instruction to leave any
+        * enabled Cause bits set in $fcr31.
         */
-       current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
+       fcr31 = mask_fcr31_x(current->thread.fpu.fcr31);
+       current->thread.fpu.fcr31 &= ~fcr31;
 
        /* Restore the hardware register state */
        own_fpu(1);
@@ -829,7 +836,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
                goto out;
 
        /* Clear FCSR.Cause before enabling interrupts */
-       write_32bit_cp1_register(CP1_STATUS, fcr31 & ~FPU_CSR_ALL_X);
+       write_32bit_cp1_register(CP1_STATUS, fcr31 & ~mask_fcr31_x(fcr31));
        local_irq_enable();
 
        die_if_kernel("FP exception in kernel code", regs);
@@ -851,13 +858,13 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
                /* Run the emulator */
                sig = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1,
                                               &fault_addr);
-               fcr31 = current->thread.fpu.fcr31;
 
                /*
-                * We can't allow the emulated instruction to leave any of
-                * the cause bits set in $fcr31.
+                * We can't allow the emulated instruction to leave any
+                * enabled Cause bits set in $fcr31.
                 */
-               current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
+               fcr31 = mask_fcr31_x(current->thread.fpu.fcr31);
+               current->thread.fpu.fcr31 &= ~fcr31;
 
                /* Restore the hardware register state */
                own_fpu(1);     /* Using the FPU again.  */
@@ -873,7 +880,7 @@ out:
        exception_exit(prev_state);
 }
 
-void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
+void do_trap_or_bp(struct pt_regs *regs, unsigned int code, int si_code,
        const char *str)
 {
        siginfo_t info = { 0 };
@@ -930,7 +937,13 @@ void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
        default:
                scnprintf(b, sizeof(b), "%s instruction in kernel code", str);
                die_if_kernel(b, regs);
-               force_sig(SIGTRAP, current);
+               if (si_code) {
+                       info.si_signo = SIGTRAP;
+                       info.si_code = si_code;
+                       force_sig_info(SIGTRAP, &info, current);
+               } else {
+                       force_sig(SIGTRAP, current);
+               }
        }
 }
 
@@ -1014,7 +1027,7 @@ asmlinkage void do_bp(struct pt_regs *regs)
                break;
        }
 
-       do_trap_or_bp(regs, bcode, "Break");
+       do_trap_or_bp(regs, bcode, TRAP_BRKPT, "Break");
 
 out:
        set_fs(seg);
@@ -1056,7 +1069,7 @@ asmlinkage void do_tr(struct pt_regs *regs)
                        tcode = (opcode >> 6) & ((1 << 10) - 1);
        }
 
-       do_trap_or_bp(regs, tcode, "Trap");
+       do_trap_or_bp(regs, tcode, 0, "Trap");
 
 out:
        set_fs(seg);
@@ -1430,13 +1443,13 @@ asmlinkage void do_cpu(struct pt_regs *regs)
 
                sig = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 0,
                                               &fault_addr);
-               fcr31 = current->thread.fpu.fcr31;
 
                /*
                 * We can't allow the emulated instruction to leave
-                * any of the cause bits set in $fcr31.
+                * any enabled Cause bits set in $fcr31.
                 */
-               current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
+               fcr31 = mask_fcr31_x(current->thread.fpu.fcr31);
+               current->thread.fpu.fcr31 &= ~fcr31;
 
                /* Send a signal if required.  */
                if (!process_fpemu_return(sig, fault_addr, fcr31) && !err)
@@ -1507,6 +1520,7 @@ asmlinkage void do_mdmx(struct pt_regs *regs)
  */
 asmlinkage void do_watch(struct pt_regs *regs)
 {
+       siginfo_t info = { .si_signo = SIGTRAP, .si_code = TRAP_HWBKPT };
        enum ctx_state prev_state;
        u32 cause;
 
@@ -1527,7 +1541,7 @@ asmlinkage void do_watch(struct pt_regs *regs)
        if (test_tsk_thread_flag(current, TIF_LOAD_WATCH)) {
                mips_read_watch_registers();
                local_irq_enable();
-               force_sig(SIGTRAP, current);
+               force_sig_info(SIGTRAP, &info, current);
        } else {
                mips_clear_watch_registers();
                local_irq_enable();
@@ -2126,6 +2140,13 @@ void per_cpu_trap_init(bool is_boot_cpu)
         *  o read IntCtl.IPFDC to determine the fast debug channel interrupt
         */
        if (cpu_has_mips_r2_r6) {
+               /*
+                * We shouldn't trust a secondary core has a sane EBASE register
+                * so use the one calculated by the boot CPU.
+                */
+               if (!is_boot_cpu)
+                       write_c0_ebase(ebase);
+
                cp0_compare_irq_shift = CAUSEB_TI - CAUSEB_IP;
                cp0_compare_irq = (read_c0_intctl() >> INTCTLB_IPTI) & 7;
                cp0_perfcount_irq = (read_c0_intctl() >> INTCTLB_IPPCI) & 7;
@@ -2229,7 +2250,7 @@ void __init trap_init(void)
 
        /*
         * Copy the generic exception handlers to their final destination.
-        * This will be overriden later as suitable for a particular
+        * This will be overridden later as suitable for a particular
         * configuration.
         */
        set_handler(0x180, &except_vec3_generic, 0x80);
index 5c62065..0aa4bae 100644 (file)
@@ -939,88 +939,114 @@ static void emulate_load_store_insn(struct pt_regs *regs,
                 * The remaining opcodes are the ones that are really of
                 * interest.
                 */
-#ifdef CONFIG_EVA
        case spec3_op:
-               /*
-                * we can land here only from kernel accessing user memory,
-                * so we need to "switch" the address limit to user space, so
-                * address check can work properly.
-                */
-               seg = get_fs();
-               set_fs(USER_DS);
-               switch (insn.spec3_format.func) {
-               case lhe_op:
-                       if (!access_ok(VERIFY_READ, addr, 2)) {
-                               set_fs(seg);
-                               goto sigbus;
-                       }
-                       LoadHWE(addr, value, res);
-                       if (res) {
-                               set_fs(seg);
-                               goto fault;
-                       }
-                       compute_return_epc(regs);
-                       regs->regs[insn.spec3_format.rt] = value;
-                       break;
-               case lwe_op:
-                       if (!access_ok(VERIFY_READ, addr, 4)) {
-                               set_fs(seg);
-                               goto sigbus;
+               if (insn.dsp_format.func == lx_op) {
+                       switch (insn.dsp_format.op) {
+                       case lwx_op:
+                               if (!access_ok(VERIFY_READ, addr, 4))
+                                       goto sigbus;
+                               LoadW(addr, value, res);
+                               if (res)
+                                       goto fault;
+                               compute_return_epc(regs);
+                               regs->regs[insn.dsp_format.rd] = value;
+                               break;
+                       case lhx_op:
+                               if (!access_ok(VERIFY_READ, addr, 2))
+                                       goto sigbus;
+                               LoadHW(addr, value, res);
+                               if (res)
+                                       goto fault;
+                               compute_return_epc(regs);
+                               regs->regs[insn.dsp_format.rd] = value;
+                               break;
+                       default:
+                               goto sigill;
                        }
+               }
+#ifdef CONFIG_EVA
+               else {
+                       /*
+                        * we can land here only from kernel accessing user
+                        * memory, so we need to "switch" the address limit to
+                        * user space, so that address check can work properly.
+                        */
+                       seg = get_fs();
+                       set_fs(USER_DS);
+                       switch (insn.spec3_format.func) {
+                       case lhe_op:
+                               if (!access_ok(VERIFY_READ, addr, 2)) {
+                                       set_fs(seg);
+                                       goto sigbus;
+                               }
+                               LoadHWE(addr, value, res);
+                               if (res) {
+                                       set_fs(seg);
+                                       goto fault;
+                               }
+                               compute_return_epc(regs);
+                               regs->regs[insn.spec3_format.rt] = value;
+                               break;
+                       case lwe_op:
+                               if (!access_ok(VERIFY_READ, addr, 4)) {
+                                       set_fs(seg);
+                                       goto sigbus;
+                               }
                                LoadWE(addr, value, res);
-                       if (res) {
-                               set_fs(seg);
-                               goto fault;
-                       }
-                       compute_return_epc(regs);
-                       regs->regs[insn.spec3_format.rt] = value;
-                       break;
-               case lhue_op:
-                       if (!access_ok(VERIFY_READ, addr, 2)) {
-                               set_fs(seg);
-                               goto sigbus;
-                       }
-                       LoadHWUE(addr, value, res);
-                       if (res) {
-                               set_fs(seg);
-                               goto fault;
-                       }
-                       compute_return_epc(regs);
-                       regs->regs[insn.spec3_format.rt] = value;
-                       break;
-               case she_op:
-                       if (!access_ok(VERIFY_WRITE, addr, 2)) {
-                               set_fs(seg);
-                               goto sigbus;
-                       }
-                       compute_return_epc(regs);
-                       value = regs->regs[insn.spec3_format.rt];
-                       StoreHWE(addr, value, res);
-                       if (res) {
-                               set_fs(seg);
-                               goto fault;
-                       }
-                       break;
-               case swe_op:
-                       if (!access_ok(VERIFY_WRITE, addr, 4)) {
-                               set_fs(seg);
-                               goto sigbus;
-                       }
-                       compute_return_epc(regs);
-                       value = regs->regs[insn.spec3_format.rt];
-                       StoreWE(addr, value, res);
-                       if (res) {
+                               if (res) {
+                                       set_fs(seg);
+                                       goto fault;
+                               }
+                               compute_return_epc(regs);
+                               regs->regs[insn.spec3_format.rt] = value;
+                               break;
+                       case lhue_op:
+                               if (!access_ok(VERIFY_READ, addr, 2)) {
+                                       set_fs(seg);
+                                       goto sigbus;
+                               }
+                               LoadHWUE(addr, value, res);
+                               if (res) {
+                                       set_fs(seg);
+                                       goto fault;
+                               }
+                               compute_return_epc(regs);
+                               regs->regs[insn.spec3_format.rt] = value;
+                               break;
+                       case she_op:
+                               if (!access_ok(VERIFY_WRITE, addr, 2)) {
+                                       set_fs(seg);
+                                       goto sigbus;
+                               }
+                               compute_return_epc(regs);
+                               value = regs->regs[insn.spec3_format.rt];
+                               StoreHWE(addr, value, res);
+                               if (res) {
+                                       set_fs(seg);
+                                       goto fault;
+                               }
+                               break;
+                       case swe_op:
+                               if (!access_ok(VERIFY_WRITE, addr, 4)) {
+                                       set_fs(seg);
+                                       goto sigbus;
+                               }
+                               compute_return_epc(regs);
+                               value = regs->regs[insn.spec3_format.rt];
+                               StoreWE(addr, value, res);
+                               if (res) {
+                                       set_fs(seg);
+                                       goto fault;
+                               }
+                               break;
+                       default:
                                set_fs(seg);
-                               goto fault;
+                               goto sigill;
                        }
-                       break;
-               default:
                        set_fs(seg);
-                       goto sigill;
                }
-               set_fs(seg);
-               break;
 #endif
+               break;
        case lh_op:
                if (!access_ok(VERIFY_READ, addr, 2))
                        goto sigbus;
@@ -1191,6 +1217,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
        case ldc1_op:
        case swc1_op:
        case sdc1_op:
+       case cop1x_op:
                die_if_kernel("Unaligned FP access in kernel code", regs);
                BUG_ON(!used_math());
 
index 5649a9e..3fcc833 100644 (file)
@@ -106,6 +106,16 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 
        down_write(&mm->mmap_sem);
 
+       /* Map delay slot emulation page */
+       base = mmap_region(NULL, STACK_TOP, PAGE_SIZE,
+                          VM_READ|VM_WRITE|VM_EXEC|
+                          VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
+                          0);
+       if (IS_ERR_VALUE(base)) {
+               ret = base;
+               goto out;
+       }
+
        /*
         * Determine total area size. This includes the VDSO data itself, the
         * data page, and the GIC user page if present. Always create a mapping
index eff71c7..75d0560 100644 (file)
@@ -683,7 +683,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 
        kvm_debug("%s: vcpu %p, cpu: %d\n", __func__, vcpu, cpu);
 
-       /* Alocate new kernel and user ASIDs if needed */
+       /* Allocate new kernel and user ASIDs if needed */
 
        local_irq_save(flags);
 
index 307cc4c..473aa4d 100644 (file)
@@ -501,7 +501,7 @@ static int kvm_trap_emul_vcpu_setup(struct kvm_vcpu *vcpu)
        kvm_write_c0_guest_config7(cop0, (MIPS_CONF7_WII) | (1 << 10));
 
        /*
-        * Setup IntCtl defaults, compatibilty mode for timer interrupts (HW5)
+        * Setup IntCtl defaults, compatibility mode for timer interrupts (HW5)
         */
        kvm_write_c0_guest_intctl(cop0, 0xFC000000);
 
index a19641d..e9f10b8 100644 (file)
@@ -4,9 +4,11 @@
 
 obj-y  += cp1emu.o ieee754dp.o ieee754sp.o ieee754.o \
           dp_div.o dp_mul.o dp_sub.o dp_add.o dp_fsp.o dp_cmp.o dp_simple.o \
-          dp_tint.o dp_fint.o dp_maddf.o dp_msubf.o dp_2008class.o dp_fmin.o dp_fmax.o \
+          dp_tint.o dp_fint.o dp_rint.o dp_maddf.o dp_2008class.o dp_fmin.o \
+          dp_fmax.o                                                         \
           sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_simple.o \
-          sp_tint.o sp_fint.o sp_maddf.o sp_msubf.o sp_2008class.o sp_fmin.o sp_fmax.o \
+          sp_tint.o sp_fint.o sp_rint.o sp_maddf.o sp_2008class.o sp_fmin.o \
+          sp_fmax.o                                                         \
           dsemul.o
 
 lib-y  += ieee754d.o \
index 89d05de..ebb5e3b 100644 (file)
@@ -434,12 +434,14 @@ static int microMIPS32_to_MIPS32(union mips_instruction *insn_ptr)
  * a single subroutine should be used across both
  * modules.
  */
-static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
-                        unsigned long *contpc)
+int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
+                 unsigned long *contpc)
 {
        union mips_instruction insn = (union mips_instruction)dec_insn.insn;
        unsigned int fcr31;
        unsigned int bit = 0;
+       unsigned int bit0;
+       union fpureg *fpr;
 
        switch (insn.i_format.opcode) {
        case spec_op:
@@ -450,7 +452,7 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                                        regs->cp0_epc + dec_insn.pc_inc +
                                        dec_insn.next_pc_inc;
                        }
-                       /* Fall through */
+                       /* fall through */
                case jr_op:
                        /* For R6, JR already emulated in jalr_op */
                        if (NO_R6EMU && insn.r_format.func == jr_op)
@@ -470,10 +472,11 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                        regs->regs[31] = regs->cp0_epc +
                                dec_insn.pc_inc +
                                dec_insn.next_pc_inc;
-                       /* Fall through */
+                       /* fall through */
                case bltzl_op:
                        if (NO_R6EMU)
                                break;
+                       /* fall through */
                case bltz_op:
                        if ((long)regs->regs[insn.i_format.rs] < 0)
                                *contpc = regs->cp0_epc +
@@ -493,10 +496,11 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                        regs->regs[31] = regs->cp0_epc +
                                dec_insn.pc_inc +
                                dec_insn.next_pc_inc;
-                       /* Fall through */
+                       /* fall through */
                case bgezl_op:
                        if (NO_R6EMU)
                                break;
+                       /* fall through */
                case bgez_op:
                        if ((long)regs->regs[insn.i_format.rs] >= 0)
                                *contpc = regs->cp0_epc +
@@ -511,11 +515,12 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                break;
        case jalx_op:
                set_isa16_mode(bit);
+               /* fall through */
        case jal_op:
                regs->regs[31] = regs->cp0_epc +
                        dec_insn.pc_inc +
                        dec_insn.next_pc_inc;
-               /* Fall through */
+               /* fall through */
        case j_op:
                *contpc = regs->cp0_epc + dec_insn.pc_inc;
                *contpc >>= 28;
@@ -527,6 +532,7 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
        case beql_op:
                if (NO_R6EMU)
                        break;
+               /* fall through */
        case beq_op:
                if (regs->regs[insn.i_format.rs] ==
                    regs->regs[insn.i_format.rt])
@@ -541,6 +547,7 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
        case bnel_op:
                if (NO_R6EMU)
                        break;
+               /* fall through */
        case bne_op:
                if (regs->regs[insn.i_format.rs] !=
                    regs->regs[insn.i_format.rt])
@@ -555,6 +562,7 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
        case blezl_op:
                if (!insn.i_format.rt && NO_R6EMU)
                        break;
+               /* fall through */
        case blez_op:
 
                /*
@@ -592,6 +600,7 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
        case bgtzl_op:
                if (!insn.i_format.rt && NO_R6EMU)
                        break;
+               /* fall through */
        case bgtz_op:
                /*
                 * Compact branches for R6 for the
@@ -627,8 +636,8 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                                dec_insn.pc_inc +
                                dec_insn.next_pc_inc;
                return 1;
-       case cbcond0_op:
-       case cbcond1_op:
+       case pop10_op:
+       case pop30_op:
                if (!cpu_has_mips_r6)
                        break;
                if (insn.i_format.rt && !insn.i_format.rs)
@@ -683,14 +692,14 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                        dec_insn.next_pc_inc;
 
                return 1;
-       case beqzcjic_op:
+       case pop66_op:
                if (!cpu_has_mips_r6)
                        break;
                *contpc = regs->cp0_epc + dec_insn.pc_inc +
                        dec_insn.next_pc_inc;
 
                return 1;
-       case bnezcjialc_op:
+       case pop76_op:
                if (!cpu_has_mips_r6)
                        break;
                if (!insn.i_format.rs)
@@ -707,14 +716,14 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                    ((insn.i_format.rs == bc1eqz_op) ||
                     (insn.i_format.rs == bc1nez_op))) {
                        bit = 0;
+                       fpr = &current->thread.fpu.fpr[insn.i_format.rt];
+                       bit0 = get_fpr32(fpr, 0) & 0x1;
                        switch (insn.i_format.rs) {
                        case bc1eqz_op:
-                               if (get_fpr32(&current->thread.fpu.fpr[insn.i_format.rt], 0) & 0x1)
-                                   bit = 1;
+                               bit = bit0 == 0;
                                break;
                        case bc1nez_op:
-                               if (!(get_fpr32(&current->thread.fpu.fpr[insn.i_format.rt], 0) & 0x1))
-                                   bit = 1;
+                               bit = bit0 != 0;
                                break;
                        }
                        if (bit)
@@ -728,7 +737,8 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
 
                        return 1;
                }
-               /* R2/R6 compatible cop1 instruction. Fall through */
+               /* R2/R6 compatible cop1 instruction */
+               /* fall through */
        case cop2_op:
        case cop1x_op:
                if (insn.i_format.rs == bc_op) {
@@ -809,7 +819,7 @@ do {                                                                        \
 #define SITOREG(si, x)                                                 \
 do {                                                                   \
        if (cop1_64bit(xcp) && !hybrid_fprs()) {                        \
-               unsigned i;                                             \
+               unsigned int i;                                         \
                set_fpr32(&ctx->fpr[x], 0, si);                         \
                for (i = 1; i < ARRAY_SIZE(ctx->fpr[x].val32); i++)     \
                        set_fpr32(&ctx->fpr[x], i, 0);                  \
@@ -822,19 +832,19 @@ do {                                                                      \
 
 #define SITOHREG(si, x)                                                        \
 do {                                                                   \
-       unsigned i;                                                     \
+       unsigned int i;                                                 \
        set_fpr32(&ctx->fpr[x], 1, si);                                 \
        for (i = 2; i < ARRAY_SIZE(ctx->fpr[x].val32); i++)             \
                set_fpr32(&ctx->fpr[x], i, 0);                          \
 } while (0)
 
 #define DIFROMREG(di, x)                                               \
-       ((di) = get_fpr64(&ctx->fpr[(x) & ~(cop1_64bit(xcp) == 0)], 0))
+       ((di) = get_fpr64(&ctx->fpr[(x) & ~(cop1_64bit(xcp) ^ 1)], 0))
 
 #define DITOREG(di, x)                                                 \
 do {                                                                   \
-       unsigned fpr, i;                                                \
-       fpr = (x) & ~(cop1_64bit(xcp) == 0);                            \
+       unsigned int fpr, i;                                            \
+       fpr = (x) & ~(cop1_64bit(xcp) ^ 1);                             \
        set_fpr64(&ctx->fpr[fpr], 0, di);                               \
        for (i = 1; i < ARRAY_SIZE(ctx->fpr[x].val64); i++)             \
                set_fpr64(&ctx->fpr[fpr], i, 0);                        \
@@ -975,9 +985,10 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                struct mm_decoded_insn dec_insn, void *__user *fault_addr)
 {
        unsigned long contpc = xcp->cp0_epc + dec_insn.pc_inc;
-       unsigned int cond, cbit;
+       unsigned int cond, cbit, bit0;
        mips_instruction ir;
        int likely, pc_inc;
+       union fpureg *fpr;
        u32 __user *wva;
        u64 __user *dva;
        u32 wval;
@@ -1188,15 +1199,18 @@ emul:
                        if (!cpu_has_mips_r6 || delay_slot(xcp))
                                return SIGILL;
 
-                       cond = likely = 0;
+                       likely = 0;
+                       cond = 0;
+                       fpr = &current->thread.fpu.fpr[MIPSInst_RT(ir)];
+                       bit0 = get_fpr32(fpr, 0) & 0x1;
                        switch (MIPSInst_RS(ir)) {
                        case bc1eqz_op:
-                               if (get_fpr32(&current->thread.fpu.fpr[MIPSInst_RT(ir)], 0) & 0x1)
-                                   cond = 1;
+                               MIPS_FPU_EMU_INC_STATS(bc1eqz);
+                               cond = bit0 == 0;
                                break;
                        case bc1nez_op:
-                               if (!(get_fpr32(&current->thread.fpu.fpr[MIPSInst_RT(ir)], 0) & 0x1))
-                                   cond = 1;
+                               MIPS_FPU_EMU_INC_STATS(bc1nez);
+                               cond = bit0 != 0;
                                break;
                        }
                        goto branch_common;
@@ -1216,18 +1230,19 @@ emul:
                        case bcfl_op:
                                if (cpu_has_mips_2_3_4_5_r)
                                        likely = 1;
-                               /* Fall through */
+                               /* fall through */
                        case bcf_op:
                                cond = !cond;
                                break;
                        case bctl_op:
                                if (cpu_has_mips_2_3_4_5_r)
                                        likely = 1;
-                               /* Fall through */
+                               /* fall through */
                        case bct_op:
                                break;
                        }
 branch_common:
+                       MIPS_FPU_EMU_INC_STATS(branches);
                        set_delay_slot(xcp);
                        if (cond) {
                                /*
@@ -1267,7 +1282,9 @@ branch_common:
                                                 * instruction in the dslot.
                                                 */
                                                sig = mips_dsemul(xcp, ir,
-                                                                 contpc);
+                                                                 bcpc, contpc);
+                                               if (sig < 0)
+                                                       break;
                                                if (sig)
                                                        xcp->cp0_epc = bcpc;
                                                /*
@@ -1320,7 +1337,9 @@ branch_common:
                                 * Single step the non-cp1
                                 * instruction in the dslot
                                 */
-                               sig = mips_dsemul(xcp, ir, contpc);
+                               sig = mips_dsemul(xcp, ir, bcpc, contpc);
+                               if (sig < 0)
+                                       break;
                                if (sig)
                                        xcp->cp0_epc = bcpc;
                                /* SIGILL forces out of the emulation loop.  */
@@ -1344,7 +1363,8 @@ branch_common:
                                return SIGILL;
 
                        /* a real fpu computation instruction */
-                       if ((sig = fpu_emu(xcp, ctx, ir)))
+                       sig = fpu_emu(xcp, ctx, ir);
+                       if (sig)
                                return sig;
                }
                break;
@@ -1457,7 +1477,7 @@ DEF3OP(nmsub, dp, ieee754dp_mul, ieee754dp_sub, ieee754dp_neg);
 static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
        mips_instruction ir, void *__user *fault_addr)
 {
-       unsigned rcsr = 0;      /* resulting csr */
+       unsigned int rcsr = 0;  /* resulting csr */
 
        MIPS_FPU_EMU_INC_STATS(cp1xops);
 
@@ -1653,10 +1673,10 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
        mips_instruction ir)
 {
        int rfmt;               /* resulting format */
-       unsigned rcsr = 0;      /* resulting csr */
+       unsigned int rcsr = 0;  /* resulting csr */
        unsigned int oldrm;
        unsigned int cbit;
-       unsigned cond;
+       unsigned int cond;
        union {
                union ieee754dp d;
                union ieee754sp s;
@@ -1672,20 +1692,24 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                        union ieee754sp(*b) (union ieee754sp, union ieee754sp);
                        union ieee754sp(*u) (union ieee754sp);
                } handler;
-               union ieee754sp fs, ft;
+               union ieee754sp fd, fs, ft;
 
                switch (MIPSInst_FUNC(ir)) {
                        /* binary ops */
                case fadd_op:
+                       MIPS_FPU_EMU_INC_STATS(add_s);
                        handler.b = ieee754sp_add;
                        goto scopbop;
                case fsub_op:
+                       MIPS_FPU_EMU_INC_STATS(sub_s);
                        handler.b = ieee754sp_sub;
                        goto scopbop;
                case fmul_op:
+                       MIPS_FPU_EMU_INC_STATS(mul_s);
                        handler.b = ieee754sp_mul;
                        goto scopbop;
                case fdiv_op:
+                       MIPS_FPU_EMU_INC_STATS(div_s);
                        handler.b = ieee754sp_div;
                        goto scopbop;
 
@@ -1694,6 +1718,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                        if (!cpu_has_mips_2_3_4_5_r)
                                return SIGILL;
 
+                       MIPS_FPU_EMU_INC_STATS(sqrt_s);
                        handler.u = ieee754sp_sqrt;
                        goto scopuop;
 
@@ -1706,6 +1731,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                        if (!cpu_has_mips_4_5_64_r2_r6)
                                return SIGILL;
 
+                       MIPS_FPU_EMU_INC_STATS(rsqrt_s);
                        handler.u = fpemu_sp_rsqrt;
                        goto scopuop;
 
@@ -1713,6 +1739,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                        if (!cpu_has_mips_4_5_64_r2_r6)
                                return SIGILL;
 
+                       MIPS_FPU_EMU_INC_STATS(recip_s);
                        handler.u = fpemu_sp_recip;
                        goto scopuop;
 
@@ -1749,6 +1776,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                        if (!cpu_has_mips_r6)
                                return SIGILL;
 
+                       MIPS_FPU_EMU_INC_STATS(seleqz_s);
                        SPFROMREG(rv.s, MIPSInst_FT(ir));
                        if (rv.w & 0x1)
                                rv.w = 0;
@@ -1760,6 +1788,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                        if (!cpu_has_mips_r6)
                                return SIGILL;
 
+                       MIPS_FPU_EMU_INC_STATS(selnez_s);
                        SPFROMREG(rv.s, MIPSInst_FT(ir));
                        if (rv.w & 0x1)
                                SPFROMREG(rv.s, MIPSInst_FS(ir));
@@ -1773,6 +1802,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                        if (!cpu_has_mips_r6)
                                return SIGILL;
 
+                       MIPS_FPU_EMU_INC_STATS(maddf_s);
                        SPFROMREG(ft, MIPSInst_FT(ir));
                        SPFROMREG(fs, MIPSInst_FS(ir));
                        SPFROMREG(fd, MIPSInst_FD(ir));
@@ -1786,6 +1816,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                        if (!cpu_has_mips_r6)
                                return SIGILL;
 
+                       MIPS_FPU_EMU_INC_STATS(msubf_s);
                        SPFROMREG(ft, MIPSInst_FT(ir));
                        SPFROMREG(fs, MIPSInst_FS(ir));
                        SPFROMREG(fd, MIPSInst_FD(ir));
@@ -1799,9 +1830,9 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                        if (!cpu_has_mips_r6)
                                return SIGILL;
 
+                       MIPS_FPU_EMU_INC_STATS(rint_s);
                        SPFROMREG(fs, MIPSInst_FS(ir));
-                       rv.l = ieee754sp_tlong(fs);
-                       rv.s = ieee754sp_flong(rv.l);
+                       rv.s = ieee754sp_rint(fs);
                        goto copcsr;
                }
 
@@ -1811,6 +1842,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                        if (!cpu_has_mips_r6)
                                return SIGILL;
 
+                       MIPS_FPU_EMU_INC_STATS(class_s);
                        SPFROMREG(fs, MIPSInst_FS(ir));
                        rv.w = ieee754sp_2008class(fs);
                        rfmt = w_fmt;
@@ -1823,6 +1855,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                        if (!cpu_has_mips_r6)
                                return SIGILL;
 
+                       MIPS_FPU_EMU_INC_STATS(min_s);
                        SPFROMREG(ft, MIPSInst_FT(ir));
                        SPFROMREG(fs, MIPSInst_FS(ir));
                        rv.s = ieee754sp_fmin(fs, ft);
@@ -1835,6 +1868,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                        if (!cpu_has_mips_r6)
                                return SIGILL;
 
+                       MIPS_FPU_EMU_INC_STATS(mina_s);
                        SPFROMREG(ft, MIPSInst_FT(ir));
                        SPFROMREG(fs, MIPSInst_FS(ir));
                        rv.s = ieee754sp_fmina(fs, ft);
@@ -1847,6 +1881,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                        if (!cpu_has_mips_r6)
                                return SIGILL;
 
+                       MIPS_FPU_EMU_INC_STATS(max_s);
                        SPFROMREG(ft, MIPSInst_FT(ir));
                        SPFROMREG(fs, MIPSInst_FS(ir));
                        rv.s = ieee754sp_fmax(fs, ft);
@@ -1859,6 +1894,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                        if (!cpu_has_mips_r6)
                                return SIGILL;
 
+                       MIPS_FPU_EMU_INC_STATS(maxa_s);
                        SPFROMREG(ft, MIPSInst_FT(ir));
                        SPFROMREG(fs, MIPSInst_FS(ir));
                        rv.s = ieee754sp_fmaxa(fs, ft);
@@ -1866,15 +1902,18 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                }
 
                case fabs_op:
+                       MIPS_FPU_EMU_INC_STATS(abs_s);
                        handler.u = ieee754sp_abs;
                        goto scopuop;
 
                case fneg_op:
+                       MIPS_FPU_EMU_INC_STATS(neg_s);
                        handler.u = ieee754sp_neg;
                        goto scopuop;
 
                case fmov_op:
                        /* an easy one */
+                       MIPS_FPU_EMU_INC_STATS(mov_s);
                        SPFROMREG(rv.s, MIPSInst_FS(ir));
                        goto copcsr;
 
@@ -1917,12 +1956,14 @@ copcsr:
                        return SIGILL;  /* not defined */
 
                case fcvtd_op:
+                       MIPS_FPU_EMU_INC_STATS(cvt_d_s);
                        SPFROMREG(fs, MIPSInst_FS(ir));
                        rv.d = ieee754dp_fsp(fs);
                        rfmt = d_fmt;
                        goto copcsr;
 
                case fcvtw_op:
+                       MIPS_FPU_EMU_INC_STATS(cvt_w_s);
                        SPFROMREG(fs, MIPSInst_FS(ir));
                        rv.w = ieee754sp_tint(fs);
                        rfmt = w_fmt;
@@ -1935,6 +1976,15 @@ copcsr:
                        if (!cpu_has_mips_2_3_4_5_r)
                                return SIGILL;
 
+                       if (MIPSInst_FUNC(ir) == fceil_op)
+                               MIPS_FPU_EMU_INC_STATS(ceil_w_s);
+                       if (MIPSInst_FUNC(ir) == ffloor_op)
+                               MIPS_FPU_EMU_INC_STATS(floor_w_s);
+                       if (MIPSInst_FUNC(ir) == fround_op)
+                               MIPS_FPU_EMU_INC_STATS(round_w_s);
+                       if (MIPSInst_FUNC(ir) == ftrunc_op)
+                               MIPS_FPU_EMU_INC_STATS(trunc_w_s);
+
                        oldrm = ieee754_csr.rm;
                        SPFROMREG(fs, MIPSInst_FS(ir));
                        ieee754_csr.rm = MIPSInst_FUNC(ir);
@@ -1943,10 +1993,23 @@ copcsr:
                        rfmt = w_fmt;
                        goto copcsr;
 
+               case fsel_op:
+                       if (!cpu_has_mips_r6)
+                               return SIGILL;
+
+                       MIPS_FPU_EMU_INC_STATS(sel_s);
+                       SPFROMREG(fd, MIPSInst_FD(ir));
+                       if (fd.bits & 0x1)
+                               SPFROMREG(rv.s, MIPSInst_FT(ir));
+                       else
+                               SPFROMREG(rv.s, MIPSInst_FS(ir));
+                       break;
+
                case fcvtl_op:
                        if (!cpu_has_mips_3_4_5_64_r2_r6)
                                return SIGILL;
 
+                       MIPS_FPU_EMU_INC_STATS(cvt_l_s);
                        SPFROMREG(fs, MIPSInst_FS(ir));
                        rv.l = ieee754sp_tlong(fs);
                        rfmt = l_fmt;
@@ -1959,6 +2022,15 @@ copcsr:
                        if (!cpu_has_mips_3_4_5_64_r2_r6)
                                return SIGILL;
 
+                       if (MIPSInst_FUNC(ir) == fceill_op)
+                               MIPS_FPU_EMU_INC_STATS(ceil_l_s);
+                       if (MIPSInst_FUNC(ir) == ffloorl_op)
+                               MIPS_FPU_EMU_INC_STATS(floor_l_s);
+                       if (MIPSInst_FUNC(ir) == froundl_op)
+                               MIPS_FPU_EMU_INC_STATS(round_l_s);
+                       if (MIPSInst_FUNC(ir) == ftruncl_op)
+                               MIPS_FPU_EMU_INC_STATS(trunc_l_s);
+
                        oldrm = ieee754_csr.rm;
                        SPFROMREG(fs, MIPSInst_FS(ir));
                        ieee754_csr.rm = MIPSInst_FUNC(ir);
@@ -1969,9 +2041,10 @@ copcsr:
 
                default:
                        if (!NO_R6EMU && MIPSInst_FUNC(ir) >= fcmp_op) {
-                               unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op;
+                               unsigned int cmpop;
                                union ieee754sp fs, ft;
 
+                               cmpop = MIPSInst_FUNC(ir) - fcmp_op;
                                SPFROMREG(fs, MIPSInst_FS(ir));
                                SPFROMREG(ft, MIPSInst_FT(ir));
                                rv.w = ieee754sp_cmp(fs, ft,
@@ -1991,7 +2064,7 @@ copcsr:
        }
 
        case d_fmt: {
-               union ieee754dp fs, ft;
+               union ieee754dp fd, fs, ft;
                union {
                        union ieee754dp(*b) (union ieee754dp, union ieee754dp);
                        union ieee754dp(*u) (union ieee754dp);
@@ -2000,15 +2073,19 @@ copcsr:
                switch (MIPSInst_FUNC(ir)) {
                        /* binary ops */
                case fadd_op:
+                       MIPS_FPU_EMU_INC_STATS(add_d);
                        handler.b = ieee754dp_add;
                        goto dcopbop;
                case fsub_op:
+                       MIPS_FPU_EMU_INC_STATS(sub_d);
                        handler.b = ieee754dp_sub;
                        goto dcopbop;
                case fmul_op:
+                       MIPS_FPU_EMU_INC_STATS(mul_d);
                        handler.b = ieee754dp_mul;
                        goto dcopbop;
                case fdiv_op:
+                       MIPS_FPU_EMU_INC_STATS(div_d);
                        handler.b = ieee754dp_div;
                        goto dcopbop;
 
@@ -2017,6 +2094,7 @@ copcsr:
                        if (!cpu_has_mips_2_3_4_5_r)
                                return SIGILL;
 
+                       MIPS_FPU_EMU_INC_STATS(sqrt_d);
                        handler.u = ieee754dp_sqrt;
                        goto dcopuop;
                /*
@@ -2028,12 +2106,14 @@ copcsr:
                        if (!cpu_has_mips_4_5_64_r2_r6)
                                return SIGILL;
 
+                       MIPS_FPU_EMU_INC_STATS(rsqrt_d);
                        handler.u = fpemu_dp_rsqrt;
                        goto dcopuop;
                case frecip_op:
                        if (!cpu_has_mips_4_5_64_r2_r6)
                                return SIGILL;
 
+                       MIPS_FPU_EMU_INC_STATS(recip_d);
                        handler.u = fpemu_dp_recip;
                        goto dcopuop;
                case fmovc_op:
@@ -2067,6 +2147,7 @@ copcsr:
                        if (!cpu_has_mips_r6)
                                return SIGILL;
 
+                       MIPS_FPU_EMU_INC_STATS(seleqz_d);
                        DPFROMREG(rv.d, MIPSInst_FT(ir));
                        if (rv.l & 0x1)
                                rv.l = 0;
@@ -2078,6 +2159,7 @@ copcsr:
                        if (!cpu_has_mips_r6)
                                return SIGILL;
 
+                       MIPS_FPU_EMU_INC_STATS(selnez_d);
                        DPFROMREG(rv.d, MIPSInst_FT(ir));
                        if (rv.l & 0x1)
                                DPFROMREG(rv.d, MIPSInst_FS(ir));
@@ -2091,6 +2173,7 @@ copcsr:
                        if (!cpu_has_mips_r6)
                                return SIGILL;
 
+                       MIPS_FPU_EMU_INC_STATS(maddf_d);
                        DPFROMREG(ft, MIPSInst_FT(ir));
                        DPFROMREG(fs, MIPSInst_FS(ir));
                        DPFROMREG(fd, MIPSInst_FD(ir));
@@ -2104,6 +2187,7 @@ copcsr:
                        if (!cpu_has_mips_r6)
                                return SIGILL;
 
+                       MIPS_FPU_EMU_INC_STATS(msubf_d);
                        DPFROMREG(ft, MIPSInst_FT(ir));
                        DPFROMREG(fs, MIPSInst_FS(ir));
                        DPFROMREG(fd, MIPSInst_FD(ir));
@@ -2117,9 +2201,9 @@ copcsr:
                        if (!cpu_has_mips_r6)
                                return SIGILL;
 
+                       MIPS_FPU_EMU_INC_STATS(rint_d);
                        DPFROMREG(fs, MIPSInst_FS(ir));
-                       rv.l = ieee754dp_tlong(fs);
-                       rv.d = ieee754dp_flong(rv.l);
+                       rv.d = ieee754dp_rint(fs);
                        goto copcsr;
                }
 
@@ -2129,9 +2213,10 @@ copcsr:
                        if (!cpu_has_mips_r6)
                                return SIGILL;
 
+                       MIPS_FPU_EMU_INC_STATS(class_d);
                        DPFROMREG(fs, MIPSInst_FS(ir));
-                       rv.w = ieee754dp_2008class(fs);
-                       rfmt = w_fmt;
+                       rv.l = ieee754dp_2008class(fs);
+                       rfmt = l_fmt;
                        goto copcsr;
                }
 
@@ -2141,6 +2226,7 @@ copcsr:
                        if (!cpu_has_mips_r6)
                                return SIGILL;
 
+                       MIPS_FPU_EMU_INC_STATS(min_d);
                        DPFROMREG(ft, MIPSInst_FT(ir));
                        DPFROMREG(fs, MIPSInst_FS(ir));
                        rv.d = ieee754dp_fmin(fs, ft);
@@ -2153,6 +2239,7 @@ copcsr:
                        if (!cpu_has_mips_r6)
                                return SIGILL;
 
+                       MIPS_FPU_EMU_INC_STATS(mina_d);
                        DPFROMREG(ft, MIPSInst_FT(ir));
                        DPFROMREG(fs, MIPSInst_FS(ir));
                        rv.d = ieee754dp_fmina(fs, ft);
@@ -2165,6 +2252,7 @@ copcsr:
                        if (!cpu_has_mips_r6)
                                return SIGILL;
 
+                       MIPS_FPU_EMU_INC_STATS(max_d);
                        DPFROMREG(ft, MIPSInst_FT(ir));
                        DPFROMREG(fs, MIPSInst_FS(ir));
                        rv.d = ieee754dp_fmax(fs, ft);
@@ -2177,6 +2265,7 @@ copcsr:
                        if (!cpu_has_mips_r6)
                                return SIGILL;
 
+                       MIPS_FPU_EMU_INC_STATS(maxa_d);
                        DPFROMREG(ft, MIPSInst_FT(ir));
                        DPFROMREG(fs, MIPSInst_FS(ir));
                        rv.d = ieee754dp_fmaxa(fs, ft);
@@ -2184,15 +2273,18 @@ copcsr:
                }
 
                case fabs_op:
+                       MIPS_FPU_EMU_INC_STATS(abs_d);
                        handler.u = ieee754dp_abs;
                        goto dcopuop;
 
                case fneg_op:
+                       MIPS_FPU_EMU_INC_STATS(neg_d);
                        handler.u = ieee754dp_neg;
                        goto dcopuop;
 
                case fmov_op:
                        /* an easy one */
+                       MIPS_FPU_EMU_INC_STATS(mov_d);
                        DPFROMREG(rv.d, MIPSInst_FS(ir));
                        goto copcsr;
 
@@ -2212,6 +2304,7 @@ dcopuop:
                 * unary conv ops
                 */
                case fcvts_op:
+                       MIPS_FPU_EMU_INC_STATS(cvt_s_d);
                        DPFROMREG(fs, MIPSInst_FS(ir));
                        rv.s = ieee754sp_fdp(fs);
                        rfmt = s_fmt;
@@ -2221,6 +2314,7 @@ dcopuop:
                        return SIGILL;  /* not defined */
 
                case fcvtw_op:
+                       MIPS_FPU_EMU_INC_STATS(cvt_w_d);
                        DPFROMREG(fs, MIPSInst_FS(ir));
                        rv.w = ieee754dp_tint(fs);      /* wrong */
                        rfmt = w_fmt;
@@ -2233,6 +2327,15 @@ dcopuop:
                        if (!cpu_has_mips_2_3_4_5_r)
                                return SIGILL;
 
+                       if (MIPSInst_FUNC(ir) == fceil_op)
+                               MIPS_FPU_EMU_INC_STATS(ceil_w_d);
+                       if (MIPSInst_FUNC(ir) == ffloor_op)
+                               MIPS_FPU_EMU_INC_STATS(floor_w_d);
+                       if (MIPSInst_FUNC(ir) == fround_op)
+                               MIPS_FPU_EMU_INC_STATS(round_w_d);
+                       if (MIPSInst_FUNC(ir) == ftrunc_op)
+                               MIPS_FPU_EMU_INC_STATS(trunc_w_d);
+
                        oldrm = ieee754_csr.rm;
                        DPFROMREG(fs, MIPSInst_FS(ir));
                        ieee754_csr.rm = MIPSInst_FUNC(ir);
@@ -2241,10 +2344,23 @@ dcopuop:
                        rfmt = w_fmt;
                        goto copcsr;
 
+               case fsel_op:
+                       if (!cpu_has_mips_r6)
+                               return SIGILL;
+
+                       MIPS_FPU_EMU_INC_STATS(sel_d);
+                       DPFROMREG(fd, MIPSInst_FD(ir));
+                       if (fd.bits & 0x1)
+                               DPFROMREG(rv.d, MIPSInst_FT(ir));
+                       else
+                               DPFROMREG(rv.d, MIPSInst_FS(ir));
+                       break;
+
                case fcvtl_op:
                        if (!cpu_has_mips_3_4_5_64_r2_r6)
                                return SIGILL;
 
+                       MIPS_FPU_EMU_INC_STATS(cvt_l_d);
                        DPFROMREG(fs, MIPSInst_FS(ir));
                        rv.l = ieee754dp_tlong(fs);
                        rfmt = l_fmt;
@@ -2257,6 +2373,15 @@ dcopuop:
                        if (!cpu_has_mips_3_4_5_64_r2_r6)
                                return SIGILL;
 
+                       if (MIPSInst_FUNC(ir) == fceill_op)
+                               MIPS_FPU_EMU_INC_STATS(ceil_l_d);
+                       if (MIPSInst_FUNC(ir) == ffloorl_op)
+                               MIPS_FPU_EMU_INC_STATS(floor_l_d);
+                       if (MIPSInst_FUNC(ir) == froundl_op)
+                               MIPS_FPU_EMU_INC_STATS(round_l_d);
+                       if (MIPSInst_FUNC(ir) == ftruncl_op)
+                               MIPS_FPU_EMU_INC_STATS(trunc_l_d);
+
                        oldrm = ieee754_csr.rm;
                        DPFROMREG(fs, MIPSInst_FS(ir));
                        ieee754_csr.rm = MIPSInst_FUNC(ir);
@@ -2267,9 +2392,10 @@ dcopuop:
 
                default:
                        if (!NO_R6EMU && MIPSInst_FUNC(ir) >= fcmp_op) {
-                               unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op;
+                               unsigned int cmpop;
                                union ieee754dp fs, ft;
 
+                               cmpop = MIPSInst_FUNC(ir) - fcmp_op;
                                DPFROMREG(fs, MIPSInst_FS(ir));
                                DPFROMREG(ft, MIPSInst_FT(ir));
                                rv.w = ieee754dp_cmp(fs, ft,
@@ -2298,12 +2424,14 @@ dcopuop:
                switch (MIPSInst_FUNC(ir)) {
                case fcvts_op:
                        /* convert word to single precision real */
+                       MIPS_FPU_EMU_INC_STATS(cvt_s_w);
                        SPFROMREG(fs, MIPSInst_FS(ir));
                        rv.s = ieee754sp_fint(fs.bits);
                        rfmt = s_fmt;
                        goto copcsr;
                case fcvtd_op:
                        /* convert word to double precision real */
+                       MIPS_FPU_EMU_INC_STATS(cvt_d_w);
                        SPFROMREG(fs, MIPSInst_FS(ir));
                        rv.d = ieee754dp_fint(fs.bits);
                        rfmt = d_fmt;
@@ -2323,6 +2451,90 @@ dcopuop:
                            (MIPSInst_FUNC(ir) & 0x20))
                                return SIGILL;
 
+                       if (!sig) {
+                               if (!(MIPSInst_FUNC(ir) & PREDICATE_BIT)) {
+                                       switch (cmpop) {
+                                       case 0:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_af_s);
+                                       break;
+                                       case 1:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_un_s);
+                                       break;
+                                       case 2:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_eq_s);
+                                       break;
+                                       case 3:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_ueq_s);
+                                       break;
+                                       case 4:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_lt_s);
+                                       break;
+                                       case 5:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_ult_s);
+                                       break;
+                                       case 6:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_le_s);
+                                       break;
+                                       case 7:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_ule_s);
+                                       break;
+                                       }
+                               } else {
+                                       switch (cmpop) {
+                                       case 1:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_or_s);
+                                       break;
+                                       case 2:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_une_s);
+                                       break;
+                                       case 3:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_ne_s);
+                                       break;
+                                       }
+                               }
+                       } else {
+                               if (!(MIPSInst_FUNC(ir) & PREDICATE_BIT)) {
+                                       switch (cmpop) {
+                                       case 0:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_saf_s);
+                                       break;
+                                       case 1:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_sun_s);
+                                       break;
+                                       case 2:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_seq_s);
+                                       break;
+                                       case 3:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_sueq_s);
+                                       break;
+                                       case 4:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_slt_s);
+                                       break;
+                                       case 5:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_sult_s);
+                                       break;
+                                       case 6:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_sle_s);
+                                       break;
+                                       case 7:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_sule_s);
+                                       break;
+                                       }
+                               } else {
+                                       switch (cmpop) {
+                                       case 1:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_sor_s);
+                                       break;
+                                       case 2:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_sune_s);
+                                       break;
+                                       case 3:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_sne_s);
+                                       break;
+                                       }
+                               }
+                       }
+
                        /* fmt is w_fmt for single precision so fix it */
                        rfmt = s_fmt;
                        /* default to false */
@@ -2366,6 +2578,7 @@ dcopuop:
                        break;
                        }
                }
+               break;
        }
 
        case l_fmt:
@@ -2378,11 +2591,13 @@ dcopuop:
                switch (MIPSInst_FUNC(ir)) {
                case fcvts_op:
                        /* convert long to single precision real */
+                       MIPS_FPU_EMU_INC_STATS(cvt_s_l);
                        rv.s = ieee754sp_flong(bits);
                        rfmt = s_fmt;
                        goto copcsr;
                case fcvtd_op:
                        /* convert long to double precision real */
+                       MIPS_FPU_EMU_INC_STATS(cvt_d_l);
                        rv.d = ieee754dp_flong(bits);
                        rfmt = d_fmt;
                        goto copcsr;
@@ -2396,6 +2611,90 @@ dcopuop:
                            (MIPSInst_FUNC(ir) & 0x20))
                                return SIGILL;
 
+                       if (!sig) {
+                               if (!(MIPSInst_FUNC(ir) & PREDICATE_BIT)) {
+                                       switch (cmpop) {
+                                       case 0:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_af_d);
+                                       break;
+                                       case 1:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_un_d);
+                                       break;
+                                       case 2:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_eq_d);
+                                       break;
+                                       case 3:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_ueq_d);
+                                       break;
+                                       case 4:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_lt_d);
+                                       break;
+                                       case 5:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_ult_d);
+                                       break;
+                                       case 6:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_le_d);
+                                       break;
+                                       case 7:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_ule_d);
+                                       break;
+                                       }
+                               } else {
+                                       switch (cmpop) {
+                                       case 1:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_or_d);
+                                       break;
+                                       case 2:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_une_d);
+                                       break;
+                                       case 3:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_ne_d);
+                                       break;
+                                       }
+                               }
+                       } else {
+                               if (!(MIPSInst_FUNC(ir) & PREDICATE_BIT)) {
+                                       switch (cmpop) {
+                                       case 0:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_saf_d);
+                                       break;
+                                       case 1:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_sun_d);
+                                       break;
+                                       case 2:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_seq_d);
+                                       break;
+                                       case 3:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_sueq_d);
+                                       break;
+                                       case 4:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_slt_d);
+                                       break;
+                                       case 5:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_sult_d);
+                                       break;
+                                       case 6:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_sle_d);
+                                       break;
+                                       case 7:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_sule_d);
+                                       break;
+                                       }
+                               } else {
+                                       switch (cmpop) {
+                                       case 1:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_sor_d);
+                                       break;
+                                       case 2:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_sune_d);
+                                       break;
+                                       case 3:
+                                       MIPS_FPU_EMU_INC_STATS(cmp_sne_d);
+                                       break;
+                                       }
+                               }
+                       }
+
                        /* fmt is l_fmt for double precision so fix it */
                        rfmt = d_fmt;
                        /* default to false */
@@ -2439,6 +2738,8 @@ dcopuop:
                        break;
                        }
                }
+               break;
+
        default:
                return SIGILL;
        }
index 8954ef0..678de20 100644 (file)
@@ -104,8 +104,7 @@ union ieee754dp ieee754dp_add(union ieee754dp x, union ieee754dp y)
 
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
                DPDNORMX;
-
-               /* FALL THROUGH */
+               /* fall through */
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
                DPDNORMY;
index f4746f7..3063ae3 100644 (file)
@@ -103,6 +103,7 @@ union ieee754dp ieee754dp_div(union ieee754dp x, union ieee754dp y)
 
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
                DPDNORMX;
+               /* fall through */
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
                DPDNORMY;
index 5bec64f..d1f984b 100644 (file)
@@ -96,6 +96,7 @@ union ieee754dp ieee754dp_fmax(union ieee754dp x, union ieee754dp y)
 
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
                DPDNORMX;
+               /* fall through */
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
                DPDNORMY;
@@ -224,6 +225,7 @@ union ieee754dp ieee754dp_fmaxa(union ieee754dp x, union ieee754dp y)
 
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
                DPDNORMX;
+               /* fall through */
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
                DPDNORMY;
index a287b23..f98b961 100644 (file)
@@ -96,6 +96,7 @@ union ieee754dp ieee754dp_fmin(union ieee754dp x, union ieee754dp y)
 
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
                DPDNORMX;
+               /* fall through */
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
                DPDNORMY;
@@ -224,6 +225,7 @@ union ieee754dp ieee754dp_fmina(union ieee754dp x, union ieee754dp y)
 
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
                DPDNORMX;
+               /* fall through */
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
                DPDNORMY;
index 119eda9..7ea2f82 100644 (file)
 
 #include "ieee754dp.h"
 
-union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x,
-                               union ieee754dp y)
+
+/* 128 bits shift right logical with rounding. */
+static void srl128(u64 *hptr, u64 *lptr, int count)
+{
+       u64 low;
+
+       if (count >= 128) {
+               *lptr = *hptr != 0 || *lptr != 0;
+               *hptr = 0;
+       } else if (count >= 64) {
+               if (count == 64) {
+                       *lptr = *hptr | (*lptr != 0);
+               } else {
+                       low = *lptr;
+                       *lptr = *hptr >> (count - 64);
+                       *lptr |= (*hptr << (128 - count)) != 0 || low != 0;
+               }
+               *hptr = 0;
+       } else {
+               low = *lptr;
+               *lptr = low >> count | *hptr << (64 - count);
+               *lptr |= (low << (64 - count)) != 0;
+               *hptr = *hptr >> count;
+       }
+}
+
+static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x,
+                                union ieee754dp y, enum maddf_flags flags)
 {
        int re;
        int rs;
-       u64 rm;
-       unsigned lxm;
-       unsigned hxm;
-       unsigned lym;
-       unsigned hym;
+       unsigned int lxm;
+       unsigned int hxm;
+       unsigned int lym;
+       unsigned int hym;
        u64 lrm;
        u64 hrm;
+       u64 lzm;
+       u64 hzm;
        u64 t;
        u64 at;
        int s;
 
        COMPXDP;
        COMPYDP;
-
-       u64 zm; int ze; int zs __maybe_unused; int zc;
+       COMPZDP;
 
        EXPLODEXDP;
        EXPLODEYDP;
-       EXPLODEDP(z, zc, zs, ze, zm)
+       EXPLODEZDP;
 
        FLUSHXDP;
        FLUSHYDP;
-       FLUSHDP(z, zc, zs, ze, zm);
+       FLUSHZDP;
 
        ieee754_clearcx();
 
-       switch (zc) {
-       case IEEE754_CLASS_SNAN:
-               ieee754_setcx(IEEE754_INVALID_OPERATION);
+       /*
+        * Handle the cases when at least one of x, y or z is a NaN.
+        * Order of precedence is sNaN, qNaN and z, x, y.
+        */
+       if (zc == IEEE754_CLASS_SNAN)
                return ieee754dp_nanxcpt(z);
-       case IEEE754_CLASS_DNORM:
-               DPDNORMx(zm, ze);
-       /* QNAN is handled separately below */
-       }
-
-       switch (CLPAIR(xc, yc)) {
-       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
-       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
-       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
-       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
-       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
-               return ieee754dp_nanxcpt(y);
-
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
+       if (xc == IEEE754_CLASS_SNAN)
                return ieee754dp_nanxcpt(x);
-
-       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
-       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
-       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
-       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
+       if (yc == IEEE754_CLASS_SNAN)
+               return ieee754dp_nanxcpt(y);
+       if (zc == IEEE754_CLASS_QNAN)
+               return z;
+       if (xc == IEEE754_CLASS_QNAN)
+               return x;
+       if (yc == IEEE754_CLASS_QNAN)
                return y;
 
-       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
-       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
-       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
-       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
-       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
-               return x;
+       if (zc == IEEE754_CLASS_DNORM)
+               DPDNORMZ;
+       /* ZERO z cases are handled separately below */
 
+       switch (CLPAIR(xc, yc)) {
 
        /*
         * Infinity handling
         */
        case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
-               if (zc == IEEE754_CLASS_QNAN)
-                       return z;
                ieee754_setcx(IEEE754_INVALID_OPERATION);
                return ieee754dp_indef();
 
@@ -99,9 +107,27 @@ union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x,
        case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
        case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
        case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
-               if (zc == IEEE754_CLASS_QNAN)
-                       return z;
-               return ieee754dp_inf(xs ^ ys);
+               if ((zc == IEEE754_CLASS_INF) &&
+                   ((!(flags & MADDF_NEGATE_PRODUCT) && (zs != (xs ^ ys))) ||
+                    ((flags & MADDF_NEGATE_PRODUCT) && (zs == (xs ^ ys))))) {
+                       /*
+                        * Cases of addition of infinities with opposite signs
+                        * or subtraction of infinities with same signs.
+                        */
+                       ieee754_setcx(IEEE754_INVALID_OPERATION);
+                       return ieee754dp_indef();
+               }
+               /*
+                * z is here either not an infinity, or an infinity having the
+                * same sign as product (x*y) (in case of MADDF.D instruction)
+                * or product -(x*y) (in MSUBF.D case). The result must be an
+                * infinity, and its sign is determined only by the value of
+                * (flags & MADDF_NEGATE_PRODUCT) and the signs of x and y.
+                */
+               if (flags & MADDF_NEGATE_PRODUCT)
+                       return ieee754dp_inf(1 ^ (xs ^ ys));
+               else
+                       return ieee754dp_inf(xs ^ ys);
 
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
@@ -110,34 +136,45 @@ union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x,
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
                if (zc == IEEE754_CLASS_INF)
                        return ieee754dp_inf(zs);
-               /* Multiplication is 0 so just return z */
+               if (zc == IEEE754_CLASS_ZERO) {
+                       /* Handle cases +0 + (-0) and similar ones. */
+                       if ((!(flags & MADDF_NEGATE_PRODUCT)
+                                       && (zs == (xs ^ ys))) ||
+                           ((flags & MADDF_NEGATE_PRODUCT)
+                                       && (zs != (xs ^ ys))))
+                               /*
+                                * Cases of addition of zeros of equal signs
+                                * or subtraction of zeroes of opposite signs.
+                                * The sign of the resulting zero is in any
+                                * such case determined only by the sign of z.
+                                */
+                               return z;
+
+                       return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD);
+               }
+               /* x*y is here 0, and z is not 0, so just return z */
                return z;
 
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
                DPDNORMX;
+               /* fall through */
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
-               if (zc == IEEE754_CLASS_QNAN)
-                       return z;
-               else if (zc == IEEE754_CLASS_INF)
+               if (zc == IEEE754_CLASS_INF)
                        return ieee754dp_inf(zs);
                DPDNORMY;
                break;
 
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
-               if (zc == IEEE754_CLASS_QNAN)
-                       return z;
-               else if (zc == IEEE754_CLASS_INF)
+               if (zc == IEEE754_CLASS_INF)
                        return ieee754dp_inf(zs);
                DPDNORMX;
                break;
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
-               if (zc == IEEE754_CLASS_QNAN)
-                       return z;
-               else if (zc == IEEE754_CLASS_INF)
+               if (zc == IEEE754_CLASS_INF)
                        return ieee754dp_inf(zs);
-               /* fall through to real computations */
+               /* continue to real computations */
        }
 
        /* Finally get to do some computation */
@@ -154,18 +191,17 @@ union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x,
 
        re = xe + ye;
        rs = xs ^ ys;
+       if (flags & MADDF_NEGATE_PRODUCT)
+               rs ^= 1;
 
        /* shunt to top of word */
        xm <<= 64 - (DP_FBITS + 1);
        ym <<= 64 - (DP_FBITS + 1);
 
        /*
-        * Multiply 32 bits xm, ym to give high 32 bits rm with stickness.
+        * Multiply 64 bits xm and ym to give 128 bits result in hrm:lrm.
         */
 
-       /* 32 * 32 => 64 */
-#define DPXMULT(x, y)  ((u64)(x) * (u64)y)
-
        lxm = xm;
        hxm = xm >> 32;
        lym = ym;
@@ -190,76 +226,120 @@ union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x,
 
        hrm = hrm + (t >> 32);
 
-       rm = hrm | (lrm != 0);
-
-       /*
-        * Sticky shift down to normal rounding precision.
-        */
-       if ((s64) rm < 0) {
-               rm = (rm >> (64 - (DP_FBITS + 1 + 3))) |
-                    ((rm << (DP_FBITS + 1 + 3)) != 0);
-                       re++;
-       } else {
-               rm = (rm >> (64 - (DP_FBITS + 1 + 3 + 1))) |
-                    ((rm << (DP_FBITS + 1 + 3 + 1)) != 0);
+       /* Put explicit bit at bit 126 if necessary */
+       if ((int64_t)hrm < 0) {
+               lrm = (hrm << 63) | (lrm >> 1);
+               hrm = hrm >> 1;
+               re++;
        }
-       assert(rm & (DP_HIDDEN_BIT << 3));
 
-       /* And now the addition */
-       assert(zm & DP_HIDDEN_BIT);
+       assert(hrm & (1 << 62));
 
-       /*
-        * Provide guard,round and stick bit space.
-        */
-       zm <<= 3;
+       if (zc == IEEE754_CLASS_ZERO) {
+               /*
+                * Move explicit bit from bit 126 to bit 55 since the
+                * ieee754dp_format code expects the mantissa to be
+                * 56 bits wide (53 + 3 rounding bits).
+                */
+               srl128(&hrm, &lrm, (126 - 55));
+               return ieee754dp_format(rs, re, lrm);
+       }
+
+       /* Move explicit bit from bit 52 to bit 126 */
+       lzm = 0;
+       hzm = zm << 10;
+       assert(hzm & (1 << 62));
 
+       /* Make the exponents the same */
        if (ze > re) {
                /*
                 * Have to shift y fraction right to align.
                 */
                s = ze - re;
-               rm = XDPSRS(rm, s);
+               srl128(&hrm, &lrm, s);
                re += s;
        } else if (re > ze) {
                /*
                 * Have to shift x fraction right to align.
                 */
                s = re - ze;
-               zm = XDPSRS(zm, s);
+               srl128(&hzm, &lzm, s);
                ze += s;
        }
        assert(ze == re);
        assert(ze <= DP_EMAX);
 
+       /* Do the addition */
        if (zs == rs) {
                /*
-                * Generate 28 bit result of adding two 27 bit numbers
-                * leaving result in xm, xs and xe.
+                * Generate 128 bit result by adding two 127 bit numbers
+                * leaving result in hzm:lzm, zs and ze.
                 */
-               zm = zm + rm;
-
-               if (zm >> (DP_FBITS + 1 + 3)) { /* carry out */
-                       zm = XDPSRS1(zm);
+               hzm = hzm + hrm + (lzm > (lzm + lrm));
+               lzm = lzm + lrm;
+               if ((int64_t)hzm < 0) {        /* carry out */
+                       srl128(&hzm, &lzm, 1);
                        ze++;
                }
        } else {
-               if (zm >= rm) {
-                       zm = zm - rm;
+               if (hzm > hrm || (hzm == hrm && lzm >= lrm)) {
+                       hzm = hzm - hrm - (lzm < lrm);
+                       lzm = lzm - lrm;
                } else {
-                       zm = rm - zm;
+                       hzm = hrm - hzm - (lrm < lzm);
+                       lzm = lrm - lzm;
                        zs = rs;
                }
-               if (zm == 0)
+               if (lzm == 0 && hzm == 0)
                        return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD);
 
                /*
-                * Normalize to rounding precision.
+                * Put explicit bit at bit 126 if necessary.
                 */
-               while ((zm >> (DP_FBITS + 3)) == 0) {
-                       zm <<= 1;
-                       ze--;
+               if (hzm == 0) {
+                       /* left shift by 63 or 64 bits */
+                       if ((int64_t)lzm < 0) {
+                               /* MSB of lzm is the explicit bit */
+                               hzm = lzm >> 1;
+                               lzm = lzm << 63;
+                               ze -= 63;
+                       } else {
+                               hzm = lzm;
+                               lzm = 0;
+                               ze -= 64;
+                       }
+               }
+
+               t = 0;
+               while ((hzm >> (62 - t)) == 0)
+                       t++;
+
+               assert(t <= 62);
+               if (t) {
+                       hzm = hzm << t | lzm >> (64 - t);
+                       lzm = lzm << t;
+                       ze -= t;
                }
        }
 
-       return ieee754dp_format(zs, ze, zm);
+       /*
+        * Move explicit bit from bit 126 to bit 55 since the
+        * ieee754dp_format code expects the mantissa to be
+        * 56 bits wide (53 + 3 rounding bits).
+        */
+       srl128(&hzm, &lzm, (126 - 55));
+
+       return ieee754dp_format(zs, ze, lzm);
+}
+
+union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x,
+                               union ieee754dp y)
+{
+       return _dp_maddf(z, x, y, 0);
+}
+
+union ieee754dp ieee754dp_msubf(union ieee754dp z, union ieee754dp x,
+                               union ieee754dp y)
+{
+       return _dp_maddf(z, x, y, MADDF_NEGATE_PRODUCT);
 }
diff --git a/arch/mips/math-emu/dp_msubf.c b/arch/mips/math-emu/dp_msubf.c
deleted file mode 100644 (file)
index 1224126..0000000
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * IEEE754 floating point arithmetic
- * double precision: MSUB.f (Fused Multiply Subtract)
- * MSUBF.fmt: FPR[fd] = FPR[fd] - (FPR[fs] x FPR[ft])
- *
- * MIPS floating point support
- * Copyright (C) 2015 Imagination Technologies, Ltd.
- * Author: Markos Chandras <markos.chandras@imgtec.com>
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License as published by the
- *  Free Software Foundation; version 2 of the License.
- */
-
-#include "ieee754dp.h"
-
-union ieee754dp ieee754dp_msubf(union ieee754dp z, union ieee754dp x,
-                               union ieee754dp y)
-{
-       int re;
-       int rs;
-       u64 rm;
-       unsigned lxm;
-       unsigned hxm;
-       unsigned lym;
-       unsigned hym;
-       u64 lrm;
-       u64 hrm;
-       u64 t;
-       u64 at;
-       int s;
-
-       COMPXDP;
-       COMPYDP;
-
-       u64 zm; int ze; int zs __maybe_unused; int zc;
-
-       EXPLODEXDP;
-       EXPLODEYDP;
-       EXPLODEDP(z, zc, zs, ze, zm)
-
-       FLUSHXDP;
-       FLUSHYDP;
-       FLUSHDP(z, zc, zs, ze, zm);
-
-       ieee754_clearcx();
-
-       switch (zc) {
-       case IEEE754_CLASS_SNAN:
-               ieee754_setcx(IEEE754_INVALID_OPERATION);
-               return ieee754dp_nanxcpt(z);
-       case IEEE754_CLASS_DNORM:
-               DPDNORMx(zm, ze);
-       /* QNAN is handled separately below */
-       }
-
-       switch (CLPAIR(xc, yc)) {
-       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
-       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
-       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
-       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
-       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
-               return ieee754dp_nanxcpt(y);
-
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
-               return ieee754dp_nanxcpt(x);
-
-       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
-       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
-       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
-       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
-               return y;
-
-       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
-       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
-       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
-       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
-       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
-               return x;
-
-
-       /*
-        * Infinity handling
-        */
-       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
-       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
-               if (zc == IEEE754_CLASS_QNAN)
-                       return z;
-               ieee754_setcx(IEEE754_INVALID_OPERATION);
-               return ieee754dp_indef();
-
-       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
-       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
-       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
-       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
-       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
-               if (zc == IEEE754_CLASS_QNAN)
-                       return z;
-               return ieee754dp_inf(xs ^ ys);
-
-       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
-       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
-       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
-       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
-       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
-               if (zc == IEEE754_CLASS_INF)
-                       return ieee754dp_inf(zs);
-               /* Multiplication is 0 so just return z */
-               return z;
-
-       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
-               DPDNORMX;
-
-       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
-               if (zc == IEEE754_CLASS_QNAN)
-                       return z;
-               else if (zc == IEEE754_CLASS_INF)
-                       return ieee754dp_inf(zs);
-               DPDNORMY;
-               break;
-
-       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
-               if (zc == IEEE754_CLASS_QNAN)
-                       return z;
-               else if (zc == IEEE754_CLASS_INF)
-                       return ieee754dp_inf(zs);
-               DPDNORMX;
-               break;
-
-       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
-               if (zc == IEEE754_CLASS_QNAN)
-                       return z;
-               else if (zc == IEEE754_CLASS_INF)
-                       return ieee754dp_inf(zs);
-               /* fall through to real computations */
-       }
-
-       /* Finally get to do some computation */
-
-       /*
-        * Do the multiplication bit first
-        *
-        * rm = xm * ym, re = xe + ye basically
-        *
-        * At this point xm and ym should have been normalized.
-        */
-       assert(xm & DP_HIDDEN_BIT);
-       assert(ym & DP_HIDDEN_BIT);
-
-       re = xe + ye;
-       rs = xs ^ ys;
-
-       /* shunt to top of word */
-       xm <<= 64 - (DP_FBITS + 1);
-       ym <<= 64 - (DP_FBITS + 1);
-
-       /*
-        * Multiply 32 bits xm, ym to give high 32 bits rm with stickness.
-        */
-
-       /* 32 * 32 => 64 */
-#define DPXMULT(x, y)  ((u64)(x) * (u64)y)
-
-       lxm = xm;
-       hxm = xm >> 32;
-       lym = ym;
-       hym = ym >> 32;
-
-       lrm = DPXMULT(lxm, lym);
-       hrm = DPXMULT(hxm, hym);
-
-       t = DPXMULT(lxm, hym);
-
-       at = lrm + (t << 32);
-       hrm += at < lrm;
-       lrm = at;
-
-       hrm = hrm + (t >> 32);
-
-       t = DPXMULT(hxm, lym);
-
-       at = lrm + (t << 32);
-       hrm += at < lrm;
-       lrm = at;
-
-       hrm = hrm + (t >> 32);
-
-       rm = hrm | (lrm != 0);
-
-       /*
-        * Sticky shift down to normal rounding precision.
-        */
-       if ((s64) rm < 0) {
-               rm = (rm >> (64 - (DP_FBITS + 1 + 3))) |
-                    ((rm << (DP_FBITS + 1 + 3)) != 0);
-                       re++;
-       } else {
-               rm = (rm >> (64 - (DP_FBITS + 1 + 3 + 1))) |
-                    ((rm << (DP_FBITS + 1 + 3 + 1)) != 0);
-       }
-       assert(rm & (DP_HIDDEN_BIT << 3));
-
-       /* And now the subtraction */
-
-       /* flip sign of r and handle as add */
-       rs ^= 1;
-
-       assert(zm & DP_HIDDEN_BIT);
-
-       /*
-        * Provide guard,round and stick bit space.
-        */
-       zm <<= 3;
-
-       if (ze > re) {
-               /*
-                * Have to shift y fraction right to align.
-                */
-               s = ze - re;
-               rm = XDPSRS(rm, s);
-               re += s;
-       } else if (re > ze) {
-               /*
-                * Have to shift x fraction right to align.
-                */
-               s = re - ze;
-               zm = XDPSRS(zm, s);
-               ze += s;
-       }
-       assert(ze == re);
-       assert(ze <= DP_EMAX);
-
-       if (zs == rs) {
-               /*
-                * Generate 28 bit result of adding two 27 bit numbers
-                * leaving result in xm, xs and xe.
-                */
-               zm = zm + rm;
-
-               if (zm >> (DP_FBITS + 1 + 3)) { /* carry out */
-                       zm = XDPSRS1(zm);
-                       ze++;
-               }
-       } else {
-               if (zm >= rm) {
-                       zm = zm - rm;
-               } else {
-                       zm = rm - zm;
-                       zs = rs;
-               }
-               if (zm == 0)
-                       return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD);
-
-               /*
-                * Normalize to rounding precision.
-                */
-               while ((zm >> (DP_FBITS + 3)) == 0) {
-                       zm <<= 1;
-                       ze--;
-               }
-       }
-
-       return ieee754dp_format(zs, ze, zm);
-}
index d0901f0..c34a6cd 100644 (file)
@@ -26,10 +26,10 @@ union ieee754dp ieee754dp_mul(union ieee754dp x, union ieee754dp y)
        int re;
        int rs;
        u64 rm;
-       unsigned lxm;
-       unsigned hxm;
-       unsigned lym;
-       unsigned hym;
+       unsigned int lxm;
+       unsigned int hxm;
+       unsigned int lym;
+       unsigned int hym;
        u64 lrm;
        u64 hrm;
        u64 t;
@@ -101,6 +101,7 @@ union ieee754dp ieee754dp_mul(union ieee754dp x, union ieee754dp y)
 
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
                DPDNORMX;
+               /* fall through */
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
                DPDNORMY;
@@ -125,12 +126,9 @@ union ieee754dp ieee754dp_mul(union ieee754dp x, union ieee754dp y)
        ym <<= 64 - (DP_FBITS + 1);
 
        /*
-        * Multiply 32 bits xm, ym to give high 32 bits rm with stickness.
+        * Multiply 64 bits xm, ym to give high 64 bits rm with stickness.
         */
 
-       /* 32 * 32 => 64 */
-#define DPXMULT(x, y)  ((u64)(x) * (u64)y)
-
        lxm = xm;
        hxm = xm >> 32;
        lym = ym;
@@ -163,7 +161,7 @@ union ieee754dp ieee754dp_mul(union ieee754dp x, union ieee754dp y)
        if ((s64) rm < 0) {
                rm = (rm >> (64 - (DP_FBITS + 1 + 3))) |
                     ((rm << (DP_FBITS + 1 + 3)) != 0);
-                       re++;
+               re++;
        } else {
                rm = (rm >> (64 - (DP_FBITS + 1 + 3 + 1))) |
                     ((rm << (DP_FBITS + 1 + 3 + 1)) != 0);
diff --git a/arch/mips/math-emu/dp_rint.c b/arch/mips/math-emu/dp_rint.c
new file mode 100644 (file)
index 0000000..c3b9077
--- /dev/null
@@ -0,0 +1,89 @@
+/* IEEE754 floating point arithmetic
+ * double precision: common utilities
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.
+ * Copyright (C) 2017 Imagination Technologies, Ltd.
+ * Author: Aleksandar Markovic <aleksandar.markovic@imgtec.com>
+ *
+ *  This program is free software; you can distribute 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 it will be useful, but WITHOUT
+ *  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.
+ */
+
+#include "ieee754dp.h"
+
+union ieee754dp ieee754dp_rint(union ieee754dp x)
+{
+       union ieee754dp ret;
+       u64 residue;
+       int sticky;
+       int round;
+       int odd;
+
+       COMPXDP;
+
+       ieee754_clearcx();
+
+       EXPLODEXDP;
+       FLUSHXDP;
+
+       if (xc == IEEE754_CLASS_SNAN)
+               return ieee754dp_nanxcpt(x);
+
+       if ((xc == IEEE754_CLASS_QNAN) ||
+           (xc == IEEE754_CLASS_INF) ||
+           (xc == IEEE754_CLASS_ZERO))
+               return x;
+
+       if (xe >= DP_FBITS)
+               return x;
+
+       if (xe < -1) {
+               residue = xm;
+               round = 0;
+               sticky = residue != 0;
+               xm = 0;
+       } else {
+               residue = xm << (64 - DP_FBITS + xe);
+               round = (residue >> 63) != 0;
+               sticky = (residue << 1) != 0;
+               xm >>= DP_FBITS - xe;
+       }
+
+       odd = (xm & 0x1) != 0x0;
+
+       switch (ieee754_csr.rm) {
+       case FPU_CSR_RN:        /* toward nearest */
+               if (round && (sticky || odd))
+                       xm++;
+               break;
+       case FPU_CSR_RZ:        /* toward zero */
+               break;
+       case FPU_CSR_RU:        /* toward +infinity */
+               if ((round || sticky) && !xs)
+                       xm++;
+               break;
+       case FPU_CSR_RD:        /* toward -infinity */
+               if ((round || sticky) && xs)
+                       xm++;
+               break;
+       }
+
+       if (round || sticky)
+               ieee754_setcx(IEEE754_INEXACT);
+
+       ret = ieee754dp_flong(xm);
+       DPSIGN(ret) = xs;
+
+       return ret;
+}
index 926d56b..eb96485 100644 (file)
 
 union ieee754dp ieee754dp_neg(union ieee754dp x)
 {
-       unsigned int oldrm;
        union ieee754dp y;
 
-       oldrm = ieee754_csr.rm;
-       ieee754_csr.rm = FPU_CSR_RD;
-       y = ieee754dp_sub(ieee754dp_zero(0), x);
-       ieee754_csr.rm = oldrm;
+       if (ieee754_csr.abs2008) {
+               y = x;
+               DPSIGN(y) = !DPSIGN(x);
+       } else {
+               unsigned int oldrm;
+
+               oldrm = ieee754_csr.rm;
+               ieee754_csr.rm = FPU_CSR_RD;
+               y = ieee754dp_sub(ieee754dp_zero(0), x);
+               ieee754_csr.rm = oldrm;
+       }
        return y;
 }
 
 union ieee754dp ieee754dp_abs(union ieee754dp x)
 {
-       unsigned int oldrm;
        union ieee754dp y;
 
-       oldrm = ieee754_csr.rm;
-       ieee754_csr.rm = FPU_CSR_RD;
-       if (DPSIGN(x))
-               y = ieee754dp_sub(ieee754dp_zero(0), x);
-       else
-               y = ieee754dp_add(ieee754dp_zero(0), x);
-       ieee754_csr.rm = oldrm;
+       if (ieee754_csr.abs2008) {
+               y = x;
+               DPSIGN(y) = 0;
+       } else {
+               unsigned int oldrm;
+
+               oldrm = ieee754_csr.rm;
+               ieee754_csr.rm = FPU_CSR_RD;
+               if (DPSIGN(x))
+                       y = ieee754dp_sub(ieee754dp_zero(0), x);
+               else
+                       y = ieee754dp_add(ieee754dp_zero(0), x);
+               ieee754_csr.rm = oldrm;
+       }
        return y;
 }
index cd5bc08..1d26c92 100644 (file)
@@ -21,7 +21,7 @@
 
 #include "ieee754dp.h"
 
-static const unsigned table[] = {
+static const unsigned int table[] = {
        0, 1204, 3062, 5746, 9193, 13348, 18162, 23592,
        29598, 36145, 43202, 50740, 58733, 67158, 75992,
        85215, 83599, 71378, 60428, 50647, 41945, 34246,
@@ -33,7 +33,7 @@ union ieee754dp ieee754dp_sqrt(union ieee754dp x)
 {
        struct _ieee754_csr oldcsr;
        union ieee754dp y, z, t;
-       unsigned scalx, yh;
+       unsigned int scalx, yh;
        COMPXDP;
 
        EXPLODEXDP;
@@ -91,7 +91,8 @@ union ieee754dp ieee754dp_sqrt(union ieee754dp x)
                scalx -= 256;
        }
 
-       y = x = builddp(0, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT);
+       x = builddp(0, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT);
+       y = x;
 
        /* magic initial approximation to almost 8 sig. bits */
        yh = y.bits >> 32;
@@ -108,7 +109,8 @@ union ieee754dp ieee754dp_sqrt(union ieee754dp x)
 
        /* triple to almost 56 sig. bits: y ~= sqrt(x) to within 1 ulp */
        /* t=y*y; z=t;  pt[n0]+=0x00100000; t+=z; z=(x-z)*y; */
-       z = t = ieee754dp_mul(y, y);
+       t = ieee754dp_mul(y, y);
+       z = t;
        t.bexp += 0x001;
        t = ieee754dp_add(t, z);
        z = ieee754dp_mul(ieee754dp_sub(x, z), y);
@@ -140,7 +142,7 @@ union ieee754dp ieee754dp_sqrt(union ieee754dp x)
                switch (oldcsr.rm) {
                case FPU_CSR_RU:
                        y.bits += 1;
-                       /* drop through */
+                       /* fall through */
                case FPU_CSR_RN:
                        t.bits += 1;
                        break;
index fc17a78..3cc48b8 100644 (file)
@@ -106,7 +106,7 @@ union ieee754dp ieee754dp_sub(union ieee754dp x, union ieee754dp y)
 
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
                DPDNORMX;
-               /* FALL THROUGH */
+               /* fall through */
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
                /* normalize ym,ye */
index 6ffc336..f398561 100644 (file)
@@ -38,10 +38,13 @@ int ieee754dp_tint(union ieee754dp x)
        switch (xc) {
        case IEEE754_CLASS_SNAN:
        case IEEE754_CLASS_QNAN:
-       case IEEE754_CLASS_INF:
                ieee754_setcx(IEEE754_INVALID_OPERATION);
                return ieee754si_indef();
 
+       case IEEE754_CLASS_INF:
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754si_overflow(xs);
+
        case IEEE754_CLASS_ZERO:
                return 0;
 
@@ -53,7 +56,7 @@ int ieee754dp_tint(union ieee754dp x)
                /* Set invalid. We will only use overflow for floating
                   point overflow */
                ieee754_setcx(IEEE754_INVALID_OPERATION);
-               return ieee754si_indef();
+               return ieee754si_overflow(xs);
        }
        /* oh gawd */
        if (xe > DP_FBITS) {
@@ -93,7 +96,7 @@ int ieee754dp_tint(union ieee754dp x)
                if ((xm >> 31) != 0 && (xs == 0 || xm != 0x80000000)) {
                        /* This can happen after rounding */
                        ieee754_setcx(IEEE754_INVALID_OPERATION);
-                       return ieee754si_indef();
+                       return ieee754si_overflow(xs);
                }
                if (round || sticky)
                        ieee754_setcx(IEEE754_INEXACT);
index 9cdc145..748fa10 100644 (file)
@@ -38,10 +38,13 @@ s64 ieee754dp_tlong(union ieee754dp x)
        switch (xc) {
        case IEEE754_CLASS_SNAN:
        case IEEE754_CLASS_QNAN:
-       case IEEE754_CLASS_INF:
                ieee754_setcx(IEEE754_INVALID_OPERATION);
                return ieee754di_indef();
 
+       case IEEE754_CLASS_INF:
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754di_overflow(xs);
+
        case IEEE754_CLASS_ZERO:
                return 0;
 
@@ -56,7 +59,7 @@ s64 ieee754dp_tlong(union ieee754dp x)
                /* Set invalid. We will only use overflow for floating
                   point overflow */
                ieee754_setcx(IEEE754_INVALID_OPERATION);
-               return ieee754di_indef();
+               return ieee754di_overflow(xs);
        }
        /* oh gawd */
        if (xe > DP_FBITS) {
@@ -97,7 +100,7 @@ s64 ieee754dp_tlong(union ieee754dp x)
                if ((xm >> 63) != 0) {
                        /* This can happen after rounding */
                        ieee754_setcx(IEEE754_INVALID_OPERATION);
-                       return ieee754di_indef();
+                       return ieee754di_overflow(xs);
                }
                if (round || sticky)
                        ieee754_setcx(IEEE754_INEXACT);
index cbb36c1..4a094f7 100644 (file)
@@ -1,3 +1,6 @@
+#include <linux/err.h>
+#include <linux/slab.h>
+
 #include <asm/branch.h>
 #include <asm/cacheflush.h>
 #include <asm/fpu_emulator.h>
 #include <asm/mipsregs.h>
 #include <asm/uaccess.h>
 
-#include "ieee754.h"
-
-/*
- * Emulate the arbritrary instruction ir at xcp->cp0_epc.  Required when
- * we have to emulate the instruction in a COP1 branch delay slot.  Do
- * not change cp0_epc due to the instruction
+/**
+ * struct emuframe - The 'emulation' frame structure
+ * @emul:      The instruction to 'emulate'.
+ * @badinst:   A break instruction to cause a return to the kernel.
  *
- * According to the spec:
- * 1) it shouldn't be a branch :-)
- * 2) it can be a COP instruction :-(
- * 3) if we are tring to run a protected memory space we must take
- *    special care on memory access instructions :-(
- */
-
-/*
- * "Trampoline" return routine to catch exception following
- *  execution of delay-slot instruction execution.
+ * This structure defines the frames placed within the delay slot emulation
+ * page in response to a call to mips_dsemul(). Each thread may be allocated
+ * only one frame at any given time. The kernel stores within it the
+ * instruction to be 'emulated' followed by a break instruction, then
+ * executes the frame in user mode. The break causes a trap to the kernel
+ * which leads to do_dsemulret() being called unless the instruction in
+ * @emul causes a trap itself, is a branch, or a signal is delivered to
+ * the thread. In these cases the allocated frame will either be reused by
+ * a subsequent delay slot 'emulation', or be freed during signal delivery or
+ * upon thread exit.
+ *
+ * This approach is used because:
+ *
+ * - Actually emulating all instructions isn't feasible. We would need to
+ *   be able to handle instructions from all revisions of the MIPS ISA,
+ *   all ASEs & all vendor instruction set extensions. This would be a
+ *   whole lot of work & continual maintenance burden as new instructions
+ *   are introduced, and in the case of some vendor extensions may not
+ *   even be possible. Thus we need to take the approach of actually
+ *   executing the instruction.
+ *
+ * - We must execute the instruction within user context. If we were to
+ *   execute the instruction in kernel mode then it would have access to
+ *   kernel resources without very careful checks, leaving us with a
+ *   high potential for security or stability issues to arise.
+ *
+ * - We used to place the frame on the users stack, but this requires
+ *   that the stack be executable. This is bad for security so the
+ *   per-process page is now used instead.
+ *
+ * - The instruction in @emul may be something entirely invalid for a
+ *   delay slot. The user may (intentionally or otherwise) place a branch
+ *   in a delay slot, or a kernel mode instruction, or something else
+ *   which generates an exception. Thus we can't rely upon the break in
+ *   @badinst always being hit. For this reason we track the index of the
+ *   frame allocated to each thread, allowing us to clean it up at later
+ *   points such as signal delivery or thread exit.
+ *
+ * - The user may generate a fake struct emuframe if they wish, invoking
+ *   the BRK_MEMU break instruction themselves. We must therefore not
+ *   trust that BRK_MEMU means there's actually a valid frame allocated
+ *   to the thread, and must not allow the user to do anything they
+ *   couldn't already.
  */
-
 struct emuframe {
        mips_instruction        emul;
        mips_instruction        badinst;
-       mips_instruction        cookie;
-       unsigned long           epc;
 };
 
-int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc)
-{
-       struct emuframe __user *fr;
-       int err;
-
-       if ((get_isa16_mode(regs->cp0_epc) && ((ir >> 16) == MM_NOP16)) ||
-               (ir == 0)) {
-               /* NOP is easy */
-               regs->cp0_epc = cpc;
-               clear_delay_slot(regs);
-               return 0;
-       }
+static const int emupage_frame_count = PAGE_SIZE / sizeof(struct emuframe);
 
-       pr_debug("dsemul %lx %lx\n", regs->cp0_epc, cpc);
+static inline __user struct emuframe *dsemul_page(void)
+{
+       return (__user struct emuframe *)STACK_TOP;
+}
 
-       /*
-        * The strategy is to push the instruction onto the user stack
-        * and put a trap after it which we can catch and jump to
-        * the required address any alternative apart from full
-        * instruction emulation!!.
-        *
-        * Algorithmics used a system call instruction, and
-        * borrowed that vector.  MIPS/Linux version is a bit
-        * more heavyweight in the interests of portability and
-        * multiprocessor support.  For Linux we generate a
-        * an unaligned access and force an address error exception.
-        *
-        * For embedded systems (stand-alone) we prefer to use a
-        * non-existing CP1 instruction. This prevents us from emulating
-        * branches, but gives us a cleaner interface to the exception
-        * handler (single entry point).
-        */
+static int alloc_emuframe(void)
+{
+       mm_context_t *mm_ctx = &current->mm->context;
+       int idx;
 
-       /* Ensure that the two instructions are in the same cache line */
-       fr = (struct emuframe __user *)
-               ((regs->regs[29] - sizeof(struct emuframe)) & ~0x7);
+retry:
+       spin_lock(&mm_ctx->bd_emupage_lock);
 
-       /* Verify that the stack pointer is not competely insane */
-       if (unlikely(!access_ok(VERIFY_WRITE, fr, sizeof(struct emuframe))))
-               return SIGBUS;
+       /* Ensure we have an allocation bitmap */
+       if (!mm_ctx->bd_emupage_allocmap) {
+               mm_ctx->bd_emupage_allocmap =
+                       kcalloc(BITS_TO_LONGS(emupage_frame_count),
+                                             sizeof(unsigned long),
+                               GFP_ATOMIC);
 
-       if (get_isa16_mode(regs->cp0_epc)) {
-               err = __put_user(ir >> 16, (u16 __user *)(&fr->emul));
-               err |= __put_user(ir & 0xffff, (u16 __user *)((long)(&fr->emul) + 2));
-               err |= __put_user(BREAK_MATH >> 16, (u16 __user *)(&fr->badinst));
-               err |= __put_user(BREAK_MATH & 0xffff, (u16 __user *)((long)(&fr->badinst) + 2));
-       } else {
-               err = __put_user(ir, &fr->emul);
-               err |= __put_user((mips_instruction)BREAK_MATH, &fr->badinst);
+               if (!mm_ctx->bd_emupage_allocmap) {
+                       idx = BD_EMUFRAME_NONE;
+                       goto out_unlock;
+               }
        }
 
-       err |= __put_user((mips_instruction)BD_COOKIE, &fr->cookie);
-       err |= __put_user(cpc, &fr->epc);
+       /* Attempt to allocate a single bit/frame */
+       idx = bitmap_find_free_region(mm_ctx->bd_emupage_allocmap,
+                                     emupage_frame_count, 0);
+       if (idx < 0) {
+               /*
+                * Failed to allocate a frame. We'll wait until one becomes
+                * available. We unlock the page so that other threads actually
+                * get the opportunity to free their frames, which means
+                * technically the result of bitmap_full may be incorrect.
+                * However the worst case is that we repeat all this and end up
+                * back here again.
+                */
+               spin_unlock(&mm_ctx->bd_emupage_lock);
+               if (!wait_event_killable(mm_ctx->bd_emupage_queue,
+                       !bitmap_full(mm_ctx->bd_emupage_allocmap,
+                                    emupage_frame_count)))
+                       goto retry;
 
-       if (unlikely(err)) {
-               MIPS_FPU_EMU_INC_STATS(errors);
-               return SIGBUS;
+               /* Received a fatal signal - just give in */
+               return BD_EMUFRAME_NONE;
        }
 
-       regs->cp0_epc = ((unsigned long) &fr->emul) |
-               get_isa16_mode(regs->cp0_epc);
+       /* Success! */
+       pr_debug("allocate emuframe %d to %d\n", idx, current->pid);
+out_unlock:
+       spin_unlock(&mm_ctx->bd_emupage_lock);
+       return idx;
+}
 
-       flush_cache_sigtramp((unsigned long)&fr->emul);
+static void free_emuframe(int idx, struct mm_struct *mm)
+{
+       mm_context_t *mm_ctx = &mm->context;
 
-       return 0;
+       spin_lock(&mm_ctx->bd_emupage_lock);
+
+       pr_debug("free emuframe %d from %d\n", idx, current->pid);
+       bitmap_clear(mm_ctx->bd_emupage_allocmap, idx, 1);
+
+       /* If some thread is waiting for a frame, now's its chance */
+       wake_up(&mm_ctx->bd_emupage_queue);
+
+       spin_unlock(&mm_ctx->bd_emupage_lock);
+}
+
+static bool within_emuframe(struct pt_regs *regs)
+{
+       unsigned long base = (unsigned long)dsemul_page();
+
+       if (regs->cp0_epc < base)
+               return false;
+       if (regs->cp0_epc >= (base + PAGE_SIZE))
+               return false;
+
+       return true;
+}
+
+bool dsemul_thread_cleanup(struct task_struct *tsk)
+{
+       int fr_idx;
+
+       /* Clear any allocated frame, retrieving its index */
+       fr_idx = atomic_xchg(&tsk->thread.bd_emu_frame, BD_EMUFRAME_NONE);
+
+       /* If no frame was allocated, we're done */
+       if (fr_idx == BD_EMUFRAME_NONE)
+               return false;
+
+       task_lock(tsk);
+
+       /* Free the frame that this thread had allocated */
+       if (tsk->mm)
+               free_emuframe(fr_idx, tsk->mm);
+
+       task_unlock(tsk);
+       return true;
 }
 
-int do_dsemulret(struct pt_regs *xcp)
+bool dsemul_thread_rollback(struct pt_regs *regs)
 {
        struct emuframe __user *fr;
-       unsigned long epc;
-       u32 insn, cookie;
-       int err = 0;
-       u16 instr[2];
+       int fr_idx;
 
-       fr = (struct emuframe __user *)
-               (msk_isa16_mode(xcp->cp0_epc) - sizeof(mips_instruction));
+       /* Do nothing if we're not executing from a frame */
+       if (!within_emuframe(regs))
+               return false;
 
-       /*
-        * If we can't even access the area, something is very wrong, but we'll
-        * leave that to the default handling
-        */
-       if (!access_ok(VERIFY_READ, fr, sizeof(struct emuframe)))
-               return 0;
+       /* Find the frame being executed */
+       fr_idx = atomic_read(&current->thread.bd_emu_frame);
+       if (fr_idx == BD_EMUFRAME_NONE)
+               return false;
+       fr = &dsemul_page()[fr_idx];
 
        /*
-        * Do some sanity checking on the stackframe:
-        *
-        *  - Is the instruction pointed to by the EPC an BREAK_MATH?
-        *  - Is the following memory word the BD_COOKIE?
+        * If the PC is at the emul instruction, roll back to the branch. If
+        * PC is at the badinst (break) instruction, we've already emulated the
+        * instruction so progress to the continue PC. If it's anything else
+        * then something is amiss & the user has branched into some other area
+        * of the emupage - we'll free the allocated frame anyway.
         */
-       if (get_isa16_mode(xcp->cp0_epc)) {
-               err = __get_user(instr[0], (u16 __user *)(&fr->badinst));
-               err |= __get_user(instr[1], (u16 __user *)((long)(&fr->badinst) + 2));
-               insn = (instr[0] << 16) | instr[1];
+       if (msk_isa16_mode(regs->cp0_epc) == (unsigned long)&fr->emul)
+               regs->cp0_epc = current->thread.bd_emu_branch_pc;
+       else if (msk_isa16_mode(regs->cp0_epc) == (unsigned long)&fr->badinst)
+               regs->cp0_epc = current->thread.bd_emu_cont_pc;
+
+       atomic_set(&current->thread.bd_emu_frame, BD_EMUFRAME_NONE);
+       free_emuframe(fr_idx, current->mm);
+       return true;
+}
+
+void dsemul_mm_cleanup(struct mm_struct *mm)
+{
+       mm_context_t *mm_ctx = &mm->context;
+
+       kfree(mm_ctx->bd_emupage_allocmap);
+}
+
+int mips_dsemul(struct pt_regs *regs, mips_instruction ir,
+               unsigned long branch_pc, unsigned long cont_pc)
+{
+       int isa16 = get_isa16_mode(regs->cp0_epc);
+       mips_instruction break_math;
+       struct emuframe __user *fr;
+       int err, fr_idx;
+
+       /* NOP is easy */
+       if (ir == 0)
+               return -1;
+
+       /* microMIPS instructions */
+       if (isa16) {
+               union mips_instruction insn = { .word = ir };
+
+               /* NOP16 aka MOVE16 $0, $0 */
+               if ((ir >> 16) == MM_NOP16)
+                       return -1;
+
+               /* ADDIUPC */
+               if (insn.mm_a_format.opcode == mm_addiupc_op) {
+                       unsigned int rs;
+                       s32 v;
+
+                       rs = (((insn.mm_a_format.rs + 0xe) & 0xf) + 2);
+                       v = regs->cp0_epc & ~3;
+                       v += insn.mm_a_format.simmediate << 2;
+                       regs->regs[rs] = (long)v;
+                       return -1;
+               }
+       }
+
+       pr_debug("dsemul 0x%08lx cont at 0x%08lx\n", regs->cp0_epc, cont_pc);
+
+       /* Allocate a frame if we don't already have one */
+       fr_idx = atomic_read(&current->thread.bd_emu_frame);
+       if (fr_idx == BD_EMUFRAME_NONE)
+               fr_idx = alloc_emuframe();
+       if (fr_idx == BD_EMUFRAME_NONE)
+               return SIGBUS;
+       fr = &dsemul_page()[fr_idx];
+
+       /* Retrieve the appropriately encoded break instruction */
+       break_math = BREAK_MATH(isa16);
+
+       /* Write the instructions to the frame */
+       if (isa16) {
+               err = __put_user(ir >> 16,
+                                (u16 __user *)(&fr->emul));
+               err |= __put_user(ir & 0xffff,
+                                 (u16 __user *)((long)(&fr->emul) + 2));
+               err |= __put_user(break_math >> 16,
+                                 (u16 __user *)(&fr->badinst));
+               err |= __put_user(break_math & 0xffff,
+                                 (u16 __user *)((long)(&fr->badinst) + 2));
        } else {
-               err = __get_user(insn, &fr->badinst);
+               err = __put_user(ir, &fr->emul);
+               err |= __put_user(break_math, &fr->badinst);
        }
-       err |= __get_user(cookie, &fr->cookie);
 
-       if (unlikely(err || (insn != BREAK_MATH) || (cookie != BD_COOKIE))) {
+       if (unlikely(err)) {
                MIPS_FPU_EMU_INC_STATS(errors);
-               return 0;
+               free_emuframe(fr_idx, current->mm);
+               return SIGBUS;
        }
 
-       /*
-        * At this point, we are satisfied that it's a BD emulation trap.  Yes,
-        * a user might have deliberately put two malformed and useless
-        * instructions in a row in his program, in which case he's in for a
-        * nasty surprise - the next instruction will be treated as a
-        * continuation address!  Alas, this seems to be the only way that we
-        * can handle signals, recursion, and longjmps() in the context of
-        * emulating the branch delay instruction.
-        */
+       /* Record the PC of the branch, PC to continue from & frame index */
+       current->thread.bd_emu_branch_pc = branch_pc;
+       current->thread.bd_emu_cont_pc = cont_pc;
+       atomic_set(&current->thread.bd_emu_frame, fr_idx);
 
-       pr_debug("dsemulret\n");
+       /* Change user register context to execute the frame */
+       regs->cp0_epc = (unsigned long)&fr->emul | isa16;
 
-       if (__get_user(epc, &fr->epc)) {                /* Saved EPC */
-               /* This is not a good situation to be in */
-               force_sig(SIGBUS, current);
+       /* Ensure the icache observes our newly written frame */
+       flush_cache_sigtramp((unsigned long)&fr->emul);
 
-               return 0;
+       return 0;
+}
+
+bool do_dsemulret(struct pt_regs *xcp)
+{
+       /* Cleanup the allocated frame, returning if there wasn't one */
+       if (!dsemul_thread_cleanup(current)) {
+               MIPS_FPU_EMU_INC_STATS(errors);
+               return false;
        }
 
        /* Set EPC to return to post-branch instruction */
-       xcp->cp0_epc = epc;
+       xcp->cp0_epc = current->thread.bd_emu_cont_pc;
+       pr_debug("dsemulret to 0x%08lx\n", xcp->cp0_epc);
        MIPS_FPU_EMU_INC_STATS(ds_emul);
-       return 1;
+       return true;
 }
index 8e97acb..e16ae7b 100644 (file)
@@ -59,7 +59,8 @@ const union ieee754dp __ieee754dp_spcvals[] = {
        DPCNST(1, 3,           0x4000000000000ULL),     /* - 10.0   */
        DPCNST(0, DP_EMAX + 1, 0x0000000000000ULL),     /* + infinity */
        DPCNST(1, DP_EMAX + 1, 0x0000000000000ULL),     /* - infinity */
-       DPCNST(0, DP_EMAX + 1, 0x7FFFFFFFFFFFFULL),     /* + indef quiet Nan */
+       DPCNST(0, DP_EMAX + 1, 0x7FFFFFFFFFFFFULL),     /* + ind legacy qNaN */
+       DPCNST(0, DP_EMAX + 1, 0x8000000000000ULL),     /* + indef 2008 qNaN */
        DPCNST(0, DP_EMAX,     0xFFFFFFFFFFFFFULL),     /* + max */
        DPCNST(1, DP_EMAX,     0xFFFFFFFFFFFFFULL),     /* - max */
        DPCNST(0, DP_EMIN,     0x0000000000000ULL),     /* + min normal */
@@ -82,7 +83,8 @@ const union ieee754sp __ieee754sp_spcvals[] = {
        SPCNST(1, 3,           0x200000),       /* - 10.0   */
        SPCNST(0, SP_EMAX + 1, 0x000000),       /* + infinity */
        SPCNST(1, SP_EMAX + 1, 0x000000),       /* - infinity */
-       SPCNST(0, SP_EMAX + 1, 0x3FFFFF),       /* + indef quiet Nan  */
+       SPCNST(0, SP_EMAX + 1, 0x3FFFFF),       /* + indef legacy quiet NaN */
+       SPCNST(0, SP_EMAX + 1, 0x400000),       /* + indef 2008 quiet NaN */
        SPCNST(0, SP_EMAX,     0x7FFFFF),       /* + max normal */
        SPCNST(1, SP_EMAX,     0x7FFFFF),       /* - max normal */
        SPCNST(0, SP_EMIN,     0x000000),       /* + min normal */
index df94720..e0eb7a9 100644 (file)
@@ -67,6 +67,7 @@ union ieee754sp ieee754sp_div(union ieee754sp x, union ieee754sp y);
 union ieee754sp ieee754sp_fint(int x);
 union ieee754sp ieee754sp_flong(s64 x);
 union ieee754sp ieee754sp_fdp(union ieee754dp x);
+union ieee754sp ieee754sp_rint(union ieee754sp x);
 
 int ieee754sp_tint(union ieee754sp x);
 s64 ieee754sp_tlong(union ieee754sp x);
@@ -101,6 +102,7 @@ union ieee754dp ieee754dp_neg(union ieee754dp x);
 union ieee754dp ieee754dp_fint(int x);
 union ieee754dp ieee754dp_flong(s64 x);
 union ieee754dp ieee754dp_fsp(union ieee754sp x);
+union ieee754dp ieee754dp_rint(union ieee754dp x);
 
 int ieee754dp_tint(union ieee754dp x);
 s64 ieee754dp_tlong(union ieee754dp x);
@@ -163,11 +165,12 @@ struct _ieee754_csr {
 };
 #define ieee754_csr (*(struct _ieee754_csr *)(&current->thread.fpu.fcr31))
 
-static inline unsigned ieee754_getrm(void)
+static inline unsigned int ieee754_getrm(void)
 {
        return (ieee754_csr.rm);
 }
-static inline unsigned ieee754_setrm(unsigned rm)
+
+static inline unsigned int ieee754_setrm(unsigned int rm)
 {
        return (ieee754_csr.rm = rm);
 }
@@ -175,14 +178,14 @@ static inline unsigned ieee754_setrm(unsigned rm)
 /*
  * get current exceptions
  */
-static inline unsigned ieee754_getcx(void)
+static inline unsigned int ieee754_getcx(void)
 {
        return (ieee754_csr.cx);
 }
 
 /* test for current exception condition
  */
-static inline int ieee754_cxtest(unsigned n)
+static inline int ieee754_cxtest(unsigned int n)
 {
        return (ieee754_csr.cx & n);
 }
@@ -190,21 +193,21 @@ static inline int ieee754_cxtest(unsigned n)
 /*
  * get sticky exceptions
  */
-static inline unsigned ieee754_getsx(void)
+static inline unsigned int ieee754_getsx(void)
 {
        return (ieee754_csr.sx);
 }
 
 /* clear sticky conditions
 */
-static inline unsigned ieee754_clrsx(void)
+static inline unsigned int ieee754_clrsx(void)
 {
        return (ieee754_csr.sx = 0);
 }
 
 /* test for sticky exception condition
  */
-static inline int ieee754_sxtest(unsigned n)
+static inline int ieee754_sxtest(unsigned int n)
 {
        return (ieee754_csr.sx & n);
 }
@@ -221,15 +224,16 @@ union ieee754dp ieee754dp_dump(char *s, union ieee754dp x);
 #define IEEE754_SPCVAL_NTEN            5       /* -10.0 */
 #define IEEE754_SPCVAL_PINFINITY       6       /* +inf */
 #define IEEE754_SPCVAL_NINFINITY       7       /* -inf */
-#define IEEE754_SPCVAL_INDEF           8       /* quiet NaN */
-#define IEEE754_SPCVAL_PMAX            9       /* +max norm */
-#define IEEE754_SPCVAL_NMAX            10      /* -max norm */
-#define IEEE754_SPCVAL_PMIN            11      /* +min norm */
-#define IEEE754_SPCVAL_NMIN            12      /* -min norm */
-#define IEEE754_SPCVAL_PMIND           13      /* +min denorm */
-#define IEEE754_SPCVAL_NMIND           14      /* -min denorm */
-#define IEEE754_SPCVAL_P1E31           15      /* + 1.0e31 */
-#define IEEE754_SPCVAL_P1E63           16      /* + 1.0e63 */
+#define IEEE754_SPCVAL_INDEF_LEG       8       /* legacy quiet NaN */
+#define IEEE754_SPCVAL_INDEF_2008      9       /* IEEE 754-2008 quiet NaN */
+#define IEEE754_SPCVAL_PMAX            10      /* +max norm */
+#define IEEE754_SPCVAL_NMAX            11      /* -max norm */
+#define IEEE754_SPCVAL_PMIN            12      /* +min norm */
+#define IEEE754_SPCVAL_NMIN            13      /* -min norm */
+#define IEEE754_SPCVAL_PMIND           14      /* +min denorm */
+#define IEEE754_SPCVAL_NMIND           15      /* -min denorm */
+#define IEEE754_SPCVAL_P1E31           16      /* + 1.0e31 */
+#define IEEE754_SPCVAL_P1E63           17      /* + 1.0e63 */
 
 extern const union ieee754dp __ieee754dp_spcvals[];
 extern const union ieee754sp __ieee754sp_spcvals[];
@@ -243,7 +247,8 @@ extern const union ieee754sp __ieee754sp_spcvals[];
 #define ieee754dp_zero(sn)     (ieee754dp_spcvals[IEEE754_SPCVAL_PZERO+(sn)])
 #define ieee754dp_one(sn)      (ieee754dp_spcvals[IEEE754_SPCVAL_PONE+(sn)])
 #define ieee754dp_ten(sn)      (ieee754dp_spcvals[IEEE754_SPCVAL_PTEN+(sn)])
-#define ieee754dp_indef()      (ieee754dp_spcvals[IEEE754_SPCVAL_INDEF])
+#define ieee754dp_indef()      (ieee754dp_spcvals[IEEE754_SPCVAL_INDEF_LEG + \
+                                                  ieee754_csr.nan2008])
 #define ieee754dp_max(sn)      (ieee754dp_spcvals[IEEE754_SPCVAL_PMAX+(sn)])
 #define ieee754dp_min(sn)      (ieee754dp_spcvals[IEEE754_SPCVAL_PMIN+(sn)])
 #define ieee754dp_mind(sn)     (ieee754dp_spcvals[IEEE754_SPCVAL_PMIND+(sn)])
@@ -254,7 +259,8 @@ extern const union ieee754sp __ieee754sp_spcvals[];
 #define ieee754sp_zero(sn)     (ieee754sp_spcvals[IEEE754_SPCVAL_PZERO+(sn)])
 #define ieee754sp_one(sn)      (ieee754sp_spcvals[IEEE754_SPCVAL_PONE+(sn)])
 #define ieee754sp_ten(sn)      (ieee754sp_spcvals[IEEE754_SPCVAL_PTEN+(sn)])
-#define ieee754sp_indef()      (ieee754sp_spcvals[IEEE754_SPCVAL_INDEF])
+#define ieee754sp_indef()      (ieee754sp_spcvals[IEEE754_SPCVAL_INDEF_LEG + \
+                                                  ieee754_csr.nan2008])
 #define ieee754sp_max(sn)      (ieee754sp_spcvals[IEEE754_SPCVAL_PMAX+(sn)])
 #define ieee754sp_min(sn)      (ieee754sp_spcvals[IEEE754_SPCVAL_PMIN+(sn)])
 #define ieee754sp_mind(sn)     (ieee754sp_spcvals[IEEE754_SPCVAL_PMIND+(sn)])
@@ -266,12 +272,25 @@ extern const union ieee754sp __ieee754sp_spcvals[];
  */
 static inline int ieee754si_indef(void)
 {
-       return INT_MAX;
+       return ieee754_csr.nan2008 ? 0 : INT_MAX;
 }
 
 static inline s64 ieee754di_indef(void)
 {
-       return S64_MAX;
+       return ieee754_csr.nan2008 ? 0 : S64_MAX;
+}
+
+/*
+ * Overflow integer value
+ */
+static inline int ieee754si_overflow(int xs)
+{
+       return ieee754_csr.nan2008 && xs ? INT_MIN : INT_MAX;
+}
+
+static inline s64 ieee754di_overflow(int xs)
+{
+       return ieee754_csr.nan2008 && xs ? S64_MIN : S64_MAX;
 }
 
 /* result types for xctx.rt */
index 522d843..465a034 100644 (file)
@@ -37,8 +37,11 @@ static inline int ieee754dp_isnan(union ieee754dp x)
 
 static inline int ieee754dp_issnan(union ieee754dp x)
 {
+       int qbit;
+
        assert(ieee754dp_isnan(x));
-       return (DPMANT(x) & DP_MBIT(DP_FBITS - 1)) == DP_MBIT(DP_FBITS - 1);
+       qbit = (DPMANT(x) & DP_MBIT(DP_FBITS - 1)) == DP_MBIT(DP_FBITS - 1);
+       return ieee754_csr.nan2008 ^ qbit;
 }
 
 
@@ -51,7 +54,15 @@ union ieee754dp __cold ieee754dp_nanxcpt(union ieee754dp r)
        assert(ieee754dp_issnan(r));
 
        ieee754_setcx(IEEE754_INVALID_OPERATION);
-       return ieee754dp_indef();
+       if (ieee754_csr.nan2008) {
+               DPMANT(r) |= DP_MBIT(DP_FBITS - 1);
+       } else {
+               DPMANT(r) &= ~DP_MBIT(DP_FBITS - 1);
+               if (!ieee754dp_isnan(r))
+                       DPMANT(r) |= DP_MBIT(DP_FBITS - 2);
+       }
+
+       return r;
 }
 
 static u64 ieee754dp_get_rounding(int sn, u64 xm)
@@ -89,7 +100,7 @@ union ieee754dp ieee754dp_format(int sn, int xe, u64 xm)
 {
        assert(xm);             /* we don't gen exact zeros (probably should) */
 
-       assert((xm >> (DP_FBITS + 1 + 3)) == 0);        /* no execess */
+       assert((xm >> (DP_FBITS + 1 + 3)) == 0);        /* no excess */
        assert(xm & (DP_HIDDEN_BIT << 3));
 
        if (xe < DP_EMIN) {
@@ -157,7 +168,7 @@ union ieee754dp ieee754dp_format(int sn, int xe, u64 xm)
        /* strip grs bits */
        xm >>= 3;
 
-       assert((xm >> (DP_FBITS + 1)) == 0);    /* no execess */
+       assert((xm >> (DP_FBITS + 1)) == 0);    /* no excess */
        assert(xe >= DP_EMIN);
 
        if (xe > DP_EMAX) {
@@ -190,7 +201,7 @@ union ieee754dp ieee754dp_format(int sn, int xe, u64 xm)
                        ieee754_setcx(IEEE754_UNDERFLOW);
                return builddp(sn, DP_EMIN - 1 + DP_EBIAS, xm);
        } else {
-               assert((xm >> (DP_FBITS + 1)) == 0);    /* no execess */
+               assert((xm >> (DP_FBITS + 1)) == 0);    /* no excess */
                assert(xm & DP_HIDDEN_BIT);
 
                return builddp(sn, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT);
index e2babd9..a56707b 100644 (file)
@@ -55,11 +55,15 @@ static inline int ieee754dp_finite(union ieee754dp x)
 #define XDPSRS1(v)     \
        (((v) >> 1) | ((v) & 1))
 
+/* 32bit * 32bit => 64bit unsigned integer multiplication */
+#define DPXMULT(x, y)  ((u64)(x) * (u64)y)
+
 /* convert denormal to normalized with extended exponent */
 #define DPDNORMx(m,e) \
        while ((m >> DP_FBITS) == 0) { m <<= 1; e--; }
 #define DPDNORMX       DPDNORMx(xm, xe)
 #define DPDNORMY       DPDNORMx(ym, ye)
+#define DPDNORMZ       DPDNORMx(zm, ze)
 
 static inline union ieee754dp builddp(int s, int bx, u64 m)
 {
index 6383e2c..06ac0e2 100644 (file)
 
 #define CLPAIR(x, y)   ((x)*6+(y))
 
+enum maddf_flags {
+       MADDF_NEGATE_PRODUCT    = 1 << 0,
+};
+
 static inline void ieee754_clearcx(void)
 {
        ieee754_csr.cx = 0;
@@ -50,10 +54,13 @@ static inline int ieee754_class_nan(int xc)
 }
 
 #define COMPXSP \
-       unsigned xm; int xe; int xs __maybe_unused; int xc
+       unsigned int xm; int xe; int xs __maybe_unused; int xc
 
 #define COMPYSP \
-       unsigned ym; int ye; int ys; int yc
+       unsigned int ym; int ye; int ys; int yc
+
+#define COMPZSP \
+       unsigned int zm; int ze; int zs; int zc
 
 #define EXPLODESP(v, vc, vs, ve, vm)                                   \
 {                                                                      \
@@ -63,10 +70,10 @@ static inline int ieee754_class_nan(int xc)
        if (ve == SP_EMAX+1+SP_EBIAS) {                                 \
                if (vm == 0)                                            \
                        vc = IEEE754_CLASS_INF;                         \
-               else if (vm & SP_MBIT(SP_FBITS-1))                      \
-                       vc = IEEE754_CLASS_SNAN;                        \
-               else                                                    \
+               else if (ieee754_csr.nan2008 ^ !(vm & SP_MBIT(SP_FBITS - 1))) \
                        vc = IEEE754_CLASS_QNAN;                        \
+               else                                                    \
+                       vc = IEEE754_CLASS_SNAN;                        \
        } else if (ve == SP_EMIN-1+SP_EBIAS) {                          \
                if (vm) {                                               \
                        ve = SP_EMIN;                                   \
@@ -81,6 +88,7 @@ static inline int ieee754_class_nan(int xc)
 }
 #define EXPLODEXSP EXPLODESP(x, xc, xs, xe, xm)
 #define EXPLODEYSP EXPLODESP(y, yc, ys, ye, ym)
+#define EXPLODEZSP EXPLODESP(z, zc, zs, ze, zm)
 
 
 #define COMPXDP \
@@ -89,6 +97,9 @@ static inline int ieee754_class_nan(int xc)
 #define COMPYDP \
        u64 ym; int ye; int ys; int yc
 
+#define COMPZDP \
+       u64 zm; int ze; int zs; int zc
+
 #define EXPLODEDP(v, vc, vs, ve, vm)                                   \
 {                                                                      \
        vm = DPMANT(v);                                                 \
@@ -97,10 +108,10 @@ static inline int ieee754_class_nan(int xc)
        if (ve == DP_EMAX+1+DP_EBIAS) {                                 \
                if (vm == 0)                                            \
                        vc = IEEE754_CLASS_INF;                         \
-               else if (vm & DP_MBIT(DP_FBITS-1))                      \
-                       vc = IEEE754_CLASS_SNAN;                        \
-               else                                                    \
+               else if (ieee754_csr.nan2008 ^ !(vm & DP_MBIT(DP_FBITS - 1))) \
                        vc = IEEE754_CLASS_QNAN;                        \
+               else                                                    \
+                       vc = IEEE754_CLASS_SNAN;                        \
        } else if (ve == DP_EMIN-1+DP_EBIAS) {                          \
                if (vm) {                                               \
                        ve = DP_EMIN;                                   \
@@ -115,6 +126,7 @@ static inline int ieee754_class_nan(int xc)
 }
 #define EXPLODEXDP EXPLODEDP(x, xc, xs, xe, xm)
 #define EXPLODEYDP EXPLODEDP(y, yc, ys, ye, ym)
+#define EXPLODEZDP EXPLODEDP(z, zc, zs, ze, zm)
 
 #define FLUSHDP(v, vc, vs, ve, vm)                                     \
        if (vc==IEEE754_CLASS_DNORM) {                                  \
@@ -140,7 +152,9 @@ static inline int ieee754_class_nan(int xc)
 
 #define FLUSHXDP FLUSHDP(x, xc, xs, xe, xm)
 #define FLUSHYDP FLUSHDP(y, yc, ys, ye, ym)
+#define FLUSHZDP FLUSHDP(z, zc, zs, ze, zm)
 #define FLUSHXSP FLUSHSP(x, xc, xs, xe, xm)
 #define FLUSHYSP FLUSHSP(y, yc, ys, ye, ym)
+#define FLUSHZSP FLUSHSP(z, zc, zs, ze, zm)
 
 #endif /* __IEEE754INT_H  */
index ca8e35e..8423e4c 100644 (file)
@@ -37,8 +37,11 @@ static inline int ieee754sp_isnan(union ieee754sp x)
 
 static inline int ieee754sp_issnan(union ieee754sp x)
 {
+       int qbit;
+
        assert(ieee754sp_isnan(x));
-       return SPMANT(x) & SP_MBIT(SP_FBITS - 1);
+       qbit = (SPMANT(x) & SP_MBIT(SP_FBITS - 1)) == SP_MBIT(SP_FBITS - 1);
+       return ieee754_csr.nan2008 ^ qbit;
 }
 
 
@@ -51,10 +54,18 @@ union ieee754sp __cold ieee754sp_nanxcpt(union ieee754sp r)
        assert(ieee754sp_issnan(r));
 
        ieee754_setcx(IEEE754_INVALID_OPERATION);
-       return ieee754sp_indef();
+       if (ieee754_csr.nan2008) {
+               SPMANT(r) |= SP_MBIT(SP_FBITS - 1);
+       } else {
+               SPMANT(r) &= ~SP_MBIT(SP_FBITS - 1);
+               if (!ieee754sp_isnan(r))
+                       SPMANT(r) |= SP_MBIT(SP_FBITS - 2);
+       }
+
+       return r;
 }
 
-static unsigned ieee754sp_get_rounding(int sn, unsigned xm)
+static unsigned int ieee754sp_get_rounding(int sn, unsigned int xm)
 {
        /* inexact must round of 3 bits
         */
@@ -85,11 +96,11 @@ static unsigned ieee754sp_get_rounding(int sn, unsigned xm)
  * xe is an unbiased exponent
  * xm is 3bit extended precision value.
  */
-union ieee754sp ieee754sp_format(int sn, int xe, unsigned xm)
+union ieee754sp ieee754sp_format(int sn, int xe, unsigned int xm)
 {
        assert(xm);             /* we don't gen exact zeros (probably should) */
 
-       assert((xm >> (SP_FBITS + 1 + 3)) == 0);        /* no execess */
+       assert((xm >> (SP_FBITS + 1 + 3)) == 0);        /* no excess */
        assert(xm & (SP_HIDDEN_BIT << 3));
 
        if (xe < SP_EMIN) {
@@ -130,7 +141,8 @@ union ieee754sp ieee754sp_format(int sn, int xe, unsigned xm)
                } else {
                        /* sticky right shift es bits
                         */
-                       SPXSRSXn(es);
+                       xm = XSPSRS(xm, es);
+                       xe += es;
                        assert((xm & (SP_HIDDEN_BIT << 3)) == 0);
                        assert(xe == SP_EMIN);
                }
@@ -155,7 +167,7 @@ union ieee754sp ieee754sp_format(int sn, int xe, unsigned xm)
        /* strip grs bits */
        xm >>= 3;
 
-       assert((xm >> (SP_FBITS + 1)) == 0);    /* no execess */
+       assert((xm >> (SP_FBITS + 1)) == 0);    /* no excess */
        assert(xe >= SP_EMIN);
 
        if (xe > SP_EMAX) {
@@ -188,7 +200,7 @@ union ieee754sp ieee754sp_format(int sn, int xe, unsigned xm)
                        ieee754_setcx(IEEE754_UNDERFLOW);
                return buildsp(sn, SP_EMIN - 1 + SP_EBIAS, xm);
        } else {
-               assert((xm >> (SP_FBITS + 1)) == 0);    /* no execess */
+               assert((xm >> (SP_FBITS + 1)) == 0);    /* no excess */
                assert(xm & SP_HIDDEN_BIT);
 
                return buildsp(sn, xe + SP_EBIAS, xm & ~SP_HIDDEN_BIT);
index 374a3f0..8c5a638 100644 (file)
@@ -45,28 +45,31 @@ static inline int ieee754sp_finite(union ieee754sp x)
        return SPBEXP(x) != SP_EMAX + 1 + SP_EBIAS;
 }
 
+/* 64 bit right shift with rounding */
+#define XSPSRS64(v, rs)                                                \
+       (((rs) >= 64) ? ((v) != 0) : ((v) >> (rs)) | ((v) << (64-(rs)) != 0))
+
 /* 3bit extended single precision sticky right shift */
-#define SPXSRSXn(rs)                                                   \
-       (xe += rs,                                                      \
-        xm = (rs > (SP_FBITS+3))?1:((xm) >> (rs)) | ((xm) << (32-(rs)) != 0))
+#define XSPSRS(v, rs)                                          \
+       ((rs > (SP_FBITS+3))?1:((v) >> (rs)) | ((v) << (32-(rs)) != 0))
 
-#define SPXSRSX1() \
-       (xe++, (xm = (xm >> 1) | (xm & 1)))
+#define XSPSRS1(m) \
+       ((m >> 1) | (m & 1))
 
-#define SPXSRSYn(rs)                                                           \
-       (ye+=rs,                                                                \
-        ym = (rs > (SP_FBITS+3))?1:((ym) >> (rs)) | ((ym) << (32-(rs)) != 0))
+#define SPXSRSX1() \
+       (xe++, (xm = XSPSRS1(xm)))
 
 #define SPXSRSY1() \
-       (ye++, (ym = (ym >> 1) | (ym & 1)))
+       (ye++, (ym = XSPSRS1(ym)))
 
 /* convert denormal to normalized with extended exponent */
 #define SPDNORMx(m,e) \
        while ((m >> SP_FBITS) == 0) { m <<= 1; e--; }
 #define SPDNORMX       SPDNORMx(xm, xe)
 #define SPDNORMY       SPDNORMx(ym, ye)
+#define SPDNORMZ       SPDNORMx(zm, ze)
 
-static inline union ieee754sp buildsp(int s, int bx, unsigned m)
+static inline union ieee754sp buildsp(int s, int bx, unsigned int m)
 {
        union ieee754sp r;
 
index be650ed..8c0ec15 100644 (file)
@@ -28,14 +28,190 @@ static int fpuemu_stat_get(void *data, u64 *val)
 }
 DEFINE_SIMPLE_ATTRIBUTE(fops_fpuemu_stat, fpuemu_stat_get, NULL, "%llu\n");
 
+/*
+ * Used to obtain names for a debugfs instruction counter, given field name
+ * in fpuemustats structure. For example, for input "cmp_sueq_d", the output
+ * would be "cmp.sueq.d". This is needed since dots are not allowed to be
+ * used in structure field names, and are, on the other hand, desired to be
+ * used in debugfs item names to be clearly associated to corresponding
+ * MIPS FPU instructions.
+ */
+static void adjust_instruction_counter_name(char *out_name, char *in_name)
+{
+       int i = 0;
+
+       strcpy(out_name, in_name);
+       while (in_name[i] != '\0') {
+               if (out_name[i] == '_')
+                       out_name[i] = '.';
+               i++;
+       }
+}
+
+static int fpuemustats_clear_show(struct seq_file *s, void *unused)
+{
+       __this_cpu_write((fpuemustats).emulated, 0);
+       __this_cpu_write((fpuemustats).loads, 0);
+       __this_cpu_write((fpuemustats).stores, 0);
+       __this_cpu_write((fpuemustats).branches, 0);
+       __this_cpu_write((fpuemustats).cp1ops, 0);
+       __this_cpu_write((fpuemustats).cp1xops, 0);
+       __this_cpu_write((fpuemustats).errors, 0);
+       __this_cpu_write((fpuemustats).ieee754_inexact, 0);
+       __this_cpu_write((fpuemustats).ieee754_underflow, 0);
+       __this_cpu_write((fpuemustats).ieee754_overflow, 0);
+       __this_cpu_write((fpuemustats).ieee754_zerodiv, 0);
+       __this_cpu_write((fpuemustats).ieee754_invalidop, 0);
+       __this_cpu_write((fpuemustats).ds_emul, 0);
+
+       __this_cpu_write((fpuemustats).abs_s, 0);
+       __this_cpu_write((fpuemustats).abs_d, 0);
+       __this_cpu_write((fpuemustats).add_s, 0);
+       __this_cpu_write((fpuemustats).add_d, 0);
+       __this_cpu_write((fpuemustats).bc1eqz, 0);
+       __this_cpu_write((fpuemustats).bc1nez, 0);
+       __this_cpu_write((fpuemustats).ceil_w_s, 0);
+       __this_cpu_write((fpuemustats).ceil_w_d, 0);
+       __this_cpu_write((fpuemustats).ceil_l_s, 0);
+       __this_cpu_write((fpuemustats).ceil_l_d, 0);
+       __this_cpu_write((fpuemustats).class_s, 0);
+       __this_cpu_write((fpuemustats).class_d, 0);
+       __this_cpu_write((fpuemustats).cmp_af_s, 0);
+       __this_cpu_write((fpuemustats).cmp_af_d, 0);
+       __this_cpu_write((fpuemustats).cmp_eq_s, 0);
+       __this_cpu_write((fpuemustats).cmp_eq_d, 0);
+       __this_cpu_write((fpuemustats).cmp_le_s, 0);
+       __this_cpu_write((fpuemustats).cmp_le_d, 0);
+       __this_cpu_write((fpuemustats).cmp_lt_s, 0);
+       __this_cpu_write((fpuemustats).cmp_lt_d, 0);
+       __this_cpu_write((fpuemustats).cmp_ne_s, 0);
+       __this_cpu_write((fpuemustats).cmp_ne_d, 0);
+       __this_cpu_write((fpuemustats).cmp_or_s, 0);
+       __this_cpu_write((fpuemustats).cmp_or_d, 0);
+       __this_cpu_write((fpuemustats).cmp_ueq_s, 0);
+       __this_cpu_write((fpuemustats).cmp_ueq_d, 0);
+       __this_cpu_write((fpuemustats).cmp_ule_s, 0);
+       __this_cpu_write((fpuemustats).cmp_ule_d, 0);
+       __this_cpu_write((fpuemustats).cmp_ult_s, 0);
+       __this_cpu_write((fpuemustats).cmp_ult_d, 0);
+       __this_cpu_write((fpuemustats).cmp_un_s, 0);
+       __this_cpu_write((fpuemustats).cmp_un_d, 0);
+       __this_cpu_write((fpuemustats).cmp_une_s, 0);
+       __this_cpu_write((fpuemustats).cmp_une_d, 0);
+       __this_cpu_write((fpuemustats).cmp_saf_s, 0);
+       __this_cpu_write((fpuemustats).cmp_saf_d, 0);
+       __this_cpu_write((fpuemustats).cmp_seq_s, 0);
+       __this_cpu_write((fpuemustats).cmp_seq_d, 0);
+       __this_cpu_write((fpuemustats).cmp_sle_s, 0);
+       __this_cpu_write((fpuemustats).cmp_sle_d, 0);
+       __this_cpu_write((fpuemustats).cmp_slt_s, 0);
+       __this_cpu_write((fpuemustats).cmp_slt_d, 0);
+       __this_cpu_write((fpuemustats).cmp_sne_s, 0);
+       __this_cpu_write((fpuemustats).cmp_sne_d, 0);
+       __this_cpu_write((fpuemustats).cmp_sor_s, 0);
+       __this_cpu_write((fpuemustats).cmp_sor_d, 0);
+       __this_cpu_write((fpuemustats).cmp_sueq_s, 0);
+       __this_cpu_write((fpuemustats).cmp_sueq_d, 0);
+       __this_cpu_write((fpuemustats).cmp_sule_s, 0);
+       __this_cpu_write((fpuemustats).cmp_sule_d, 0);
+       __this_cpu_write((fpuemustats).cmp_sult_s, 0);
+       __this_cpu_write((fpuemustats).cmp_sult_d, 0);
+       __this_cpu_write((fpuemustats).cmp_sun_s, 0);
+       __this_cpu_write((fpuemustats).cmp_sun_d, 0);
+       __this_cpu_write((fpuemustats).cmp_sune_s, 0);
+       __this_cpu_write((fpuemustats).cmp_sune_d, 0);
+       __this_cpu_write((fpuemustats).cvt_d_l, 0);
+       __this_cpu_write((fpuemustats).cvt_d_s, 0);
+       __this_cpu_write((fpuemustats).cvt_d_w, 0);
+       __this_cpu_write((fpuemustats).cvt_l_s, 0);
+       __this_cpu_write((fpuemustats).cvt_l_d, 0);
+       __this_cpu_write((fpuemustats).cvt_s_d, 0);
+       __this_cpu_write((fpuemustats).cvt_s_l, 0);
+       __this_cpu_write((fpuemustats).cvt_s_w, 0);
+       __this_cpu_write((fpuemustats).cvt_w_s, 0);
+       __this_cpu_write((fpuemustats).cvt_w_d, 0);
+       __this_cpu_write((fpuemustats).div_s, 0);
+       __this_cpu_write((fpuemustats).div_d, 0);
+       __this_cpu_write((fpuemustats).floor_w_s, 0);
+       __this_cpu_write((fpuemustats).floor_w_d, 0);
+       __this_cpu_write((fpuemustats).floor_l_s, 0);
+       __this_cpu_write((fpuemustats).floor_l_d, 0);
+       __this_cpu_write((fpuemustats).maddf_s, 0);
+       __this_cpu_write((fpuemustats).maddf_d, 0);
+       __this_cpu_write((fpuemustats).max_s, 0);
+       __this_cpu_write((fpuemustats).max_d, 0);
+       __this_cpu_write((fpuemustats).maxa_s, 0);
+       __this_cpu_write((fpuemustats).maxa_d, 0);
+       __this_cpu_write((fpuemustats).min_s, 0);
+       __this_cpu_write((fpuemustats).min_d, 0);
+       __this_cpu_write((fpuemustats).mina_s, 0);
+       __this_cpu_write((fpuemustats).mina_d, 0);
+       __this_cpu_write((fpuemustats).mov_s, 0);
+       __this_cpu_write((fpuemustats).mov_d, 0);
+       __this_cpu_write((fpuemustats).msubf_s, 0);
+       __this_cpu_write((fpuemustats).msubf_d, 0);
+       __this_cpu_write((fpuemustats).mul_s, 0);
+       __this_cpu_write((fpuemustats).mul_d, 0);
+       __this_cpu_write((fpuemustats).neg_s, 0);
+       __this_cpu_write((fpuemustats).neg_d, 0);
+       __this_cpu_write((fpuemustats).recip_s, 0);
+       __this_cpu_write((fpuemustats).recip_d, 0);
+       __this_cpu_write((fpuemustats).rint_s, 0);
+       __this_cpu_write((fpuemustats).rint_d, 0);
+       __this_cpu_write((fpuemustats).round_w_s, 0);
+       __this_cpu_write((fpuemustats).round_w_d, 0);
+       __this_cpu_write((fpuemustats).round_l_s, 0);
+       __this_cpu_write((fpuemustats).round_l_d, 0);
+       __this_cpu_write((fpuemustats).rsqrt_s, 0);
+       __this_cpu_write((fpuemustats).rsqrt_d, 0);
+       __this_cpu_write((fpuemustats).sel_s, 0);
+       __this_cpu_write((fpuemustats).sel_d, 0);
+       __this_cpu_write((fpuemustats).seleqz_s, 0);
+       __this_cpu_write((fpuemustats).seleqz_d, 0);
+       __this_cpu_write((fpuemustats).selnez_s, 0);
+       __this_cpu_write((fpuemustats).selnez_d, 0);
+       __this_cpu_write((fpuemustats).sqrt_s, 0);
+       __this_cpu_write((fpuemustats).sqrt_d, 0);
+       __this_cpu_write((fpuemustats).sub_s, 0);
+       __this_cpu_write((fpuemustats).sub_d, 0);
+       __this_cpu_write((fpuemustats).trunc_w_s, 0);
+       __this_cpu_write((fpuemustats).trunc_w_d, 0);
+       __this_cpu_write((fpuemustats).trunc_l_s, 0);
+       __this_cpu_write((fpuemustats).trunc_l_d, 0);
+
+       return 0;
+}
+
+static int fpuemustats_clear_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, fpuemustats_clear_show, inode->i_private);
+}
+
+static const struct file_operations fpuemustats_clear_fops = {
+       .open                   = fpuemustats_clear_open,
+       .read                   = seq_read,
+       .llseek                 = seq_lseek,
+       .release                = single_release,
+};
+
 static int __init debugfs_fpuemu(void)
 {
-       struct dentry *d, *dir;
+       struct dentry *fpuemu_debugfs_base_dir;
+       struct dentry *fpuemu_debugfs_inst_dir;
+       struct dentry *d, *reset_file;
 
        if (!mips_debugfs_dir)
                return -ENODEV;
-       dir = debugfs_create_dir("fpuemustats", mips_debugfs_dir);
-       if (!dir)
+
+       fpuemu_debugfs_base_dir = debugfs_create_dir("fpuemustats",
+                                                    mips_debugfs_dir);
+       if (!fpuemu_debugfs_base_dir)
+               return -ENOMEM;
+
+       reset_file = debugfs_create_file("fpuemustats_clear", 0444,
+                                        mips_debugfs_dir, NULL,
+                                        &fpuemustats_clear_fops);
+       if (!reset_file)
                return -ENOMEM;
 
 #define FPU_EMU_STAT_OFFSET(m)                                         \
@@ -43,7 +219,7 @@ static int __init debugfs_fpuemu(void)
 
 #define FPU_STAT_CREATE(m)                                             \
 do {                                                                   \
-       d = debugfs_create_file(#m , S_IRUGO, dir,                      \
+       d = debugfs_create_file(#m, 0444, fpuemu_debugfs_base_dir,      \
                                (void *)FPU_EMU_STAT_OFFSET(m),         \
                                &fops_fpuemu_stat);                     \
        if (!d)                                                         \
@@ -53,6 +229,7 @@ do {                                                                 \
        FPU_STAT_CREATE(emulated);
        FPU_STAT_CREATE(loads);
        FPU_STAT_CREATE(stores);
+       FPU_STAT_CREATE(branches);
        FPU_STAT_CREATE(cp1ops);
        FPU_STAT_CREATE(cp1xops);
        FPU_STAT_CREATE(errors);
@@ -63,6 +240,139 @@ do {                                                                       \
        FPU_STAT_CREATE(ieee754_invalidop);
        FPU_STAT_CREATE(ds_emul);
 
+       fpuemu_debugfs_inst_dir = debugfs_create_dir("instructions",
+                                                    fpuemu_debugfs_base_dir);
+       if (!fpuemu_debugfs_inst_dir)
+               return -ENOMEM;
+
+#define FPU_STAT_CREATE_EX(m)                                          \
+do {                                                                   \
+       char name[32];                                                  \
+                                                                       \
+       adjust_instruction_counter_name(name, #m);                      \
+                                                                       \
+       d = debugfs_create_file(name, 0444, fpuemu_debugfs_inst_dir,    \
+                               (void *)FPU_EMU_STAT_OFFSET(m),         \
+                               &fops_fpuemu_stat);                     \
+       if (!d)                                                         \
+               return -ENOMEM;                                         \
+} while (0)
+
+       FPU_STAT_CREATE_EX(abs_s);
+       FPU_STAT_CREATE_EX(abs_d);
+       FPU_STAT_CREATE_EX(add_s);
+       FPU_STAT_CREATE_EX(add_d);
+       FPU_STAT_CREATE_EX(bc1eqz);
+       FPU_STAT_CREATE_EX(bc1nez);
+       FPU_STAT_CREATE_EX(ceil_w_s);
+       FPU_STAT_CREATE_EX(ceil_w_d);
+       FPU_STAT_CREATE_EX(ceil_l_s);
+       FPU_STAT_CREATE_EX(ceil_l_d);
+       FPU_STAT_CREATE_EX(class_s);
+       FPU_STAT_CREATE_EX(class_d);
+       FPU_STAT_CREATE_EX(cmp_af_s);
+       FPU_STAT_CREATE_EX(cmp_af_d);
+       FPU_STAT_CREATE_EX(cmp_eq_s);
+       FPU_STAT_CREATE_EX(cmp_eq_d);
+       FPU_STAT_CREATE_EX(cmp_le_s);
+       FPU_STAT_CREATE_EX(cmp_le_d);
+       FPU_STAT_CREATE_EX(cmp_lt_s);
+       FPU_STAT_CREATE_EX(cmp_lt_d);
+       FPU_STAT_CREATE_EX(cmp_ne_s);
+       FPU_STAT_CREATE_EX(cmp_ne_d);
+       FPU_STAT_CREATE_EX(cmp_or_s);
+       FPU_STAT_CREATE_EX(cmp_or_d);
+       FPU_STAT_CREATE_EX(cmp_ueq_s);
+       FPU_STAT_CREATE_EX(cmp_ueq_d);
+       FPU_STAT_CREATE_EX(cmp_ule_s);
+       FPU_STAT_CREATE_EX(cmp_ule_d);
+       FPU_STAT_CREATE_EX(cmp_ult_s);
+       FPU_STAT_CREATE_EX(cmp_ult_d);
+       FPU_STAT_CREATE_EX(cmp_un_s);
+       FPU_STAT_CREATE_EX(cmp_un_d);
+       FPU_STAT_CREATE_EX(cmp_une_s);
+       FPU_STAT_CREATE_EX(cmp_une_d);
+       FPU_STAT_CREATE_EX(cmp_saf_s);
+       FPU_STAT_CREATE_EX(cmp_saf_d);
+       FPU_STAT_CREATE_EX(cmp_seq_s);
+       FPU_STAT_CREATE_EX(cmp_seq_d);
+       FPU_STAT_CREATE_EX(cmp_sle_s);
+       FPU_STAT_CREATE_EX(cmp_sle_d);
+       FPU_STAT_CREATE_EX(cmp_slt_s);
+       FPU_STAT_CREATE_EX(cmp_slt_d);
+       FPU_STAT_CREATE_EX(cmp_sne_s);
+       FPU_STAT_CREATE_EX(cmp_sne_d);
+       FPU_STAT_CREATE_EX(cmp_sor_s);
+       FPU_STAT_CREATE_EX(cmp_sor_d);
+       FPU_STAT_CREATE_EX(cmp_sueq_s);
+       FPU_STAT_CREATE_EX(cmp_sueq_d);
+       FPU_STAT_CREATE_EX(cmp_sule_s);
+       FPU_STAT_CREATE_EX(cmp_sule_d);
+       FPU_STAT_CREATE_EX(cmp_sult_s);
+       FPU_STAT_CREATE_EX(cmp_sult_d);
+       FPU_STAT_CREATE_EX(cmp_sun_s);
+       FPU_STAT_CREATE_EX(cmp_sun_d);
+       FPU_STAT_CREATE_EX(cmp_sune_s);
+       FPU_STAT_CREATE_EX(cmp_sune_d);
+       FPU_STAT_CREATE_EX(cvt_d_l);
+       FPU_STAT_CREATE_EX(cvt_d_s);
+       FPU_STAT_CREATE_EX(cvt_d_w);
+       FPU_STAT_CREATE_EX(cvt_l_s);
+       FPU_STAT_CREATE_EX(cvt_l_d);
+       FPU_STAT_CREATE_EX(cvt_s_d);
+       FPU_STAT_CREATE_EX(cvt_s_l);
+       FPU_STAT_CREATE_EX(cvt_s_w);
+       FPU_STAT_CREATE_EX(cvt_w_s);
+       FPU_STAT_CREATE_EX(cvt_w_d);
+       FPU_STAT_CREATE_EX(div_s);
+       FPU_STAT_CREATE_EX(div_d);
+       FPU_STAT_CREATE_EX(floor_w_s);
+       FPU_STAT_CREATE_EX(floor_w_d);
+       FPU_STAT_CREATE_EX(floor_l_s);
+       FPU_STAT_CREATE_EX(floor_l_d);
+       FPU_STAT_CREATE_EX(maddf_s);
+       FPU_STAT_CREATE_EX(maddf_d);
+       FPU_STAT_CREATE_EX(max_s);
+       FPU_STAT_CREATE_EX(max_d);
+       FPU_STAT_CREATE_EX(maxa_s);
+       FPU_STAT_CREATE_EX(maxa_d);
+       FPU_STAT_CREATE_EX(min_s);
+       FPU_STAT_CREATE_EX(min_d);
+       FPU_STAT_CREATE_EX(mina_s);
+       FPU_STAT_CREATE_EX(mina_d);
+       FPU_STAT_CREATE_EX(mov_s);
+       FPU_STAT_CREATE_EX(mov_d);
+       FPU_STAT_CREATE_EX(msubf_s);
+       FPU_STAT_CREATE_EX(msubf_d);
+       FPU_STAT_CREATE_EX(mul_s);
+       FPU_STAT_CREATE_EX(mul_d);
+       FPU_STAT_CREATE_EX(neg_s);
+       FPU_STAT_CREATE_EX(neg_d);
+       FPU_STAT_CREATE_EX(recip_s);
+       FPU_STAT_CREATE_EX(recip_d);
+       FPU_STAT_CREATE_EX(rint_s);
+       FPU_STAT_CREATE_EX(rint_d);
+       FPU_STAT_CREATE_EX(round_w_s);
+       FPU_STAT_CREATE_EX(round_w_d);
+       FPU_STAT_CREATE_EX(round_l_s);
+       FPU_STAT_CREATE_EX(round_l_d);
+       FPU_STAT_CREATE_EX(rsqrt_s);
+       FPU_STAT_CREATE_EX(rsqrt_d);
+       FPU_STAT_CREATE_EX(sel_s);
+       FPU_STAT_CREATE_EX(sel_d);
+       FPU_STAT_CREATE_EX(seleqz_s);
+       FPU_STAT_CREATE_EX(seleqz_d);
+       FPU_STAT_CREATE_EX(selnez_s);
+       FPU_STAT_CREATE_EX(selnez_d);
+       FPU_STAT_CREATE_EX(sqrt_s);
+       FPU_STAT_CREATE_EX(sqrt_d);
+       FPU_STAT_CREATE_EX(sub_s);
+       FPU_STAT_CREATE_EX(sub_d);
+       FPU_STAT_CREATE_EX(trunc_w_s);
+       FPU_STAT_CREATE_EX(trunc_w_d);
+       FPU_STAT_CREATE_EX(trunc_l_s);
+       FPU_STAT_CREATE_EX(trunc_l_d);
+
        return 0;
 }
 arch_initcall(debugfs_fpuemu);
index f1c87b0..51dced9 100644 (file)
@@ -104,8 +104,7 @@ union ieee754sp ieee754sp_add(union ieee754sp x, union ieee754sp y)
 
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
                SPDNORMX;
-
-               /* FALL THROUGH */
+               /* fall through */
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
                SPDNORMY;
@@ -132,13 +131,15 @@ union ieee754sp ieee754sp_add(union ieee754sp x, union ieee754sp y)
                 * Have to shift y fraction right to align.
                 */
                s = xe - ye;
-               SPXSRSYn(s);
+               ym = XSPSRS(ym, s);
+               ye += s;
        } else if (ye > xe) {
                /*
                 * Have to shift x fraction right to align.
                 */
                s = ye - xe;
-               SPXSRSXn(s);
+               xm = XSPSRS(xm, s);
+               xe += s;
        }
        assert(xe == ye);
        assert(xe <= SP_EMAX);
index 27f6db3..5d29049 100644 (file)
@@ -23,9 +23,9 @@
 
 union ieee754sp ieee754sp_div(union ieee754sp x, union ieee754sp y)
 {
-       unsigned rm;
+       unsigned int rm;
        int re;
-       unsigned bm;
+       unsigned int bm;
 
        COMPXSP;
        COMPYSP;
@@ -103,6 +103,7 @@ union ieee754sp ieee754sp_div(union ieee754sp x, union ieee754sp y)
 
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
                SPDNORMX;
+               /* fall through */
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
                SPDNORMY;
index 3797148..36a50f9 100644 (file)
@@ -44,13 +44,17 @@ union ieee754sp ieee754sp_fdp(union ieee754dp x)
 
        switch (xc) {
        case IEEE754_CLASS_SNAN:
-               return ieee754sp_nanxcpt(ieee754sp_nan_fdp(xs, xm));
+               x = ieee754dp_nanxcpt(x);
+               EXPLODEXDP;
+               /* fall through */
 
        case IEEE754_CLASS_QNAN:
                y = ieee754sp_nan_fdp(xs, xm);
-               EXPLODEYSP;
-               if (!ieee754_class_nan(yc))
-                       y = ieee754sp_indef();
+               if (!ieee754_csr.nan2008) {
+                       EXPLODEYSP;
+                       if (!ieee754_class_nan(yc))
+                               y = ieee754sp_indef();
+               }
                return y;
 
        case IEEE754_CLASS_INF:
index d5d8495..1a35d12 100644 (file)
@@ -23,7 +23,7 @@
 
 union ieee754sp ieee754sp_fint(int x)
 {
-       unsigned xm;
+       unsigned int xm;
        int xe;
        int xs;
 
index 74a5a00..22019ed 100644 (file)
@@ -96,6 +96,7 @@ union ieee754sp ieee754sp_fmax(union ieee754sp x, union ieee754sp y)
 
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
                SPDNORMX;
+               /* fall through */
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
                SPDNORMY;
@@ -224,6 +225,7 @@ union ieee754sp ieee754sp_fmaxa(union ieee754sp x, union ieee754sp y)
 
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
                SPDNORMX;
+               /* fall through */
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
                SPDNORMY;
index c51385f..feaec39 100644 (file)
@@ -96,6 +96,7 @@ union ieee754sp ieee754sp_fmin(union ieee754sp x, union ieee754sp y)
 
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
                SPDNORMX;
+               /* fall through */
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
                SPDNORMY;
@@ -224,6 +225,7 @@ union ieee754sp ieee754sp_fmina(union ieee754sp x, union ieee754sp y)
 
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
                SPDNORMX;
+               /* fall through */
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
                SPDNORMY;
index dd1dd83..07ba675 100644 (file)
 
 #include "ieee754sp.h"
 
-union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x,
-                               union ieee754sp y)
+
+static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x,
+                                union ieee754sp y, enum maddf_flags flags)
 {
        int re;
        int rs;
-       unsigned rm;
-       unsigned short lxm;
-       unsigned short hxm;
-       unsigned short lym;
-       unsigned short hym;
-       unsigned lrm;
-       unsigned hrm;
-       unsigned t;
-       unsigned at;
+       unsigned int rm;
+       u64 rm64;
+       u64 zm64;
        int s;
 
        COMPXSP;
        COMPYSP;
-       u32 zm; int ze; int zs __maybe_unused; int zc;
+       COMPZSP;
 
        EXPLODEXSP;
        EXPLODEYSP;
-       EXPLODESP(z, zc, zs, ze, zm)
+       EXPLODEZSP;
 
        FLUSHXSP;
        FLUSHYSP;
-       FLUSHSP(z, zc, zs, ze, zm);
+       FLUSHZSP;
 
        ieee754_clearcx();
 
-       switch (zc) {
-       case IEEE754_CLASS_SNAN:
-               ieee754_setcx(IEEE754_INVALID_OPERATION);
+       /*
+        * Handle the cases when at least one of x, y or z is a NaN.
+        * Order of precedence is sNaN, qNaN and z, x, y.
+        */
+       if (zc == IEEE754_CLASS_SNAN)
                return ieee754sp_nanxcpt(z);
-       case IEEE754_CLASS_DNORM:
-               SPDNORMx(zm, ze);
-       /* QNAN is handled separately below */
-       }
-
-       switch (CLPAIR(xc, yc)) {
-       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
-       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
-       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
-       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
-       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
+       if (xc == IEEE754_CLASS_SNAN)
+               return ieee754sp_nanxcpt(x);
+       if (yc == IEEE754_CLASS_SNAN)
                return ieee754sp_nanxcpt(y);
+       if (zc == IEEE754_CLASS_QNAN)
+               return z;
+       if (xc == IEEE754_CLASS_QNAN)
+               return x;
+       if (yc == IEEE754_CLASS_QNAN)
+               return y;
 
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
-               return ieee754sp_nanxcpt(x);
+       if (zc == IEEE754_CLASS_DNORM)
+               SPDNORMZ;
+       /* ZERO z cases are handled separately below */
 
-       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
-       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
-       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
-       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
-               return y;
+       switch (CLPAIR(xc, yc)) {
 
-       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
-       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
-       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
-       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
-       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
-               return x;
 
        /*
         * Infinity handling
         */
        case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
-               if (zc == IEEE754_CLASS_QNAN)
-                       return z;
                ieee754_setcx(IEEE754_INVALID_OPERATION);
                return ieee754sp_indef();
 
@@ -97,9 +76,27 @@ union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x,
        case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
        case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
        case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
-               if (zc == IEEE754_CLASS_QNAN)
-                       return z;
-               return ieee754sp_inf(xs ^ ys);
+               if ((zc == IEEE754_CLASS_INF) &&
+                   ((!(flags & MADDF_NEGATE_PRODUCT) && (zs != (xs ^ ys))) ||
+                    ((flags & MADDF_NEGATE_PRODUCT) && (zs == (xs ^ ys))))) {
+                       /*
+                        * Cases of addition of infinities with opposite signs
+                        * or subtraction of infinities with same signs.
+                        */
+                       ieee754_setcx(IEEE754_INVALID_OPERATION);
+                       return ieee754sp_indef();
+               }
+               /*
+                * z is here either not an infinity, or an infinity having the
+                * same sign as product (x*y) (in case of MADDF.D instruction)
+                * or product -(x*y) (in MSUBF.D case). The result must be an
+                * infinity, and its sign is determined only by the value of
+                * (flags & MADDF_NEGATE_PRODUCT) and the signs of x and y.
+                */
+               if (flags & MADDF_NEGATE_PRODUCT)
+                       return ieee754sp_inf(1 ^ (xs ^ ys));
+               else
+                       return ieee754sp_inf(xs ^ ys);
 
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
@@ -108,34 +105,45 @@ union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x,
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
                if (zc == IEEE754_CLASS_INF)
                        return ieee754sp_inf(zs);
-               /* Multiplication is 0 so just return z */
+               if (zc == IEEE754_CLASS_ZERO) {
+                       /* Handle cases +0 + (-0) and similar ones. */
+                       if ((!(flags & MADDF_NEGATE_PRODUCT)
+                                       && (zs == (xs ^ ys))) ||
+                           ((flags & MADDF_NEGATE_PRODUCT)
+                                       && (zs != (xs ^ ys))))
+                               /*
+                                * Cases of addition of zeros of equal signs
+                                * or subtraction of zeroes of opposite signs.
+                                * The sign of the resulting zero is in any
+                                * such case determined only by the sign of z.
+                                */
+                               return z;
+
+                       return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD);
+               }
+               /* x*y is here 0, and z is not 0, so just return z */
                return z;
 
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
                SPDNORMX;
+               /* fall through */
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
-               if (zc == IEEE754_CLASS_QNAN)
-                       return z;
-               else if (zc == IEEE754_CLASS_INF)
+               if (zc == IEEE754_CLASS_INF)
                        return ieee754sp_inf(zs);
                SPDNORMY;
                break;
 
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
-               if (zc == IEEE754_CLASS_QNAN)
-                       return z;
-               else if (zc == IEEE754_CLASS_INF)
+               if (zc == IEEE754_CLASS_INF)
                        return ieee754sp_inf(zs);
                SPDNORMX;
                break;
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
-               if (zc == IEEE754_CLASS_QNAN)
-                       return z;
-               else if (zc == IEEE754_CLASS_INF)
+               if (zc == IEEE754_CLASS_INF)
                        return ieee754sp_inf(zs);
-               /* fall through to real computations */
+               /* continue to real computations */
        }
 
        /* Finally get to do some computation */
@@ -154,102 +162,104 @@ union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x,
 
        re = xe + ye;
        rs = xs ^ ys;
+       if (flags & MADDF_NEGATE_PRODUCT)
+               rs ^= 1;
 
-       /* shunt to top of word */
-       xm <<= 32 - (SP_FBITS + 1);
-       ym <<= 32 - (SP_FBITS + 1);
+       /* Multiple 24 bit xm and ym to give 48 bit results */
+       rm64 = (uint64_t)xm * ym;
 
-       /*
-        * Multiply 32 bits xm, ym to give high 32 bits rm with stickness.
-        */
-       lxm = xm & 0xffff;
-       hxm = xm >> 16;
-       lym = ym & 0xffff;
-       hym = ym >> 16;
+       /* Shunt to top of word */
+       rm64 = rm64 << 16;
 
-       lrm = lxm * lym;        /* 16 * 16 => 32 */
-       hrm = hxm * hym;        /* 16 * 16 => 32 */
-
-       t = lxm * hym; /* 16 * 16 => 32 */
-       at = lrm + (t << 16);
-       hrm += at < lrm;
-       lrm = at;
-       hrm = hrm + (t >> 16);
-
-       t = hxm * lym; /* 16 * 16 => 32 */
-       at = lrm + (t << 16);
-       hrm += at < lrm;
-       lrm = at;
-       hrm = hrm + (t >> 16);
-
-       rm = hrm | (lrm != 0);
-
-       /*
-        * Sticky shift down to normal rounding precision.
-        */
-       if ((int) rm < 0) {
-               rm = (rm >> (32 - (SP_FBITS + 1 + 3))) |
-                   ((rm << (SP_FBITS + 1 + 3)) != 0);
+       /* Put explicit bit at bit 62 if necessary */
+       if ((int64_t) rm64 < 0) {
+               rm64 = rm64 >> 1;
                re++;
-       } else {
-               rm = (rm >> (32 - (SP_FBITS + 1 + 3 + 1))) |
-                    ((rm << (SP_FBITS + 1 + 3 + 1)) != 0);
        }
-       assert(rm & (SP_HIDDEN_BIT << 3));
 
-       /* And now the addition */
+       assert(rm64 & (1 << 62));
 
-       assert(zm & SP_HIDDEN_BIT);
+       if (zc == IEEE754_CLASS_ZERO) {
+               /*
+                * Move explicit bit from bit 62 to bit 26 since the
+                * ieee754sp_format code expects the mantissa to be
+                * 27 bits wide (24 + 3 rounding bits).
+                */
+               rm = XSPSRS64(rm64, (62 - 26));
+               return ieee754sp_format(rs, re, rm);
+       }
 
-       /*
-        * Provide guard,round and stick bit space.
-        */
-       zm <<= 3;
+       /* Move explicit bit from bit 23 to bit 62 */
+       zm64 = (uint64_t)zm << (62 - 23);
+       assert(zm64 & (1 << 62));
 
+       /* Make the exponents the same */
        if (ze > re) {
                /*
-                * Have to shift y fraction right to align.
+                * Have to shift r fraction right to align.
                 */
                s = ze - re;
-               SPXSRSYn(s);
+               rm64 = XSPSRS64(rm64, s);
+               re += s;
        } else if (re > ze) {
                /*
-                * Have to shift x fraction right to align.
+                * Have to shift z fraction right to align.
                 */
                s = re - ze;
-               SPXSRSYn(s);
+               zm64 = XSPSRS64(zm64, s);
+               ze += s;
        }
        assert(ze == re);
        assert(ze <= SP_EMAX);
 
+       /* Do the addition */
        if (zs == rs) {
                /*
-                * Generate 28 bit result of adding two 27 bit numbers
-                * leaving result in zm, zs and ze.
+                * Generate 64 bit result by adding two 63 bit numbers
+                * leaving result in zm64, zs and ze.
                 */
-               zm = zm + rm;
-
-               if (zm >> (SP_FBITS + 1 + 3)) { /* carry out */
-                       SPXSRSX1();
+               zm64 = zm64 + rm64;
+               if ((int64_t)zm64 < 0) {        /* carry out */
+                       zm64 = XSPSRS1(zm64);
+                       ze++;
                }
        } else {
-               if (zm >= rm) {
-                       zm = zm - rm;
+               if (zm64 >= rm64) {
+                       zm64 = zm64 - rm64;
                } else {
-                       zm = rm - zm;
+                       zm64 = rm64 - zm64;
                        zs = rs;
                }
-               if (zm == 0)
+               if (zm64 == 0)
                        return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD);
 
                /*
-                * Normalize in extended single precision
+                * Put explicit bit at bit 62 if necessary.
                 */
-               while ((zm >> (SP_MBITS + 3)) == 0) {
-                       zm <<= 1;
+               while ((zm64 >> 62) == 0) {
+                       zm64 <<= 1;
                        ze--;
                }
-
        }
+
+       /*
+        * Move explicit bit from bit 62 to bit 26 since the
+        * ieee754sp_format code expects the mantissa to be
+        * 27 bits wide (24 + 3 rounding bits).
+        */
+       zm = XSPSRS64(zm64, (62 - 26));
+
        return ieee754sp_format(zs, ze, zm);
 }
+
+union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x,
+                               union ieee754sp y)
+{
+       return _sp_maddf(z, x, y, 0);
+}
+
+union ieee754sp ieee754sp_msubf(union ieee754sp z, union ieee754sp x,
+                               union ieee754sp y)
+{
+       return _sp_maddf(z, x, y, MADDF_NEGATE_PRODUCT);
+}
diff --git a/arch/mips/math-emu/sp_msubf.c b/arch/mips/math-emu/sp_msubf.c
deleted file mode 100644 (file)
index 81c38b9..0000000
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * IEEE754 floating point arithmetic
- * single precision: MSUB.f (Fused Multiply Subtract)
- * MSUBF.fmt: FPR[fd] = FPR[fd] - (FPR[fs] x FPR[ft])
- *
- * MIPS floating point support
- * Copyright (C) 2015 Imagination Technologies, Ltd.
- * Author: Markos Chandras <markos.chandras@imgtec.com>
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License as published by the
- *  Free Software Foundation; version 2 of the License.
- */
-
-#include "ieee754sp.h"
-
-union ieee754sp ieee754sp_msubf(union ieee754sp z, union ieee754sp x,
-                               union ieee754sp y)
-{
-       int re;
-       int rs;
-       unsigned rm;
-       unsigned short lxm;
-       unsigned short hxm;
-       unsigned short lym;
-       unsigned short hym;
-       unsigned lrm;
-       unsigned hrm;
-       unsigned t;
-       unsigned at;
-       int s;
-
-       COMPXSP;
-       COMPYSP;
-       u32 zm; int ze; int zs __maybe_unused; int zc;
-
-       EXPLODEXSP;
-       EXPLODEYSP;
-       EXPLODESP(z, zc, zs, ze, zm)
-
-       FLUSHXSP;
-       FLUSHYSP;
-       FLUSHSP(z, zc, zs, ze, zm);
-
-       ieee754_clearcx();
-
-       switch (zc) {
-       case IEEE754_CLASS_SNAN:
-               ieee754_setcx(IEEE754_INVALID_OPERATION);
-               return ieee754sp_nanxcpt(z);
-       case IEEE754_CLASS_DNORM:
-               SPDNORMx(zm, ze);
-       /* QNAN is handled separately below */
-       }
-
-       switch (CLPAIR(xc, yc)) {
-       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
-       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
-       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
-       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
-       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
-               return ieee754sp_nanxcpt(y);
-
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
-               return ieee754sp_nanxcpt(x);
-
-       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
-       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
-       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
-       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
-               return y;
-
-       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
-       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
-       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
-       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
-       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
-               return x;
-
-       /*
-        * Infinity handling
-        */
-       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
-       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
-               if (zc == IEEE754_CLASS_QNAN)
-                       return z;
-               ieee754_setcx(IEEE754_INVALID_OPERATION);
-               return ieee754sp_indef();
-
-       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
-       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
-       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
-       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
-       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
-               if (zc == IEEE754_CLASS_QNAN)
-                       return z;
-               return ieee754sp_inf(xs ^ ys);
-
-       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
-       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
-       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
-       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
-       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
-               if (zc == IEEE754_CLASS_INF)
-                       return ieee754sp_inf(zs);
-               /* Multiplication is 0 so just return z */
-               return z;
-
-       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
-               SPDNORMX;
-
-       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
-               if (zc == IEEE754_CLASS_QNAN)
-                       return z;
-               else if (zc == IEEE754_CLASS_INF)
-                       return ieee754sp_inf(zs);
-               SPDNORMY;
-               break;
-
-       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
-               if (zc == IEEE754_CLASS_QNAN)
-                       return z;
-               else if (zc == IEEE754_CLASS_INF)
-                       return ieee754sp_inf(zs);
-               SPDNORMX;
-               break;
-
-       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
-               if (zc == IEEE754_CLASS_QNAN)
-                       return z;
-               else if (zc == IEEE754_CLASS_INF)
-                       return ieee754sp_inf(zs);
-               /* fall through to real compuation */
-       }
-
-       /* Finally get to do some computation */
-
-       /*
-        * Do the multiplication bit first
-        *
-        * rm = xm * ym, re = xe + ye basically
-        *
-        * At this point xm and ym should have been normalized.
-        */
-
-       /* rm = xm * ym, re = xe+ye basically */
-       assert(xm & SP_HIDDEN_BIT);
-       assert(ym & SP_HIDDEN_BIT);
-
-       re = xe + ye;
-       rs = xs ^ ys;
-
-       /* shunt to top of word */
-       xm <<= 32 - (SP_FBITS + 1);
-       ym <<= 32 - (SP_FBITS + 1);
-
-       /*
-        * Multiply 32 bits xm, ym to give high 32 bits rm with stickness.
-        */
-       lxm = xm & 0xffff;
-       hxm = xm >> 16;
-       lym = ym & 0xffff;
-       hym = ym >> 16;
-
-       lrm = lxm * lym;        /* 16 * 16 => 32 */
-       hrm = hxm * hym;        /* 16 * 16 => 32 */
-
-       t = lxm * hym; /* 16 * 16 => 32 */
-       at = lrm + (t << 16);
-       hrm += at < lrm;
-       lrm = at;
-       hrm = hrm + (t >> 16);
-
-       t = hxm * lym; /* 16 * 16 => 32 */
-       at = lrm + (t << 16);
-       hrm += at < lrm;
-       lrm = at;
-       hrm = hrm + (t >> 16);
-
-       rm = hrm | (lrm != 0);
-
-       /*
-        * Sticky shift down to normal rounding precision.
-        */
-       if ((int) rm < 0) {
-               rm = (rm >> (32 - (SP_FBITS + 1 + 3))) |
-                   ((rm << (SP_FBITS + 1 + 3)) != 0);
-               re++;
-       } else {
-               rm = (rm >> (32 - (SP_FBITS + 1 + 3 + 1))) |
-                    ((rm << (SP_FBITS + 1 + 3 + 1)) != 0);
-       }
-       assert(rm & (SP_HIDDEN_BIT << 3));
-
-       /* And now the subtraction */
-
-       /* Flip sign of r and handle as add */
-       rs ^= 1;
-
-       assert(zm & SP_HIDDEN_BIT);
-
-       /*
-        * Provide guard,round and stick bit space.
-        */
-       zm <<= 3;
-
-       if (ze > re) {
-               /*
-                * Have to shift y fraction right to align.
-                */
-               s = ze - re;
-               SPXSRSYn(s);
-       } else if (re > ze) {
-               /*
-                * Have to shift x fraction right to align.
-                */
-               s = re - ze;
-               SPXSRSYn(s);
-       }
-       assert(ze == re);
-       assert(ze <= SP_EMAX);
-
-       if (zs == rs) {
-               /*
-                * Generate 28 bit result of adding two 27 bit numbers
-                * leaving result in zm, zs and ze.
-                */
-               zm = zm + rm;
-
-               if (zm >> (SP_FBITS + 1 + 3)) { /* carry out */
-                       SPXSRSX1(); /* shift preserving sticky */
-               }
-       } else {
-               if (zm >= rm) {
-                       zm = zm - rm;
-               } else {
-                       zm = rm - zm;
-                       zs = rs;
-               }
-               if (zm == 0)
-                       return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD);
-
-               /*
-                * Normalize in extended single precision
-                */
-               while ((zm >> (SP_MBITS + 3)) == 0) {
-                       zm <<= 1;
-                       ze--;
-               }
-
-       }
-       return ieee754sp_format(zs, ze, zm);
-}
index d910c43..fde71e2 100644 (file)
@@ -25,15 +25,15 @@ union ieee754sp ieee754sp_mul(union ieee754sp x, union ieee754sp y)
 {
        int re;
        int rs;
-       unsigned rm;
+       unsigned int rm;
        unsigned short lxm;
        unsigned short hxm;
        unsigned short lym;
        unsigned short hym;
-       unsigned lrm;
-       unsigned hrm;
-       unsigned t;
-       unsigned at;
+       unsigned int lrm;
+       unsigned int hrm;
+       unsigned int t;
+       unsigned int at;
 
        COMPXSP;
        COMPYSP;
@@ -101,6 +101,7 @@ union ieee754sp ieee754sp_mul(union ieee754sp x, union ieee754sp y)
 
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
                SPDNORMX;
+               /* fall through */
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
                SPDNORMY;
diff --git a/arch/mips/math-emu/sp_rint.c b/arch/mips/math-emu/sp_rint.c
new file mode 100644 (file)
index 0000000..70765b1
--- /dev/null
@@ -0,0 +1,90 @@
+/* IEEE754 floating point arithmetic
+ * single precision
+ */
+/*
+ * MIPS floating point support
+ * Copyright (C) 1994-2000 Algorithmics Ltd.
+ * Copyright (C) 2017 Imagination Technologies, Ltd.
+ * Author: Aleksandar Markovic <aleksandar.markovic@imgtec.com>
+ *
+ *  This program is free software; you can distribute 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 it will be useful, but WITHOUT
+ *  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.
+ */
+
+#include "ieee754sp.h"
+
+union ieee754sp ieee754sp_rint(union ieee754sp x)
+{
+       union ieee754sp ret;
+       u32 residue;
+       int sticky;
+       int round;
+       int odd;
+
+       COMPXDP;                /* <-- DP needed for 64-bit mantissa tmp */
+
+       ieee754_clearcx();
+
+       EXPLODEXSP;
+       FLUSHXSP;
+
+       if (xc == IEEE754_CLASS_SNAN)
+               return ieee754sp_nanxcpt(x);
+
+       if ((xc == IEEE754_CLASS_QNAN) ||
+           (xc == IEEE754_CLASS_INF) ||
+           (xc == IEEE754_CLASS_ZERO))
+               return x;
+
+       if (xe >= SP_FBITS)
+               return x;
+
+       if (xe < -1) {
+               residue = xm;
+               round = 0;
+               sticky = residue != 0;
+               xm = 0;
+       } else {
+               residue = xm << (xe + 1);
+               residue <<= 31 - SP_FBITS;
+               round = (residue >> 31) != 0;
+               sticky = (residue << 1) != 0;
+               xm >>= SP_FBITS - xe;
+       }
+
+       odd = (xm & 0x1) != 0x0;
+
+       switch (ieee754_csr.rm) {
+       case FPU_CSR_RN:        /* toward nearest */
+               if (round && (sticky || odd))
+                       xm++;
+               break;
+       case FPU_CSR_RZ:        /* toward zero */
+               break;
+       case FPU_CSR_RU:        /* toward +infinity */
+               if ((round || sticky) && !xs)
+                       xm++;
+               break;
+       case FPU_CSR_RD:        /* toward -infinity */
+               if ((round || sticky) && xs)
+                       xm++;
+               break;
+       }
+
+       if (round || sticky)
+               ieee754_setcx(IEEE754_INEXACT);
+
+       ret = ieee754sp_flong(xm);
+       SPSIGN(ret) = xs;
+
+       return ret;
+}
index c50e945..756c9cf 100644 (file)
 
 union ieee754sp ieee754sp_neg(union ieee754sp x)
 {
-       unsigned int oldrm;
        union ieee754sp y;
 
-       oldrm = ieee754_csr.rm;
-       ieee754_csr.rm = FPU_CSR_RD;
-       y = ieee754sp_sub(ieee754sp_zero(0), x);
-       ieee754_csr.rm = oldrm;
+       if (ieee754_csr.abs2008) {
+               y = x;
+               SPSIGN(y) = !SPSIGN(x);
+       } else {
+               unsigned int oldrm;
+
+               oldrm = ieee754_csr.rm;
+               ieee754_csr.rm = FPU_CSR_RD;
+               y = ieee754sp_sub(ieee754sp_zero(0), x);
+               ieee754_csr.rm = oldrm;
+       }
        return y;
 }
 
 union ieee754sp ieee754sp_abs(union ieee754sp x)
 {
-       unsigned int oldrm;
        union ieee754sp y;
 
-       oldrm = ieee754_csr.rm;
-       ieee754_csr.rm = FPU_CSR_RD;
-       if (SPSIGN(x))
-               y = ieee754sp_sub(ieee754sp_zero(0), x);
-       else
-               y = ieee754sp_add(ieee754sp_zero(0), x);
-       ieee754_csr.rm = oldrm;
+       if (ieee754_csr.abs2008) {
+               y = x;
+               SPSIGN(y) = 0;
+       } else {
+               unsigned int oldrm;
+
+               oldrm = ieee754_csr.rm;
+               ieee754_csr.rm = FPU_CSR_RD;
+               if (SPSIGN(x))
+                       y = ieee754sp_sub(ieee754sp_zero(0), x);
+               else
+                       y = ieee754sp_add(ieee754sp_zero(0), x);
+               ieee754_csr.rm = oldrm;
+       }
        return y;
 }
index 67059c3..9cc83f0 100644 (file)
@@ -82,7 +82,8 @@ union ieee754sp ieee754sp_sqrt(union ieee754sp x)
 
        /* generate sqrt(x) bit by bit */
        ix += ix;
-       q = s = 0;              /* q = sqrt(x) */
+       s = 0;
+       q = 0;                  /* q = sqrt(x) */
        r = 0x01000000;         /* r = moving bit from right to left */
 
        while (r != 0) {
index ec5f937..9f2ff72 100644 (file)
@@ -106,6 +106,7 @@ union ieee754sp ieee754sp_sub(union ieee754sp x, union ieee754sp y)
 
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
                SPDNORMX;
+               /* fall through */
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
                SPDNORMY;
@@ -134,13 +135,15 @@ union ieee754sp ieee754sp_sub(union ieee754sp x, union ieee754sp y)
                 * have to shift y fraction right to align
                 */
                s = xe - ye;
-               SPXSRSYn(s);
+               ym = XSPSRS(ym, s);
+               ye += s;
        } else if (ye > xe) {
                /*
                 * have to shift x fraction right to align
                 */
                s = ye - xe;
-               SPXSRSXn(s);
+               xm = XSPSRS(xm, s);
+               xe += s;
        }
        assert(xe == ye);
        assert(xe <= SP_EMAX);
index 091299a..f4b4cab 100644 (file)
@@ -38,10 +38,13 @@ int ieee754sp_tint(union ieee754sp x)
        switch (xc) {
        case IEEE754_CLASS_SNAN:
        case IEEE754_CLASS_QNAN:
-       case IEEE754_CLASS_INF:
                ieee754_setcx(IEEE754_INVALID_OPERATION);
                return ieee754si_indef();
 
+       case IEEE754_CLASS_INF:
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754si_overflow(xs);
+
        case IEEE754_CLASS_ZERO:
                return 0;
 
@@ -56,7 +59,7 @@ int ieee754sp_tint(union ieee754sp x)
                /* Set invalid. We will only use overflow for floating
                   point overflow */
                ieee754_setcx(IEEE754_INVALID_OPERATION);
-               return ieee754si_indef();
+               return ieee754si_overflow(xs);
        }
        /* oh gawd */
        if (xe > SP_FBITS) {
@@ -97,7 +100,7 @@ int ieee754sp_tint(union ieee754sp x)
                if ((xm >> 31) != 0) {
                        /* This can happen after rounding */
                        ieee754_setcx(IEEE754_INVALID_OPERATION);
-                       return ieee754si_indef();
+                       return ieee754si_overflow(xs);
                }
                if (round || sticky)
                        ieee754_setcx(IEEE754_INEXACT);
index 9f3c742..bca5ac9 100644 (file)
@@ -20,7 +20,6 @@
  */
 
 #include "ieee754sp.h"
-#include "ieee754dp.h"
 
 s64 ieee754sp_tlong(union ieee754sp x)
 {
@@ -39,10 +38,13 @@ s64 ieee754sp_tlong(union ieee754sp x)
        switch (xc) {
        case IEEE754_CLASS_SNAN:
        case IEEE754_CLASS_QNAN:
-       case IEEE754_CLASS_INF:
                ieee754_setcx(IEEE754_INVALID_OPERATION);
                return ieee754di_indef();
 
+       case IEEE754_CLASS_INF:
+               ieee754_setcx(IEEE754_INVALID_OPERATION);
+               return ieee754di_overflow(xs);
+
        case IEEE754_CLASS_ZERO:
                return 0;
 
@@ -57,7 +59,7 @@ s64 ieee754sp_tlong(union ieee754sp x)
                /* Set invalid. We will only use overflow for floating
                   point overflow */
                ieee754_setcx(IEEE754_INVALID_OPERATION);
-               return ieee754di_indef();
+               return ieee754di_overflow(xs);
        }
        /* oh gawd */
        if (xe > SP_FBITS) {
@@ -94,7 +96,7 @@ s64 ieee754sp_tlong(union ieee754sp x)
                if ((xm >> 63) != 0) {
                        /* This can happen after rounding */
                        ieee754_setcx(IEEE754_INVALID_OPERATION);
-                       return ieee754di_indef();
+                       return ieee754di_overflow(xs);
                }
                if (round || sticky)
                        ieee754_setcx(IEEE754_INEXACT);
index 5d3a25e..d66a61e 100644 (file)
@@ -780,25 +780,72 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size)
 }
 #endif /* CONFIG_DMA_NONCOHERENT || CONFIG_DMA_MAYBE_COHERENT */
 
+struct flush_cache_sigtramp_args {
+       struct mm_struct *mm;
+       struct page *page;
+       unsigned long addr;
+};
+
 /*
  * While we're protected against bad userland addresses we don't care
  * very much about what happens in that case.  Usually a segmentation
  * fault will dump the process later on anyway ...
  */
-static void local_r4k_flush_cache_sigtramp(void * arg)
+static void local_r4k_flush_cache_sigtramp(void *args)
 {
+       struct flush_cache_sigtramp_args *fcs_args = args;
+       unsigned long addr = fcs_args->addr;
+       struct page *page = fcs_args->page;
+       struct mm_struct *mm = fcs_args->mm;
+       int map_coherent = 0;
+       void *vaddr;
+
        unsigned long ic_lsize = cpu_icache_line_size();
        unsigned long dc_lsize = cpu_dcache_line_size();
        unsigned long sc_lsize = cpu_scache_line_size();
-       unsigned long addr = (unsigned long) arg;
+
+       /*
+        * If owns no valid ASID yet, cannot possibly have gotten
+        * this page into the cache.
+        */
+       if (!has_valid_asid(mm))
+               return;
+
+       if (mm == current->active_mm) {
+               vaddr = NULL;
+       } else {
+               /*
+                * Use kmap_coherent or kmap_atomic to do flushes for
+                * another ASID than the current one.
+                */
+               map_coherent = (cpu_has_dc_aliases &&
+                               page_mapcount(page) &&
+                               !Page_dcache_dirty(page));
+               if (map_coherent)
+                       vaddr = kmap_coherent(page, addr);
+               else
+                       vaddr = kmap_atomic(page);
+               addr = (unsigned long)vaddr + (addr & ~PAGE_MASK);
+       }
 
        R4600_HIT_CACHEOP_WAR_IMPL;
        if (dc_lsize)
-               protected_writeback_dcache_line(addr & ~(dc_lsize - 1));
+               vaddr ? flush_dcache_line(addr & ~(dc_lsize - 1))
+                     : protected_writeback_dcache_line(addr & ~(dc_lsize - 1));
        if (!cpu_icache_snoops_remote_store && scache_size)
-               protected_writeback_scache_line(addr & ~(sc_lsize - 1));
+               vaddr ? flush_scache_line(addr & ~(sc_lsize - 1))
+                     : protected_writeback_scache_line(addr & ~(sc_lsize - 1));
        if (ic_lsize)
-               protected_flush_icache_line(addr & ~(ic_lsize - 1));
+               vaddr ? flush_icache_line(addr & ~(ic_lsize - 1))
+                     : protected_flush_icache_line(addr & ~(ic_lsize - 1));
+
+       if (vaddr) {
+               if (map_coherent)
+                       kunmap_coherent();
+               else
+                       kunmap_atomic(vaddr);
+       }
+
        if (MIPS4K_ICACHE_REFILL_WAR) {
                __asm__ __volatile__ (
                        ".set push\n\t"
@@ -823,7 +870,23 @@ static void local_r4k_flush_cache_sigtramp(void * arg)
 
 static void r4k_flush_cache_sigtramp(unsigned long addr)
 {
-       r4k_on_each_cpu(local_r4k_flush_cache_sigtramp, (void *) addr);
+       struct flush_cache_sigtramp_args args;
+       int npages;
+
+       down_read(&current->mm->mmap_sem);
+
+       npages = get_user_pages_fast(addr, 1, 0, &args.page);
+       if (npages < 1)
+               goto out;
+
+       args.mm = current->mm;
+       args.addr = addr;
+
+       r4k_on_each_cpu(local_r4k_flush_cache_sigtramp, &args);
+
+       put_page(args.page);
+out:
+       up_read(&current->mm->mmap_sem);
 }
 
 static void r4k_flush_icache_all(void)
@@ -1670,7 +1733,7 @@ void r4k_cache_init(void)
         * This code supports virtually indexed processors and will be
         * unnecessarily inefficient on physically indexed processors.
         */
-       if (c->dcache.linesz)
+       if (c->dcache.linesz && cpu_has_dc_aliases)
                shm_align_mask = max_t( unsigned long,
                                        c->dcache.sets * c->dcache.linesz - 1,
                                        PAGE_SIZE - 1);
@@ -1696,7 +1759,12 @@ void r4k_cache_init(void)
        local_flush_icache_range        = local_r4k_flush_icache_range;
 
 #if defined(CONFIG_DMA_NONCOHERENT) || defined(CONFIG_DMA_MAYBE_COHERENT)
-       if (coherentio) {
+# if defined(CONFIG_DMA_PERDEV_COHERENT)
+       if (0) {
+# else
+       if ((coherentio == IO_COHERENCE_ENABLED) ||
+           ((coherentio == IO_COHERENCE_DEFAULT) && hw_coherentio)) {
+# endif
                _dma_cache_wback_inv    = (void *)cache_noop;
                _dma_cache_wback        = (void *)cache_noop;
                _dma_cache_inv          = (void *)cache_noop;
index 730d394..3ae73ae 100644 (file)
 
 #include <dma-coherence.h>
 
-#ifdef CONFIG_DMA_MAYBE_COHERENT
-int coherentio = 0;    /* User defined DMA coherency from command line. */
+#if defined(CONFIG_DMA_MAYBE_COHERENT) && !defined(CONFIG_DMA_PERDEV_COHERENT)
+/* User defined DMA coherency from command line. */
+enum coherent_io_user_state coherentio = IO_COHERENCE_DEFAULT;
 EXPORT_SYMBOL_GPL(coherentio);
 int hw_coherentio = 0; /* Actual hardware supported DMA coherency setting. */
 
 static int __init setcoherentio(char *str)
 {
-       coherentio = 1;
+       coherentio = IO_COHERENCE_ENABLED;
        pr_info("Hardware DMA cache coherency (command line)\n");
        return 0;
 }
@@ -39,7 +40,7 @@ early_param("coherentio", setcoherentio);
 
 static int __init setnocoherentio(char *str)
 {
-       coherentio = 0;
+       coherentio = IO_COHERENCE_DISABLED;
        pr_info("Software DMA cache coherency (command line)\n");
        return 0;
 }
@@ -159,8 +160,7 @@ static void *mips_dma_alloc_coherent(struct device *dev, size_t size,
        *dma_handle = plat_map_dma_mem(dev, ret, size);
        if (!plat_device_is_coherent(dev)) {
                dma_cache_wback_inv((unsigned long) ret, size);
-               if (!hw_coherentio)
-                       ret = UNCAC_ADDR(ret);
+               ret = UNCAC_ADDR(ret);
        }
 
        return ret;
@@ -188,7 +188,7 @@ static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr,
 
        plat_unmap_dma_mem(dev, dma_handle, size, DMA_BIDIRECTIONAL);
 
-       if (!plat_device_is_coherent(dev) && !hw_coherentio)
+       if (!plat_device_is_coherent(dev))
                addr = CAC_ADDR(addr);
 
        page = virt_to_page((void *) addr);
@@ -208,7 +208,7 @@ static int mips_dma_mmap(struct device *dev, struct vm_area_struct *vma,
        unsigned long pfn;
        int ret = -ENXIO;
 
-       if (!plat_device_is_coherent(dev) && !hw_coherentio)
+       if (!plat_device_is_coherent(dev))
                addr = CAC_ADDR(addr);
 
        pfn = page_to_pfn(virt_to_page((void *)addr));
index efaf364..f293a97 100644 (file)
@@ -172,7 +172,7 @@ static inline int __init indy_sc_probe(void)
        return 1;
 }
 
-/* XXX Check with wje if the Indy caches can differenciate between
+/* XXX Check with wje if the Indy caches can differentiate between
    writeback + invalidate and just invalidate. */
 static struct bcache_ops indy_sc_ops = {
        .bc_enable = indy_sc_enable,
index ddb8154..91dec32 100644 (file)
@@ -186,10 +186,6 @@ static int __init mips_sc_probe_cm3(void)
        return 0;
 }
 
-void __weak platform_early_l2_init(void)
-{
-}
-
 static inline int __init mips_sc_probe(void)
 {
        struct cpuinfo_mips *c = &current_cpu_data;
@@ -199,12 +195,6 @@ static inline int __init mips_sc_probe(void)
        /* Mark as not present until probe completed */
        c->scache.flags |= MIPS_CACHE_NOT_PRESENT;
 
-       /*
-        * Do we need some platform specific probing before
-        * we configure L2?
-        */
-       platform_early_l2_init();
-
        if (mips_cm_revision() >= CM_REV_CM3)
                return mips_sc_probe_cm3();
 
index 63b7d6f..b5a0234 100644 (file)
@@ -12,7 +12,7 @@
  * Copyright (C) 2011  MIPS Technologies, Inc.
  *
  * ... and the days got worse and worse and now you see
- * I've gone completly out of my mind.
+ * I've gone completely out of my mind.
  *
  * They're coming to take me a away haha
  * they're coming to take me a away hoho hihi haha
index 571148c..dc2c521 100644 (file)
@@ -293,7 +293,6 @@ mips_pci_controller:
        console_config();
 #endif
        /* Early detection of CMP support */
-       mips_cm_probe();
        mips_cpc_probe();
 
        if (!register_cps_smp_ops())
@@ -304,10 +303,3 @@ mips_pci_controller:
                return;
        register_up_smp_ops();
 }
-
-void platform_early_l2_init(void)
-{
-       /* L2 configuration lives in the CM3 */
-       if (mips_cm_revision() >= CM_REV_CM3)
-               mips_cm_probe();
-}
index 36b09b2..363c9a3 100644 (file)
@@ -154,12 +154,12 @@ static void __init plat_setup_iocoherency(void)
         * coherency instead.
         */
        if (plat_enable_iocoherency()) {
-               if (coherentio == 0)
+               if (coherentio == IO_COHERENCE_DISABLED)
                        pr_info("Hardware DMA cache coherency disabled\n");
                else
                        pr_info("Hardware DMA cache coherency enabled\n");
        } else {
-               if (coherentio == 1)
+               if (coherentio == IO_COHERENCE_ENABLED)
                        pr_info("Hardware DMA cache coherency unsupported, but enabled from command line!\n");
                else
                        pr_info("Software DMA cache coherency enabled\n");
index 2895263..f945ee8 100644 (file)
@@ -429,7 +429,8 @@ static int alchemy_pci_probe(struct platform_device *pdev)
 
        /* Au1500 revisions older than AD have borked coherent PCI */
        if ((alchemy_get_cputype() == ALCHEMY_CPU_AU1500) &&
-           (read_c0_prid() < 0x01030202) && !coherentio) {
+           (read_c0_prid() < 0x01030202) &&
+           (coherentio == IO_COHERENCE_DISABLED)) {
                val = __raw_readl(ctx->regs + PCI_REG_CONFIG);
                val |= PCI_CONFIG_NC;
                __raw_writel(val, ctx->regs + PCI_REG_CONFIG);
index 8d0eb26..f1f8829 100644 (file)
@@ -7,7 +7,7 @@
  * Copyright (C) 2000 by Silicon Graphics, Inc.
  * Copyright (C) 2004 by Christoph Hellwig
  *
- * On SGI IP27 the ARC memory configuration data is completly bogus but
+ * On SGI IP27 the ARC memory configuration data is completely bogus but
  * alternate easier to use mechanisms are available.
  */
 #include <linux/init.h>
index a2358b4..cfceaea 100644 (file)
@@ -23,7 +23,7 @@ typedef unsigned long machreg_t;
 static arch_spinlock_t nmi_lock = __ARCH_SPIN_LOCK_UNLOCKED;
 
 /*
- * Lets see what else we need to do here. Set up sp, gp?
+ * Let's see what else we need to do here. Set up sp, gp?
  */
 void nmi_dump(void)
 {
index 20f582a..4fe5678 100644 (file)
@@ -67,7 +67,7 @@ static int xbow_probe(nasid_t nasid)
                return -ENODEV;
 
        /*
-        * Okay, here's a xbow. Lets arbitrate and find
+        * Okay, here's a xbow. Let's arbitrate and find
         * out if we should initialize it. Set enabled
         * hub connected at highest or lowest widget as
         * master.
index a046b30..160b880 100644 (file)
@@ -263,7 +263,7 @@ spurious_8259A_irq:
                static int spurious_irq_mask;
                /*
                 * At this point we can be sure the IRQ is spurious,
-                * lets ACK and report it. [once per IRQ]
+                * let's ACK and report it. [once per IRQ]
                 */
                if (!(spurious_irq_mask & irqmask)) {
                        printk(KERN_DEBUG
index ce89c9e..e2690d7 100644 (file)
 #include <asm/unistd.h>
 #include <asm/vdso.h>
 
+#ifdef CONFIG_MIPS_CLOCK_VSYSCALL
+
+static __always_inline long gettimeofday_fallback(struct timeval *_tv,
+                                         struct timezone *_tz)
+{
+       register struct timezone *tz asm("a1") = _tz;
+       register struct timeval *tv asm("a0") = _tv;
+       register long ret asm("v0");
+       register long nr asm("v0") = __NR_gettimeofday;
+       register long error asm("a3");
+
+       asm volatile(
+       "       syscall\n"
+       : "=r" (ret), "=r" (error)
+       : "r" (tv), "r" (tz), "r" (nr)
+       : "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13",
+         "$14", "$15", "$24", "$25", "hi", "lo", "memory");
+
+       return error ? -ret : ret;
+}
+
+#endif
+
+static __always_inline long clock_gettime_fallback(clockid_t _clkid,
+                                          struct timespec *_ts)
+{
+       register struct timespec *ts asm("a1") = _ts;
+       register clockid_t clkid asm("a0") = _clkid;
+       register long ret asm("v0");
+       register long nr asm("v0") = __NR_clock_gettime;
+       register long error asm("a3");
+
+       asm volatile(
+       "       syscall\n"
+       : "=r" (ret), "=r" (error)
+       : "r" (clkid), "r" (ts), "r" (nr)
+       : "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13",
+         "$14", "$15", "$24", "$25", "hi", "lo", "memory");
+
+       return error ? -ret : ret;
+}
+
 static __always_inline int do_realtime_coarse(struct timespec *ts,
                                              const union mips_vdso_data *data)
 {
@@ -39,8 +81,8 @@ static __always_inline int do_monotonic_coarse(struct timespec *ts,
                                               const union mips_vdso_data *data)
 {
        u32 start_seq;
-       u32 to_mono_sec;
-       u32 to_mono_nsec;
+       u64 to_mono_sec;
+       u64 to_mono_nsec;
 
        do {
                start_seq = vdso_data_read_begin(data);
@@ -148,8 +190,8 @@ static __always_inline int do_monotonic(struct timespec *ts,
 {
        u32 start_seq;
        u64 ns;
-       u32 to_mono_sec;
-       u32 to_mono_nsec;
+       u64 to_mono_sec;
+       u64 to_mono_nsec;
 
        do {
                start_seq = vdso_data_read_begin(data);
@@ -187,7 +229,7 @@ int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
 
        ret = do_realtime(&ts, data);
        if (ret)
-               return ret;
+               return gettimeofday_fallback(tv, tz);
 
        if (tv) {
                tv->tv_sec = ts.tv_sec;
@@ -202,12 +244,12 @@ int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
        return 0;
 }
 
-#endif /* CONFIG_CLKSRC_MIPS_GIC */
+#endif /* CONFIG_MIPS_CLOCK_VSYSCALL */
 
 int __vdso_clock_gettime(clockid_t clkid, struct timespec *ts)
 {
        const union mips_vdso_data *data = get_vdso_data();
-       int ret;
+       int ret = -1;
 
        switch (clkid) {
        case CLOCK_REALTIME_COARSE:
@@ -223,10 +265,11 @@ int __vdso_clock_gettime(clockid_t clkid, struct timespec *ts)
                ret = do_monotonic(ts, data);
                break;
        default:
-               ret = -ENOSYS;
                break;
        }
 
-       /* If we return -ENOSYS libc should fall back to a syscall. */
+       if (ret)
+               ret = clock_gettime_fallback(clkid, ts);
+
        return ret;
 }
index 78ae555..e5f4a19 100644 (file)
@@ -1,5 +1,6 @@
 config MN10300
        def_bool y
+       select HAVE_EXIT_THREAD
        select HAVE_OPROFILE
        select HAVE_UID16
        select GENERIC_IRQ_SHOW
index 738ff72..a47e995 100644 (file)
@@ -76,11 +76,9 @@ static inline void unlazy_fpu(struct task_struct *tsk)
        preempt_enable();
 }
 
-static inline void exit_fpu(void)
+static inline void exit_fpu(struct task_struct *tsk)
 {
 #ifdef CONFIG_LAZY_SAVE_FPU
-       struct task_struct *tsk = current;
-
        preempt_disable();
        if (fpu_state_owner == tsk)
                fpu_state_owner = NULL;
@@ -123,7 +121,7 @@ static inline void fpu_init_state(void) {}
 static inline void fpu_save(struct fpu_state_struct *s) {}
 static inline void fpu_kill_state(struct task_struct *tsk) {}
 static inline void unlazy_fpu(struct task_struct *tsk) {}
-static inline void exit_fpu(void) {}
+static inline void exit_fpu(struct task_struct *tsk) {}
 static inline void flush_fpu(void) {}
 static inline int fpu_setup_sigcontext(struct fpucontext *buf) { return 0; }
 static inline int fpu_restore_sigcontext(struct fpucontext *buf) { return 0; }
index 3707da5..cbede4e 100644 (file)
@@ -103,9 +103,9 @@ void show_regs(struct pt_regs *regs)
 /*
  * free current thread data structures etc..
  */
-void exit_thread(void)
+void exit_thread(struct task_struct *tsk)
 {
-       exit_fpu();
+       exit_fpu(tsk);
 }
 
 void flush_thread(void)
index b9920b1..70cef54 100644 (file)
@@ -437,7 +437,7 @@ transfer_failed:
 
        info.si_signo   = SIGSEGV;
        info.si_errno   = 0;
-       info.si_code    = 0;
+       info.si_code    = SEGV_MAPERR;
        info.si_addr    = (void *) regs->pc;
        force_sig_info(SIGSEGV, &info, current);
        return;
index c2ba45c..1c953f0 100644 (file)
@@ -75,11 +75,6 @@ static inline void release_thread(struct task_struct *dead_task)
 {
 }
 
-/* Free current thread data structures etc.. */
-static inline void exit_thread(void)
-{
-}
-
 /* Return saved PC of a blocked thread. */
 #define thread_saved_pc(tsk)   ((tsk)->thread.kregs->ea)
 
index 4d235e3..70334c9 100644 (file)
@@ -85,15 +85,6 @@ void release_thread(struct task_struct *);
 unsigned long get_wchan(struct task_struct *p);
 
 /*
- * Free current thread data structures etc..
- */
-
-extern inline void exit_thread(void)
-{
-       /* Nothing needs to be done.  */
-}
-
-/*
  * Return saved PC of a blocked thread. For now, this is the "user" PC
  */
 extern unsigned long thread_saved_pc(struct task_struct *t);
index 3d3f606..605a284 100644 (file)
@@ -302,12 +302,12 @@ asmlinkage void do_unaligned_access(struct pt_regs *regs, unsigned long address)
        siginfo_t info;
 
        if (user_mode(regs)) {
-               /* Send a SIGSEGV */
-               info.si_signo = SIGSEGV;
+               /* Send a SIGBUS */
+               info.si_signo = SIGBUS;
                info.si_errno = 0;
-               /* info.si_code has been set above */
-               info.si_addr = (void *)address;
-               force_sig_info(SIGSEGV, &info, current);
+               info.si_code = BUS_ADRALN;
+               info.si_addr = (void __user *)address;
+               force_sig_info(SIGBUS, &info, current);
        } else {
                printk("KERNEL: Unaligned Access 0x%.8lx\n", address);
                show_registers(regs);
index 809905a..4063943 100644 (file)
@@ -144,13 +144,6 @@ void machine_power_off(void)
 void (*pm_power_off)(void) = machine_power_off;
 EXPORT_SYMBOL(pm_power_off);
 
-/*
- * Free current thread data structures etc..
- */
-void exit_thread(void)
-{
-}
-
 void flush_thread(void)
 {
        /* Only needs to handle fpu stuff or perf monitors.
index c628f47..f3a47e9 100644 (file)
@@ -113,6 +113,7 @@ config PPC
        select HAVE_MEMBLOCK_NODE_MAP
        select HAVE_DMA_ATTRS
        select HAVE_DMA_API_DEBUG
+       select HAVE_EXIT_THREAD
        select HAVE_OPROFILE
        select HAVE_DEBUG_KMEMLEAK
        select ARCH_HAS_SG_CHAIN
@@ -129,13 +130,14 @@ config PPC
        select IRQ_FORCED_THREADING
        select HAVE_RCU_TABLE_FREE if SMP
        select HAVE_SYSCALL_TRACEPOINTS
-       select HAVE_BPF_JIT
+       select HAVE_BPF_JIT if CPU_BIG_ENDIAN
        select HAVE_ARCH_JUMP_LABEL
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
        select ARCH_HAS_GCOV_PROFILE_ALL
        select GENERIC_SMP_IDLE_THREAD
        select GENERIC_CMOS_UPDATE
        select GENERIC_TIME_VSYSCALL_OLD
+       select GENERIC_CPU_VULNERABILITIES      if PPC_BOOK3S_64
        select GENERIC_CLOCKEVENTS
        select GENERIC_CLOCKEVENTS_BROADCAST if SMP
        select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
index a703452..555e22d 100644 (file)
@@ -209,5 +209,11 @@ exc_##label##_book3e:
        ori     r3,r3,vector_offset@l;          \
        mtspr   SPRN_IVOR##vector_number,r3;
 
+#define RFI_TO_KERNEL                                                  \
+       rfi
+
+#define RFI_TO_USER                                                    \
+       rfi
+
 #endif /* _ASM_POWERPC_EXCEPTION_64E_H */
 
index 77f52b2..9bddbec 100644 (file)
 #define EX_PPR         88      /* SMT thread status register (priority) */
 #define EX_CTR         96
 
+/*
+ * Macros for annotating the expected destination of (h)rfid
+ *
+ * The nop instructions allow us to insert one or more instructions to flush the
+ * L1-D cache when returning to userspace or a guest.
+ */
+#define RFI_FLUSH_SLOT                                                 \
+       RFI_FLUSH_FIXUP_SECTION;                                        \
+       nop;                                                            \
+       nop;                                                            \
+       nop
+
+#define RFI_TO_KERNEL                                                  \
+       rfid
+
+#define RFI_TO_USER                                                    \
+       RFI_FLUSH_SLOT;                                                 \
+       rfid;                                                           \
+       b       rfi_flush_fallback
+
+#define RFI_TO_USER_OR_KERNEL                                          \
+       RFI_FLUSH_SLOT;                                                 \
+       rfid;                                                           \
+       b       rfi_flush_fallback
+
+#define RFI_TO_GUEST                                                   \
+       RFI_FLUSH_SLOT;                                                 \
+       rfid;                                                           \
+       b       rfi_flush_fallback
+
+#define HRFI_TO_KERNEL                                                 \
+       hrfid
+
+#define HRFI_TO_USER                                                   \
+       RFI_FLUSH_SLOT;                                                 \
+       hrfid;                                                          \
+       b       hrfi_flush_fallback
+
+#define HRFI_TO_USER_OR_KERNEL                                         \
+       RFI_FLUSH_SLOT;                                                 \
+       hrfid;                                                          \
+       b       hrfi_flush_fallback
+
+#define HRFI_TO_GUEST                                                  \
+       RFI_FLUSH_SLOT;                                                 \
+       hrfid;                                                          \
+       b       hrfi_flush_fallback
+
+#define HRFI_TO_UNKNOWN                                                        \
+       RFI_FLUSH_SLOT;                                                 \
+       hrfid;                                                          \
+       b       hrfi_flush_fallback
+
 #ifdef CONFIG_RELOCATABLE
 #define __EXCEPTION_RELON_PROLOG_PSERIES_1(label, h)                   \
        ld      r12,PACAKBASE(r13);     /* get high part of &label */   \
@@ -191,7 +244,7 @@ END_FTR_SECTION_NESTED(ftr,ftr,943)
        mtspr   SPRN_##h##SRR0,r12;                                     \
        mfspr   r12,SPRN_##h##SRR1;     /* and SRR1 */                  \
        mtspr   SPRN_##h##SRR1,r10;                                     \
-       h##rfid;                                                        \
+       h##RFI_TO_KERNEL;                                               \
        b       .       /* prevent speculative execution */
 #define EXCEPTION_PROLOG_PSERIES_1(label, h)                           \
        __EXCEPTION_PROLOG_PSERIES_1(label, h)
index 9a67a38..7068baf 100644 (file)
@@ -184,4 +184,19 @@ label##3:                                          \
        FTR_ENTRY_OFFSET label##1b-label##3b;           \
        .popsection;
 
+#define RFI_FLUSH_FIXUP_SECTION                                \
+951:                                                   \
+       .pushsection __rfi_flush_fixup,"a";             \
+       .align 2;                                       \
+952:                                                   \
+       FTR_ENTRY_OFFSET 951b-952b;                     \
+       .popsection;
+
+
+#ifndef __ASSEMBLY__
+
+extern long __start___rfi_flush_fixup, __stop___rfi_flush_fixup;
+
+#endif
+
 #endif /* __ASM_POWERPC_FEATURE_FIXUPS_H */
index 85bc8c0..449bbb8 100644 (file)
 #define H_GET_HCA_INFO          0x1B8
 #define H_GET_PERF_COUNT        0x1BC
 #define H_MANAGE_TRACE          0x1C0
+#define H_GET_CPU_CHARACTERISTICS 0x1C8
 #define H_FREE_LOGICAL_LAN_BUFFER 0x1D4
 #define H_QUERY_INT_STATE       0x1E4
 #define H_POLL_PENDING         0x1D8
 #define H_SET_MODE_RESOURCE_ADDR_TRANS_MODE    3
 #define H_SET_MODE_RESOURCE_LE                 4
 
+/* H_GET_CPU_CHARACTERISTICS return values */
+#define H_CPU_CHAR_SPEC_BAR_ORI31      (1ull << 63) // IBM bit 0
+#define H_CPU_CHAR_BCCTRL_SERIALISED   (1ull << 62) // IBM bit 1
+#define H_CPU_CHAR_L1D_FLUSH_ORI30     (1ull << 61) // IBM bit 2
+#define H_CPU_CHAR_L1D_FLUSH_TRIG2     (1ull << 60) // IBM bit 3
+#define H_CPU_CHAR_L1D_THREAD_PRIV     (1ull << 59) // IBM bit 4
+
+#define H_CPU_BEHAV_FAVOUR_SECURITY    (1ull << 63) // IBM bit 0
+#define H_CPU_BEHAV_L1D_FLUSH_PR       (1ull << 62) // IBM bit 1
+#define H_CPU_BEHAV_BNDS_CHK_SPEC_BAR  (1ull << 61) // IBM bit 2
+
 #ifndef __ASSEMBLY__
+#include <linux/types.h>
 
 /**
  * plpar_hcall_norets: - Make a pseries hypervisor call with no return arguments
@@ -423,6 +436,11 @@ extern long pseries_big_endian_exceptions(void);
 
 #endif /* CONFIG_PPC_PSERIES */
 
+struct h_cpu_char_result {
+       u64 character;
+       u64 behaviour;
+};
+
 #endif /* __ASSEMBLY__ */
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_HVCALL_H */
index 70bd438..45e2aef 100644 (file)
@@ -192,6 +192,16 @@ struct paca_struct {
 #endif
        struct kvmppc_host_state kvm_hstate;
 #endif
+#ifdef CONFIG_PPC_BOOK3S_64
+       /*
+        * rfi fallback flush must be in its own cacheline to prevent
+        * other paca data leaking into the L1d
+        */
+       u64 exrfi[13] __aligned(0x80);
+       void *rfi_flush_fallback_area;
+       u64 l1d_flush_congruence;
+       u64 l1d_flush_sets;
+#endif
 };
 
 extern struct paca_struct *paca;
index 67859ed..6e05cb3 100644 (file)
@@ -323,4 +323,18 @@ static inline long plapr_set_watchpoint0(unsigned long dawr0, unsigned long dawr
        return plpar_set_mode(0, H_SET_MODE_RESOURCE_SET_DAWR, dawr0, dawrx0);
 }
 
+static inline long plpar_get_cpu_characteristics(struct h_cpu_char_result *p)
+{
+       unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+       long rc;
+
+       rc = plpar_hcall(H_GET_CPU_CHARACTERISTICS, retbuf);
+       if (rc == H_SUCCESS) {
+               p->character = retbuf[0];
+               p->behaviour = retbuf[1];
+       }
+
+       return rc;
+}
+
 #endif /* _ASM_POWERPC_PLPAR_WRAPPERS_H */
index dd0fc18..160bb23 100644 (file)
@@ -224,6 +224,16 @@ name: \
        .globl name; \
 name:
 
+#define _KPROBE_TOC(name)                      \
+       .section ".kprobes.text","a";           \
+       .align 2 ;                              \
+       .type name,@function;                   \
+       .globl name;                            \
+name:                                          \
+0:     addis r2,r12,(.TOC.-0b)@ha;             \
+       addi r2,r2,(.TOC.-0b)@l;                \
+       .localentry name,.-name
+
 #define DOTSYM(a)      a
 
 #else
@@ -261,6 +271,8 @@ name: \
        .type GLUE(.,name),@function; \
 GLUE(.,name):
 
+#define _KPROBE_TOC(n) _KPROBE(n)
+
 #define DOTSYM(a)      GLUE(.,a)
 
 #endif
index e9d384c..7916b56 100644 (file)
@@ -26,6 +26,19 @@ void initmem_init(void);
 void setup_panic(void);
 #define ARCH_PANIC_TIMEOUT 180
 
+void rfi_flush_enable(bool enable);
+
+/* These are bit flags */
+enum l1d_flush_type {
+       L1D_FLUSH_NONE          = 0x1,
+       L1D_FLUSH_FALLBACK      = 0x2,
+       L1D_FLUSH_ORI           = 0x4,
+       L1D_FLUSH_MTTRIG        = 0x8,
+};
+
+void __init setup_rfi_flush(enum l1d_flush_type, bool enable);
+void do_rfi_flush_fixups(enum l1d_flush_type types);
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* _ASM_POWERPC_SETUP_H */
index 40da691..d92705e 100644 (file)
@@ -243,6 +243,10 @@ int main(void)
 #ifdef CONFIG_PPC_BOOK3S_64
        DEFINE(PACAMCEMERGSP, offsetof(struct paca_struct, mc_emergency_sp));
        DEFINE(PACA_IN_MCE, offsetof(struct paca_struct, in_mce));
+       DEFINE(PACA_RFI_FLUSH_FALLBACK_AREA, offsetof(struct paca_struct, rfi_flush_fallback_area));
+       DEFINE(PACA_EXRFI, offsetof(struct paca_struct, exrfi));
+       DEFINE(PACA_L1D_FLUSH_CONGRUENCE, offsetof(struct paca_struct, l1d_flush_congruence));
+       DEFINE(PACA_L1D_FLUSH_SETS, offsetof(struct paca_struct, l1d_flush_sets));
 #endif
        DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id));
        DEFINE(PACAKEXECSTATE, offsetof(struct paca_struct, kexec_state));
index f6fd033..2837232 100644 (file)
 #include <asm/hw_irq.h>
 #include <asm/context_tracking.h>
 #include <asm/tm.h>
+#ifdef CONFIG_PPC_BOOK3S
+#include <asm/exception-64s.h>
+#else
+#include <asm/exception-64e.h>
+#endif
 
 /*
  * System calls.
@@ -225,13 +230,23 @@ END_FTR_SECTION_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS)
        ACCOUNT_CPU_USER_EXIT(r11, r12)
        HMT_MEDIUM_LOW_HAS_PPR
        ld      r13,GPR13(r1)   /* only restore r13 if returning to usermode */
+       ld      r2,GPR2(r1)
+       ld      r1,GPR1(r1)
+       mtlr    r4
+       mtcr    r5
+       mtspr   SPRN_SRR0,r7
+       mtspr   SPRN_SRR1,r8
+       RFI_TO_USER
+       b       .       /* prevent speculative execution */
+
+       /* exit to kernel */
 1:     ld      r2,GPR2(r1)
        ld      r1,GPR1(r1)
        mtlr    r4
        mtcr    r5
        mtspr   SPRN_SRR0,r7
        mtspr   SPRN_SRR1,r8
-       RFI
+       RFI_TO_KERNEL
        b       .       /* prevent speculative execution */
 
 syscall_error: 
@@ -353,8 +368,7 @@ tabort_syscall:
        mtmsrd  r10, 1
        mtspr   SPRN_SRR0, r11
        mtspr   SPRN_SRR1, r12
-
-       rfid
+       RFI_TO_USER
        b       .       /* prevent speculative execution */
 #endif
 
@@ -887,7 +901,7 @@ BEGIN_FTR_SECTION
 END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
        ACCOUNT_CPU_USER_EXIT(r2, r4)
        REST_GPR(13, r1)
-1:
+
        mtspr   SPRN_SRR1,r3
 
        ld      r2,_CCR(r1)
@@ -900,8 +914,22 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
        ld      r3,GPR3(r1)
        ld      r4,GPR4(r1)
        ld      r1,GPR1(r1)
+       RFI_TO_USER
+       b       .       /* prevent speculative execution */
 
-       rfid
+1:     mtspr   SPRN_SRR1,r3
+
+       ld      r2,_CCR(r1)
+       mtcrf   0xFF,r2
+       ld      r2,_NIP(r1)
+       mtspr   SPRN_SRR0,r2
+
+       ld      r0,GPR0(r1)
+       ld      r2,GPR2(r1)
+       ld      r3,GPR3(r1)
+       ld      r4,GPR4(r1)
+       ld      r1,GPR1(r1)
+       RFI_TO_KERNEL
        b       .       /* prevent speculative execution */
 
 #endif /* CONFIG_PPC_BOOK3E */
@@ -1077,7 +1105,7 @@ _GLOBAL(enter_rtas)
        
        mtspr   SPRN_SRR0,r5
        mtspr   SPRN_SRR1,r6
-       rfid
+       RFI_TO_KERNEL
        b       .       /* prevent speculative execution */
 
 rtas_return_loc:
@@ -1102,7 +1130,7 @@ rtas_return_loc:
 
        mtspr   SPRN_SRR0,r3
        mtspr   SPRN_SRR1,r4
-       rfid
+       RFI_TO_KERNEL
        b       .       /* prevent speculative execution */
 
        .align  3
@@ -1173,7 +1201,7 @@ _GLOBAL(enter_prom)
        LOAD_REG_IMMEDIATE(r12, MSR_SF | MSR_ISF | MSR_LE)
        andc    r11,r11,r12
        mtsrr1  r11
-       rfid
+       RFI_TO_KERNEL
 #endif /* CONFIG_PPC_BOOK3E */
 
 1:     /* Return from OF */
index b81ccc5..938a30f 100644 (file)
@@ -46,7 +46,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE)                                \
        mtspr   SPRN_SRR0,r10 ;                                 \
        ld      r10,PACAKMSR(r13) ;                             \
        mtspr   SPRN_SRR1,r10 ;                                 \
-       rfid ;                                                  \
+       RFI_TO_KERNEL ;                                                         \
        b       . ;     /* prevent speculative execution */
 
 #define SYSCALL_PSERIES_3                                      \
@@ -54,7 +54,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE)                                \
 1:     mfspr   r12,SPRN_SRR1 ;                                 \
        xori    r12,r12,MSR_LE ;                                \
        mtspr   SPRN_SRR1,r12 ;                                 \
-       rfid ;          /* return to userspace */               \
+       RFI_TO_USER ;           /* return to userspace */               \
        b       . ;     /* prevent speculative execution */
 
 #if defined(CONFIG_RELOCATABLE)
@@ -507,7 +507,7 @@ BEGIN_FTR_SECTION
        LOAD_HANDLER(r12, machine_check_handle_early)
 1:     mtspr   SPRN_SRR0,r12
        mtspr   SPRN_SRR1,r11
-       rfid
+       RFI_TO_KERNEL
        b       .       /* prevent speculative execution */
 2:
        /* Stack overflow. Stay on emergency stack and panic.
@@ -601,7 +601,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
        ld      r11,PACA_EXGEN+EX_R11(r13)
        ld      r12,PACA_EXGEN+EX_R12(r13)
        ld      r13,PACA_EXGEN+EX_R13(r13)
-       HRFID
+       HRFI_TO_UNKNOWN
        b       .
 #endif
 
@@ -666,7 +666,7 @@ masked_##_H##interrupt:                                     \
        ld      r10,PACA_EXGEN+EX_R10(r13);             \
        ld      r11,PACA_EXGEN+EX_R11(r13);             \
        GET_SCRATCH0(r13);                              \
-       ##_H##rfid;                                     \
+       ##_H##RFI_TO_KERNEL;                            \
        b       .
        
        MASKED_INTERRUPT()
@@ -756,7 +756,7 @@ kvmppc_skip_interrupt:
        addi    r13, r13, 4
        mtspr   SPRN_SRR0, r13
        GET_SCRATCH0(r13)
-       rfid
+       RFI_TO_KERNEL
        b       .
 
 kvmppc_skip_Hinterrupt:
@@ -768,7 +768,7 @@ kvmppc_skip_Hinterrupt:
        addi    r13, r13, 4
        mtspr   SPRN_HSRR0, r13
        GET_SCRATCH0(r13)
-       hrfid
+       HRFI_TO_KERNEL
        b       .
 #endif
 
@@ -1439,7 +1439,7 @@ machine_check_handle_early:
        li      r3,MSR_ME
        andc    r10,r10,r3              /* Turn off MSR_ME */
        mtspr   SPRN_SRR1,r10
-       rfid
+       RFI_TO_KERNEL
        b       .
 2:
        /*
@@ -1457,7 +1457,7 @@ machine_check_handle_early:
         */
        bl      machine_check_queue_event
        MACHINE_CHECK_HANDLER_WINDUP
-       rfid
+       RFI_TO_USER_OR_KERNEL
 9:
        /* Deliver the machine check to host kernel in V mode. */
        MACHINE_CHECK_HANDLER_WINDUP
@@ -1503,6 +1503,8 @@ slb_miss_realmode:
 
        andi.   r10,r12,MSR_RI  /* check for unrecoverable exception */
        beq-    2f
+       andi.   r10,r12,MSR_PR  /* check for user mode (PR != 0) */
+       bne     1f
 
 .machine       push
 .machine       "power4"
@@ -1516,7 +1518,23 @@ slb_miss_realmode:
        ld      r11,PACA_EXSLB+EX_R11(r13)
        ld      r12,PACA_EXSLB+EX_R12(r13)
        ld      r13,PACA_EXSLB+EX_R13(r13)
-       rfid
+       RFI_TO_KERNEL
+       b       .       /* prevent speculative execution */
+
+1:
+.machine       push
+.machine       "power4"
+       mtcrf   0x80,r9
+       mtcrf   0x01,r9         /* slb_allocate uses cr0 and cr7 */
+.machine       pop
+
+       RESTORE_PPR_PACA(PACA_EXSLB, r9)
+       ld      r9,PACA_EXSLB+EX_R9(r13)
+       ld      r10,PACA_EXSLB+EX_R10(r13)
+       ld      r11,PACA_EXSLB+EX_R11(r13)
+       ld      r12,PACA_EXSLB+EX_R12(r13)
+       ld      r13,PACA_EXSLB+EX_R13(r13)
+       RFI_TO_USER
        b       .       /* prevent speculative execution */
 
 2:     mfspr   r11,SPRN_SRR0
@@ -1525,7 +1543,7 @@ slb_miss_realmode:
        mtspr   SPRN_SRR0,r10
        ld      r10,PACAKMSR(r13)
        mtspr   SPRN_SRR1,r10
-       rfid
+       RFI_TO_KERNEL
        b       .
 
 unrecov_slb:
@@ -1546,6 +1564,92 @@ power4_fixup_nap:
        blr
 #endif
 
+       .globl rfi_flush_fallback
+rfi_flush_fallback:
+       SET_SCRATCH0(r13);
+       GET_PACA(r13);
+       std     r9,PACA_EXRFI+EX_R9(r13)
+       std     r10,PACA_EXRFI+EX_R10(r13)
+       std     r11,PACA_EXRFI+EX_R11(r13)
+       std     r12,PACA_EXRFI+EX_R12(r13)
+       std     r8,PACA_EXRFI+EX_R13(r13)
+       mfctr   r9
+       ld      r10,PACA_RFI_FLUSH_FALLBACK_AREA(r13)
+       ld      r11,PACA_L1D_FLUSH_SETS(r13)
+       ld      r12,PACA_L1D_FLUSH_CONGRUENCE(r13)
+       /*
+        * The load adresses are at staggered offsets within cachelines,
+        * which suits some pipelines better (on others it should not
+        * hurt).
+        */
+       addi    r12,r12,8
+       mtctr   r11
+       DCBT_STOP_ALL_STREAM_IDS(r11) /* Stop prefetch streams */
+
+       /* order ld/st prior to dcbt stop all streams with flushing */
+       sync
+1:     li      r8,0
+       .rept   8 /* 8-way set associative */
+       ldx     r11,r10,r8
+       add     r8,r8,r12
+       xor     r11,r11,r11     // Ensure r11 is 0 even if fallback area is not
+       add     r8,r8,r11       // Add 0, this creates a dependency on the ldx
+       .endr
+       addi    r10,r10,128 /* 128 byte cache line */
+       bdnz    1b
+
+       mtctr   r9
+       ld      r9,PACA_EXRFI+EX_R9(r13)
+       ld      r10,PACA_EXRFI+EX_R10(r13)
+       ld      r11,PACA_EXRFI+EX_R11(r13)
+       ld      r12,PACA_EXRFI+EX_R12(r13)
+       ld      r8,PACA_EXRFI+EX_R13(r13)
+       GET_SCRATCH0(r13);
+       rfid
+
+       .globl hrfi_flush_fallback
+hrfi_flush_fallback:
+       SET_SCRATCH0(r13);
+       GET_PACA(r13);
+       std     r9,PACA_EXRFI+EX_R9(r13)
+       std     r10,PACA_EXRFI+EX_R10(r13)
+       std     r11,PACA_EXRFI+EX_R11(r13)
+       std     r12,PACA_EXRFI+EX_R12(r13)
+       std     r8,PACA_EXRFI+EX_R13(r13)
+       mfctr   r9
+       ld      r10,PACA_RFI_FLUSH_FALLBACK_AREA(r13)
+       ld      r11,PACA_L1D_FLUSH_SETS(r13)
+       ld      r12,PACA_L1D_FLUSH_CONGRUENCE(r13)
+       /*
+        * The load adresses are at staggered offsets within cachelines,
+        * which suits some pipelines better (on others it should not
+        * hurt).
+        */
+       addi    r12,r12,8
+       mtctr   r11
+       DCBT_STOP_ALL_STREAM_IDS(r11) /* Stop prefetch streams */
+
+       /* order ld/st prior to dcbt stop all streams with flushing */
+       sync
+1:     li      r8,0
+       .rept   8 /* 8-way set associative */
+       ldx     r11,r10,r8
+       add     r8,r8,r12
+       xor     r11,r11,r11     // Ensure r11 is 0 even if fallback area is not
+       add     r8,r8,r11       // Add 0, this creates a dependency on the ldx
+       .endr
+       addi    r10,r10,128 /* 128 byte cache line */
+       bdnz    1b
+
+       mtctr   r9
+       ld      r9,PACA_EXRFI+EX_R9(r13)
+       ld      r10,PACA_EXRFI+EX_R10(r13)
+       ld      r11,PACA_EXRFI+EX_R11(r13)
+       ld      r12,PACA_EXRFI+EX_R12(r13)
+       ld      r8,PACA_EXRFI+EX_R13(r13)
+       GET_SCRATCH0(r13);
+       hrfid
+
 /*
  * Hash table stuff
  */
index db475d4..1075882 100644 (file)
@@ -66,7 +66,7 @@ PPC64_CACHES:
  *   flush all bytes from start through stop-1 inclusive
  */
 
-_KPROBE(flush_icache_range)
+_KPROBE_TOC(flush_icache_range)
 BEGIN_FTR_SECTION
        PURGE_PREFETCHED_INS
        blr
@@ -117,7 +117,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
  *
  *    flush all bytes from start to stop-1 inclusive
  */
-_GLOBAL(flush_dcache_range)
+_GLOBAL_TOC(flush_dcache_range)
 
 /*
  * Flush the data cache to memory 
@@ -701,31 +701,3 @@ _GLOBAL(kexec_sequence)
        li      r5,0
        blr     /* image->start(physid, image->start, 0); */
 #endif /* CONFIG_KEXEC */
-
-#ifdef CONFIG_MODULES
-#if defined(_CALL_ELF) && _CALL_ELF == 2
-
-#ifdef CONFIG_MODVERSIONS
-.weak __crc_TOC.
-.section "___kcrctab+TOC.","a"
-.globl __kcrctab_TOC.
-__kcrctab_TOC.:
-       .llong  __crc_TOC.
-#endif
-
-/*
- * Export a fake .TOC. since both modpost and depmod will complain otherwise.
- * Both modpost and depmod strip the leading . so we do the same here.
- */
-.section "__ksymtab_strings","a"
-__kstrtab_TOC.:
-       .asciz "TOC."
-
-.section "___ksymtab+TOC.","a"
-/* This symbol name is important: it's used by modpost to find exported syms */
-.globl __ksymtab_TOC.
-__ksymtab_TOC.:
-       .llong 0 /* .value */
-       .llong __kstrtab_TOC.
-#endif /* ELFv2 */
-#endif /* MODULES */
index e4f7d4e..08b7a40 100644 (file)
@@ -326,7 +326,10 @@ static void dedotify_versions(struct modversion_info *vers,
                }
 }
 
-/* Undefined symbols which refer to .funcname, hack to funcname (or .TOC.) */
+/*
+ * Undefined symbols which refer to .funcname, hack to funcname. Make .TOC.
+ * seem to be defined (value set later).
+ */
 static void dedotify(Elf64_Sym *syms, unsigned int numsyms, char *strtab)
 {
        unsigned int i;
@@ -334,8 +337,11 @@ static void dedotify(Elf64_Sym *syms, unsigned int numsyms, char *strtab)
        for (i = 1; i < numsyms; i++) {
                if (syms[i].st_shndx == SHN_UNDEF) {
                        char *name = strtab + syms[i].st_name;
-                       if (name[0] == '.')
+                       if (name[0] == '.') {
+                               if (strcmp(name+1, "TOC.") == 0)
+                                       syms[i].st_shndx = SHN_ABS;
                                syms[i].st_name++;
+                       }
                }
        }
 }
@@ -351,7 +357,7 @@ static Elf64_Sym *find_dot_toc(Elf64_Shdr *sechdrs,
        numsyms = sechdrs[symindex].sh_size / sizeof(Elf64_Sym);
 
        for (i = 1; i < numsyms; i++) {
-               if (syms[i].st_shndx == SHN_UNDEF
+               if (syms[i].st_shndx == SHN_ABS
                    && strcmp(strtab + syms[i].st_name, "TOC.") == 0)
                        return &syms[i];
        }
index b7abf3c..ef5f566 100644 (file)
@@ -209,7 +209,8 @@ void enable_kernel_vsx(void)
        WARN_ON(preemptible());
 
 #ifdef CONFIG_SMP
-       if (current->thread.regs && (current->thread.regs->msr & MSR_VSX))
+       if (current->thread.regs &&
+           (current->thread.regs->msr & (MSR_VSX|MSR_VEC|MSR_FP)))
                giveup_vsx(current);
        else
                giveup_vsx(NULL);       /* just enable vsx for kernel - force */
@@ -231,7 +232,7 @@ void flush_vsx_to_thread(struct task_struct *tsk)
 {
        if (tsk->thread.regs) {
                preempt_disable();
-               if (tsk->thread.regs->msr & MSR_VSX) {
+               if (tsk->thread.regs->msr & (MSR_VSX|MSR_VEC|MSR_FP)) {
 #ifdef CONFIG_SMP
                        BUG_ON(tsk != current);
 #endif
index a208232..df4a87e 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/hugetlb.h>
 #include <linux/memory.h>
 #include <linux/nmi.h>
+#include <linux/debugfs.h>
 
 #include <asm/io.h>
 #include <asm/kdump.h>
@@ -834,4 +835,142 @@ static int __init disable_hardlockup_detector(void)
        return 0;
 }
 early_initcall(disable_hardlockup_detector);
+
+#ifdef CONFIG_PPC_BOOK3S_64
+static enum l1d_flush_type enabled_flush_types;
+static void *l1d_flush_fallback_area;
+static bool no_rfi_flush;
+bool rfi_flush;
+
+static int __init handle_no_rfi_flush(char *p)
+{
+       pr_info("rfi-flush: disabled on command line.");
+       no_rfi_flush = true;
+       return 0;
+}
+early_param("no_rfi_flush", handle_no_rfi_flush);
+
+/*
+ * The RFI flush is not KPTI, but because users will see doco that says to use
+ * nopti we hijack that option here to also disable the RFI flush.
+ */
+static int __init handle_no_pti(char *p)
+{
+       pr_info("rfi-flush: disabling due to 'nopti' on command line.\n");
+       handle_no_rfi_flush(NULL);
+       return 0;
+}
+early_param("nopti", handle_no_pti);
+
+static void do_nothing(void *unused)
+{
+       /*
+        * We don't need to do the flush explicitly, just enter+exit kernel is
+        * sufficient, the RFI exit handlers will do the right thing.
+        */
+}
+
+void rfi_flush_enable(bool enable)
+{
+       if (rfi_flush == enable)
+               return;
+
+       if (enable) {
+               do_rfi_flush_fixups(enabled_flush_types);
+               on_each_cpu(do_nothing, NULL, 1);
+       } else
+               do_rfi_flush_fixups(L1D_FLUSH_NONE);
+
+       rfi_flush = enable;
+}
+
+static void init_fallback_flush(void)
+{
+       u64 l1d_size, limit;
+       int cpu;
+
+       l1d_size = ppc64_caches.dsize;
+       limit = min(safe_stack_limit(), ppc64_rma_size);
+
+       /*
+        * Align to L1d size, and size it at 2x L1d size, to catch possible
+        * hardware prefetch runoff. We don't have a recipe for load patterns to
+        * reliably avoid the prefetcher.
+        */
+       l1d_flush_fallback_area = __va(memblock_alloc_base(l1d_size * 2, l1d_size, limit));
+       memset(l1d_flush_fallback_area, 0, l1d_size * 2);
+
+       for_each_possible_cpu(cpu) {
+               /*
+                * The fallback flush is currently coded for 8-way
+                * associativity. Different associativity is possible, but it
+                * will be treated as 8-way and may not evict the lines as
+                * effectively.
+                *
+                * 128 byte lines are mandatory.
+                */
+               u64 c = l1d_size / 8;
+
+               paca[cpu].rfi_flush_fallback_area = l1d_flush_fallback_area;
+               paca[cpu].l1d_flush_congruence = c;
+               paca[cpu].l1d_flush_sets = c / 128;
+       }
+}
+
+void __init setup_rfi_flush(enum l1d_flush_type types, bool enable)
+{
+       if (types & L1D_FLUSH_FALLBACK) {
+               pr_info("rfi-flush: Using fallback displacement flush\n");
+               init_fallback_flush();
+       }
+
+       if (types & L1D_FLUSH_ORI)
+               pr_info("rfi-flush: Using ori type flush\n");
+
+       if (types & L1D_FLUSH_MTTRIG)
+               pr_info("rfi-flush: Using mttrig type flush\n");
+
+       enabled_flush_types = types;
+
+       if (!no_rfi_flush)
+               rfi_flush_enable(enable);
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int rfi_flush_set(void *data, u64 val)
+{
+       if (val == 1)
+               rfi_flush_enable(true);
+       else if (val == 0)
+               rfi_flush_enable(false);
+       else
+               return -EINVAL;
+
+       return 0;
+}
+
+static int rfi_flush_get(void *data, u64 *val)
+{
+       *val = rfi_flush ? 1 : 0;
+       return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_rfi_flush, rfi_flush_get, rfi_flush_set, "%llu\n");
+
+static __init int rfi_flush_debugfs_init(void)
+{
+       debugfs_create_file("rfi_flush", 0600, powerpc_debugfs_root, NULL, &fops_rfi_flush);
+       return 0;
+}
+device_initcall(rfi_flush_debugfs_init);
+#endif
+
+ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       if (rfi_flush)
+               return sprintf(buf, "Mitigation: RFI Flush\n");
+
+       return sprintf(buf, "Vulnerable\n");
+}
+#endif /* CONFIG_PPC_BOOK3S_64 */
 #endif
index 2dd91f7..30f90e8 100644 (file)
@@ -73,6 +73,15 @@ SECTIONS
        /* Read-only data */
        RODATA
 
+#ifdef CONFIG_PPC64
+       . = ALIGN(8);
+       __rfi_flush_fixup : AT(ADDR(__rfi_flush_fixup) - LOAD_OFFSET) {
+               __start___rfi_flush_fixup = .;
+               *(__rfi_flush_fixup)
+               __stop___rfi_flush_fixup = .;
+       }
+#endif
+
        EXCEPTION_TABLE(0)
 
        NOTES :kernel :notes
index ffab926..4463718 100644 (file)
@@ -64,7 +64,7 @@ _GLOBAL_TOC(kvmppc_hv_entry_trampoline)
        mtmsrd  r0,1            /* clear RI in MSR */
        mtsrr0  r5
        mtsrr1  r6
-       RFI
+       RFI_TO_KERNEL
 
 kvmppc_call_hv_entry:
        ld      r4, HSTATE_KVM_VCPU(r13)
@@ -170,7 +170,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
        mtsrr0  r8
        mtsrr1  r7
        beq     cr1, 13f                /* machine check */
-       RFI
+       RFI_TO_KERNEL
 
        /* On POWER7, we have external interrupts set to use HSRR0/1 */
 11:    mtspr   SPRN_HSRR0, r8
@@ -965,8 +965,7 @@ BEGIN_FTR_SECTION
 END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
        ld      r0, VCPU_GPR(R0)(r4)
        ld      r4, VCPU_GPR(R4)(r4)
-
-       hrfid
+       HRFI_TO_GUEST
        b       .
 
 secondary_too_late:
index 16c4d88..a328f99 100644 (file)
@@ -46,6 +46,9 @@
 
 #define FUNC(name)             name
 
+#define RFI_TO_KERNEL  RFI
+#define RFI_TO_GUEST   RFI
+
 .macro INTERRUPT_TRAMPOLINE intno
 
 .global kvmppc_trampoline_\intno
@@ -141,7 +144,7 @@ kvmppc_handler_skip_ins:
        GET_SCRATCH0(r13)
 
        /* And get back into the code */
-       RFI
+       RFI_TO_KERNEL
 #endif
 
 /*
@@ -164,6 +167,6 @@ _GLOBAL_TOC(kvmppc_entry_trampoline)
        ori     r5, r5, MSR_EE
        mtsrr0  r7
        mtsrr1  r6
-       RFI
+       RFI_TO_KERNEL
 
 #include "book3s_segment.S"
index ca8f174..7c98295 100644 (file)
@@ -156,7 +156,7 @@ no_dcbz32_on:
        PPC_LL  r9, SVCPU_R9(r3)
        PPC_LL  r3, (SVCPU_R3)(r3)
 
-       RFI
+       RFI_TO_GUEST
 kvmppc_handler_trampoline_enter_end:
 
 
@@ -389,5 +389,5 @@ END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)
        cmpwi   r12, BOOK3S_INTERRUPT_DOORBELL
        beqa    BOOK3S_INTERRUPT_DOORBELL
 
-       RFI
+       RFI_TO_KERNEL
 kvmppc_handler_trampoline_exit_end:
index 7ce3870..a18d648 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/code-patching.h>
 #include <asm/page.h>
 #include <asm/sections.h>
+#include <asm/setup.h>
 
 
 struct fixup_entry {
@@ -113,6 +114,47 @@ void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end)
        }
 }
 
+#ifdef CONFIG_PPC_BOOK3S_64
+void do_rfi_flush_fixups(enum l1d_flush_type types)
+{
+       unsigned int instrs[3], *dest;
+       long *start, *end;
+       int i;
+
+       start = PTRRELOC(&__start___rfi_flush_fixup),
+       end = PTRRELOC(&__stop___rfi_flush_fixup);
+
+       instrs[0] = 0x60000000; /* nop */
+       instrs[1] = 0x60000000; /* nop */
+       instrs[2] = 0x60000000; /* nop */
+
+       if (types & L1D_FLUSH_FALLBACK)
+               /* b .+16 to fallback flush */
+               instrs[0] = 0x48000010;
+
+       i = 0;
+       if (types & L1D_FLUSH_ORI) {
+               instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */
+               instrs[i++] = 0x63de0000; /* ori 30,30,0 L1d flush*/
+       }
+
+       if (types & L1D_FLUSH_MTTRIG)
+               instrs[i++] = 0x7c12dba6; /* mtspr TRIG2,r0 (SPR #882) */
+
+       for (i = 0; start < end; start++, i++) {
+               dest = (void *)start + *start;
+
+               pr_devel("patching dest %lx\n", (unsigned long)dest);
+
+               patch_instruction(dest, instrs[0]);
+               patch_instruction(dest + 1, instrs[1]);
+               patch_instruction(dest + 2, instrs[2]);
+       }
+
+       printk(KERN_DEBUG "rfi-flush: patched %d locations\n", i);
+}
+#endif /* CONFIG_PPC_BOOK3S_64 */
+
 void do_lwsync_fixups(unsigned long value, void *fixup_start, void *fixup_end)
 {
        long *start, *end;
index b2ab164..4eba7c0 100644 (file)
@@ -1381,7 +1381,7 @@ static int collect_events(struct perf_event *group, int max_count,
        int n = 0;
        struct perf_event *event;
 
-       if (!is_software_event(group)) {
+       if (group->pmu->task_ctx_nr == perf_hw_context) {
                if (n >= max_count)
                        return -1;
                ctrs[n] = group;
@@ -1389,7 +1389,7 @@ static int collect_events(struct perf_event *group, int max_count,
                events[n++] = group->hw.config;
        }
        list_for_each_entry(event, &group->sibling_list, group_entry) {
-               if (!is_software_event(event) &&
+               if (event->pmu->task_ctx_nr == perf_hw_context &&
                    event->state != PERF_EVENT_STATE_OFF) {
                        if (n >= max_count)
                                return -1;
index f48afc0..30c6b3b 100644 (file)
 #include <asm/opal.h>
 #include <asm/kexec.h>
 #include <asm/smp.h>
+#include <asm/tm.h>
+#include <asm/setup.h>
 
 #include "powernv.h"
 
+static void pnv_setup_rfi_flush(void)
+{
+       struct device_node *np, *fw_features;
+       enum l1d_flush_type type;
+       int enable;
+
+       /* Default to fallback in case fw-features are not available */
+       type = L1D_FLUSH_FALLBACK;
+       enable = 1;
+
+       np = of_find_node_by_name(NULL, "ibm,opal");
+       fw_features = of_get_child_by_name(np, "fw-features");
+       of_node_put(np);
+
+       if (fw_features) {
+               np = of_get_child_by_name(fw_features, "inst-l1d-flush-trig2");
+               if (np && of_property_read_bool(np, "enabled"))
+                       type = L1D_FLUSH_MTTRIG;
+
+               of_node_put(np);
+
+               np = of_get_child_by_name(fw_features, "inst-l1d-flush-ori30,30,0");
+               if (np && of_property_read_bool(np, "enabled"))
+                       type = L1D_FLUSH_ORI;
+
+               of_node_put(np);
+
+               /* Enable unless firmware says NOT to */
+               enable = 2;
+               np = of_get_child_by_name(fw_features, "needs-l1d-flush-msr-hv-1-to-0");
+               if (np && of_property_read_bool(np, "disabled"))
+                       enable--;
+
+               of_node_put(np);
+
+               np = of_get_child_by_name(fw_features, "needs-l1d-flush-msr-pr-0-to-1");
+               if (np && of_property_read_bool(np, "disabled"))
+                       enable--;
+
+               of_node_put(np);
+               of_node_put(fw_features);
+       }
+
+       setup_rfi_flush(type, enable > 0);
+}
+
 static void __init pnv_setup_arch(void)
 {
        set_arch_panic_timeout(10, ARCH_PANIC_TIMEOUT);
 
+       pnv_setup_rfi_flush();
+
        /* Initialize SMP */
        pnv_smp_init();
 
index 36df46e..dd2545f 100644 (file)
@@ -499,6 +499,39 @@ static void __init find_and_init_phbs(void)
        of_pci_check_probe_only();
 }
 
+static void pseries_setup_rfi_flush(void)
+{
+       struct h_cpu_char_result result;
+       enum l1d_flush_type types;
+       bool enable;
+       long rc;
+
+       /* Enable by default */
+       enable = true;
+
+       rc = plpar_get_cpu_characteristics(&result);
+       if (rc == H_SUCCESS) {
+               types = L1D_FLUSH_NONE;
+
+               if (result.character & H_CPU_CHAR_L1D_FLUSH_TRIG2)
+                       types |= L1D_FLUSH_MTTRIG;
+               if (result.character & H_CPU_CHAR_L1D_FLUSH_ORI30)
+                       types |= L1D_FLUSH_ORI;
+
+               /* Use fallback if nothing set in hcall */
+               if (types == L1D_FLUSH_NONE)
+                       types = L1D_FLUSH_FALLBACK;
+
+               if (!(result.behaviour & H_CPU_BEHAV_L1D_FLUSH_PR))
+                       enable = false;
+       } else {
+               /* Default to fallback if case hcall is not available */
+               types = L1D_FLUSH_FALLBACK;
+       }
+
+       setup_rfi_flush(types, enable);
+}
+
 static void __init pSeries_setup_arch(void)
 {
        set_arch_panic_timeout(10, ARCH_PANIC_TIMEOUT);
@@ -515,7 +548,9 @@ static void __init pSeries_setup_arch(void)
 
        fwnmi_init();
 
-       /* By default, only probe PCI (can be overriden by rtas_pci) */
+       pseries_setup_rfi_flush();
+
+       /* By default, only probe PCI (can be overridden by rtas_pci) */
        pci_add_flags(PCI_PROBE_ONLY);
 
        /* Find and initialize PCI host bridges */
index 0176ebc..86f9342 100644 (file)
@@ -110,7 +110,7 @@ COMPAT_SYSCALL_DEFINE2(s390_setregid16, u16, rgid, u16, egid)
 
 COMPAT_SYSCALL_DEFINE1(s390_setgid16, u16, gid)
 {
-       return sys_setgid((gid_t)gid);
+       return sys_setgid(low2highgid(gid));
 }
 
 COMPAT_SYSCALL_DEFINE2(s390_setreuid16, u16, ruid, u16, euid)
@@ -120,7 +120,7 @@ COMPAT_SYSCALL_DEFINE2(s390_setreuid16, u16, ruid, u16, euid)
 
 COMPAT_SYSCALL_DEFINE1(s390_setuid16, u16, uid)
 {
-       return sys_setuid((uid_t)uid);
+       return sys_setuid(low2highuid(uid));
 }
 
 COMPAT_SYSCALL_DEFINE3(s390_setresuid16, u16, ruid, u16, euid, u16, suid)
@@ -173,12 +173,12 @@ COMPAT_SYSCALL_DEFINE3(s390_getresgid16, u16 __user *, rgidp,
 
 COMPAT_SYSCALL_DEFINE1(s390_setfsuid16, u16, uid)
 {
-       return sys_setfsuid((uid_t)uid);
+       return sys_setfsuid(low2highuid(uid));
 }
 
 COMPAT_SYSCALL_DEFINE1(s390_setfsgid16, u16, gid)
 {
-       return sys_setfsgid((gid_t)gid);
+       return sys_setfsgid(low2highgid(gid));
 }
 
 static int groups16_to_user(u16 __user *grouplist, struct group_info *group_info)
index 7bc4e4c..d1653cc 100644 (file)
@@ -67,13 +67,6 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
 
 extern void kernel_thread_starter(void);
 
-/*
- * Free current thread data structures etc..
- */
-void exit_thread(void)
-{
-}
-
 void flush_thread(void)
 {
 }
index a1519ad..aae9480 100644 (file)
@@ -56,8 +56,6 @@ void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp)
        regs->regs[0] = sp;
 }
 
-void exit_thread(void) {}
-
 /*
  * When a process does an "exec", machine state like FPU and debug
  * registers need to be reset.  This is a hook function for that.
index d514df7..0bc9282 100644 (file)
@@ -71,6 +71,7 @@ config SUPERH32
 
 config SUPERH64
        def_bool ARCH = "sh64"
+       select HAVE_EXIT_THREAD
        select KALLSYMS
 
 config ARCH_DEFCONFIG
index 2885fc9..ee12e94 100644 (file)
@@ -76,13 +76,6 @@ void start_thread(struct pt_regs *regs, unsigned long new_pc,
 }
 EXPORT_SYMBOL(start_thread);
 
-/*
- * Free current thread data structures etc..
- */
-void exit_thread(void)
-{
-}
-
 void flush_thread(void)
 {
        struct task_struct *tsk = current;
index e2062e6..9d3e991 100644 (file)
@@ -288,7 +288,7 @@ void show_regs(struct pt_regs *regs)
 /*
  * Free current thread data structures etc..
  */
-void exit_thread(void)
+void exit_thread(struct task_struct *tsk)
 {
        /*
         * See arch/sparc/kernel/process.c for the precedent for doing
@@ -307,9 +307,8 @@ void exit_thread(void)
         * which it would get safely nulled.
         */
 #ifdef CONFIG_SH_FPU
-       if (last_task_used_math == current) {
+       if (last_task_used_math == tsk)
                last_task_used_math = NULL;
-       }
 #endif
 }
 
index ff63934..c5b9977 100644 (file)
@@ -607,7 +607,8 @@ asmlinkage void do_divide_error(unsigned long r4)
                break;
        }
 
-       force_sig_info(SIGFPE, &info, current);
+       info.si_signo = SIGFPE;
+       force_sig_info(info.si_signo, &info, current);
 }
 #endif
 
index 1cf6a15..a1eb588 100644 (file)
@@ -20,6 +20,7 @@ config SPARC
        select HAVE_OPROFILE
        select HAVE_ARCH_KGDB if !SMP || SPARC64
        select HAVE_ARCH_TRACEHOOK
+       select HAVE_EXIT_THREAD
        select SYSCTL_EXCEPTION_TRACE
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
index c5113c7..b7780a5 100644 (file)
@@ -184,21 +184,21 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
 /*
  * Free current thread data structures etc..
  */
-void exit_thread(void)
+void exit_thread(struct task_struct *tsk)
 {
 #ifndef CONFIG_SMP
-       if(last_task_used_math == current) {
+       if (last_task_used_math == tsk) {
 #else
-       if (test_thread_flag(TIF_USEDFPU)) {
+       if (test_ti_thread_flag(task_thread_info(tsk), TIF_USEDFPU)) {
 #endif
                /* Keep process from leaving FPU in a bogon state. */
                put_psr(get_psr() | PSR_EF);
-               fpsave(&current->thread.float_regs[0], &current->thread.fsr,
-                      &current->thread.fpqueue[0], &current->thread.fpqdepth);
+               fpsave(&tsk->thread.float_regs[0], &tsk->thread.fsr,
+                      &tsk->thread.fpqueue[0], &tsk->thread.fpqdepth);
 #ifndef CONFIG_SMP
                last_task_used_math = NULL;
 #else
-               clear_thread_flag(TIF_USEDFPU);
+               clear_ti_thread_flag(task_thread_info(tsk), TIF_USEDFPU);
 #endif
        }
 }
index 46a5964..7c3fc58 100644 (file)
@@ -417,9 +417,9 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
 }
 
 /* Free current thread data structures etc.. */
-void exit_thread(void)
+void exit_thread(struct task_struct *tsk)
 {
-       struct thread_info *t = current_thread_info();
+       struct thread_info *t = task_thread_info(tsk);
 
        if (t->utraps) {
                if (t->utraps[0] < 2)
index 8ec7a45..09d4656 100644 (file)
@@ -3,6 +3,7 @@
 
 config TILE
        def_bool y
+       select HAVE_EXIT_THREAD
        select HAVE_PERF_EVENTS
        select USE_PMC if PERF_EVENTS
        select HAVE_DMA_ATTRS
index a97ab1a..c5f3c1a 100644 (file)
@@ -539,7 +539,7 @@ void flush_thread(void)
 /*
  * Free current thread data structures etc..
  */
-void exit_thread(void)
+void exit_thread(struct task_struct *tsk)
 {
 #ifdef CONFIG_HARDWALL
        /*
@@ -548,7 +548,7 @@ void exit_thread(void)
         * the last reference to a hardwall fd, it would already have
         * been released and deactivated at this point.)
         */
-       hardwall_deactivate_all(current);
+       hardwall_deactivate_all(tsk);
 #endif
 }
 
index 48af59a..0b04711 100644 (file)
@@ -103,10 +103,6 @@ void interrupt_end(void)
                tracehook_notify_resume(regs);
 }
 
-void exit_thread(void)
-{
-}
-
 int get_current_pid(void)
 {
        return task_pid_nr(current);
index b008e99..00299c9 100644 (file)
@@ -201,13 +201,6 @@ void show_regs(struct pt_regs *regs)
        __backtrace();
 }
 
-/*
- * Free current thread data structures etc..
- */
-void exit_thread(void)
-{
-}
-
 void flush_thread(void)
 {
        struct thread_info *thread = current_thread_info();
index ddc3abd..33bb33e 100644 (file)
@@ -108,6 +108,7 @@ config X86
        select HAVE_DYNAMIC_FTRACE
        select HAVE_DYNAMIC_FTRACE_WITH_REGS
        select HAVE_EFFICIENT_UNALIGNED_ACCESS
+       select HAVE_EXIT_THREAD
        select HAVE_FENTRY                      if X86_64
        select HAVE_FTRACE_MCOUNT_RECORD
        select HAVE_FUNCTION_GRAPH_FP_TEST
@@ -1026,7 +1027,7 @@ config X86_MCE_THRESHOLD
        def_bool y
 
 config X86_MCE_INJECT
-       depends on X86_MCE
+       depends on X86_MCE && X86_LOCAL_APIC
        tristate "Machine check injector support"
        ---help---
          Provide support for injecting machine checks for testing purposes.
index 1f6c306..e5031f4 100644 (file)
@@ -379,6 +379,7 @@ config X86_DEBUG_FPU
 
 config PUNIT_ATOM_DEBUG
        tristate "ATOM Punit debug driver"
+       depends on PCI
        select DEBUG_FS
        select IOSF_MBI
        ---help---
index d99b919..ec4a9de 100644 (file)
@@ -72,12 +72,13 @@ UBSAN_SANITIZE := n
 $(obj)/bzImage: asflags-y  := $(SVGA_MODE)
 
 quiet_cmd_image = BUILD   $@
+silent_redirect_image = >/dev/null
 cmd_image = $(obj)/tools/build $(obj)/setup.bin $(obj)/vmlinux.bin \
-                              $(obj)/zoffset.h $@
+                              $(obj)/zoffset.h $@ $($(quiet)redirect_image)
 
 $(obj)/bzImage: $(obj)/setup.bin $(obj)/vmlinux.bin $(obj)/tools/build FORCE
        $(call if_changed,image)
-       @echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
+       @$(kecho) 'Kernel: $@ is ready' ' (#'`cat .version`')'
 
 OBJCOPYFLAGS_vmlinux.bin := -O binary -R .note -R .comment -S
 $(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
index 4264a3d..7c06488 100644 (file)
@@ -164,7 +164,6 @@ static struct shash_alg alg = {
        .init           = poly1305_simd_init,
        .update         = poly1305_simd_update,
        .final          = crypto_poly1305_final,
-       .setkey         = crypto_poly1305_setkey,
        .descsize       = sizeof(struct poly1305_simd_desc_ctx),
        .base           = {
                .cra_name               = "poly1305",
index 1c3b7ce..e7273a6 100644 (file)
 #define RAB1bl %bl
 #define RAB2bl %cl
 
+#define CD0 0x0(%rsp)
+#define CD1 0x8(%rsp)
+#define CD2 0x10(%rsp)
+
+# used only before/after all rounds
 #define RCD0 %r8
 #define RCD1 %r9
 #define RCD2 %r10
 
-#define RCD0d %r8d
-#define RCD1d %r9d
-#define RCD2d %r10d
-
-#define RX0 %rbp
-#define RX1 %r11
-#define RX2 %r12
+# used only during rounds
+#define RX0 %r8
+#define RX1 %r9
+#define RX2 %r10
 
-#define RX0d %ebp
-#define RX1d %r11d
-#define RX2d %r12d
+#define RX0d %r8d
+#define RX1d %r9d
+#define RX2d %r10d
 
-#define RY0 %r13
-#define RY1 %r14
-#define RY2 %r15
+#define RY0 %r11
+#define RY1 %r12
+#define RY2 %r13
 
-#define RY0d %r13d
-#define RY1d %r14d
-#define RY2d %r15d
+#define RY0d %r11d
+#define RY1d %r12d
+#define RY2d %r13d
 
 #define RT0 %rdx
 #define RT1 %rsi
@@ -85,6 +87,8 @@
 #define RT0d %edx
 #define RT1d %esi
 
+#define RT1bl %sil
+
 #define do16bit_ror(rot, op1, op2, T0, T1, tmp1, tmp2, ab, dst) \
        movzbl ab ## bl,                tmp2 ## d; \
        movzbl ab ## bh,                tmp1 ## d; \
        op1##l T0(CTX, tmp2, 4),        dst ## d; \
        op2##l T1(CTX, tmp1, 4),        dst ## d;
 
+#define swap_ab_with_cd(ab, cd, tmp)   \
+       movq cd, tmp;                   \
+       movq ab, cd;                    \
+       movq tmp, ab;
+
 /*
  * Combined G1 & G2 function. Reordered with help of rotates to have moves
  * at begining.
        /* G1,2 && G2,2 */ \
        do16bit_ror(32, xor, xor, Tx2, Tx3, RT0, RT1, ab ## 0, x ## 0); \
        do16bit_ror(16, xor, xor, Ty3, Ty0, RT0, RT1, ab ## 0, y ## 0); \
-       xchgq cd ## 0, ab ## 0; \
+       swap_ab_with_cd(ab ## 0, cd ## 0, RT0); \
        \
        do16bit_ror(32, xor, xor, Tx2, Tx3, RT0, RT1, ab ## 1, x ## 1); \
        do16bit_ror(16, xor, xor, Ty3, Ty0, RT0, RT1, ab ## 1, y ## 1); \
-       xchgq cd ## 1, ab ## 1; \
+       swap_ab_with_cd(ab ## 1, cd ## 1, RT0); \
        \
        do16bit_ror(32, xor, xor, Tx2, Tx3, RT0, RT1, ab ## 2, x ## 2); \
        do16bit_ror(16, xor, xor, Ty3, Ty0, RT0, RT1, ab ## 2, y ## 2); \
-       xchgq cd ## 2, ab ## 2;
+       swap_ab_with_cd(ab ## 2, cd ## 2, RT0);
 
 #define enc_round_end(ab, x, y, n) \
        addl y ## d,                    x ## d; \
        decrypt_round3(ba, dc, (n*2)+1); \
        decrypt_round3(ba, dc, (n*2));
 
+#define push_cd()      \
+       pushq RCD2;     \
+       pushq RCD1;     \
+       pushq RCD0;
+
+#define pop_cd()       \
+       popq RCD0;      \
+       popq RCD1;      \
+       popq RCD2;
+
 #define inpack3(in, n, xy, m) \
        movq 4*(n)(in),                 xy ## 0; \
        xorq w+4*m(CTX),                xy ## 0; \
@@ -223,11 +242,8 @@ ENTRY(__twofish_enc_blk_3way)
         *      %rdx: src, RIO
         *      %rcx: bool, if true: xor output
         */
-       pushq %r15;
-       pushq %r14;
        pushq %r13;
        pushq %r12;
-       pushq %rbp;
        pushq %rbx;
 
        pushq %rcx; /* bool xor */
@@ -235,40 +251,36 @@ ENTRY(__twofish_enc_blk_3way)
 
        inpack_enc3();
 
-       encrypt_cycle3(RAB, RCD, 0);
-       encrypt_cycle3(RAB, RCD, 1);
-       encrypt_cycle3(RAB, RCD, 2);
-       encrypt_cycle3(RAB, RCD, 3);
-       encrypt_cycle3(RAB, RCD, 4);
-       encrypt_cycle3(RAB, RCD, 5);
-       encrypt_cycle3(RAB, RCD, 6);
-       encrypt_cycle3(RAB, RCD, 7);
+       push_cd();
+       encrypt_cycle3(RAB, CD, 0);
+       encrypt_cycle3(RAB, CD, 1);
+       encrypt_cycle3(RAB, CD, 2);
+       encrypt_cycle3(RAB, CD, 3);
+       encrypt_cycle3(RAB, CD, 4);
+       encrypt_cycle3(RAB, CD, 5);
+       encrypt_cycle3(RAB, CD, 6);
+       encrypt_cycle3(RAB, CD, 7);
+       pop_cd();
 
        popq RIO; /* dst */
-       popq %rbp; /* bool xor */
+       popq RT1; /* bool xor */
 
-       testb %bpl, %bpl;
+       testb RT1bl, RT1bl;
        jnz .L__enc_xor3;
 
        outunpack_enc3(mov);
 
        popq %rbx;
-       popq %rbp;
        popq %r12;
        popq %r13;
-       popq %r14;
-       popq %r15;
        ret;
 
 .L__enc_xor3:
        outunpack_enc3(xor);
 
        popq %rbx;
-       popq %rbp;
        popq %r12;
        popq %r13;
-       popq %r14;
-       popq %r15;
        ret;
 ENDPROC(__twofish_enc_blk_3way)
 
@@ -278,35 +290,31 @@ ENTRY(twofish_dec_blk_3way)
         *      %rsi: dst
         *      %rdx: src, RIO
         */
-       pushq %r15;
-       pushq %r14;
        pushq %r13;
        pushq %r12;
-       pushq %rbp;
        pushq %rbx;
 
        pushq %rsi; /* dst */
 
        inpack_dec3();
 
-       decrypt_cycle3(RAB, RCD, 7);
-       decrypt_cycle3(RAB, RCD, 6);
-       decrypt_cycle3(RAB, RCD, 5);
-       decrypt_cycle3(RAB, RCD, 4);
-       decrypt_cycle3(RAB, RCD, 3);
-       decrypt_cycle3(RAB, RCD, 2);
-       decrypt_cycle3(RAB, RCD, 1);
-       decrypt_cycle3(RAB, RCD, 0);
+       push_cd();
+       decrypt_cycle3(RAB, CD, 7);
+       decrypt_cycle3(RAB, CD, 6);
+       decrypt_cycle3(RAB, CD, 5);
+       decrypt_cycle3(RAB, CD, 4);
+       decrypt_cycle3(RAB, CD, 3);
+       decrypt_cycle3(RAB, CD, 2);
+       decrypt_cycle3(RAB, CD, 1);
+       decrypt_cycle3(RAB, CD, 0);
+       pop_cd();
 
        popq RIO; /* dst */
 
        outunpack_dec3();
 
        popq %rbx;
-       popq %rbp;
        popq %r12;
        popq %r13;
-       popq %r14;
-       popq %r15;
        ret;
 ENDPROC(twofish_dec_blk_3way)
index 1a4477c..b5eb1cc 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/export.h>
 #include <linux/context_tracking.h>
 #include <linux/user-return-notifier.h>
+#include <linux/nospec.h>
 #include <linux/uprobes.h>
 
 #include <asm/desc.h>
@@ -381,6 +382,7 @@ __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs)
        }
 
        if (likely(nr < IA32_NR_syscalls)) {
+               nr = array_index_nospec(nr, IA32_NR_syscalls);
                /*
                 * It's possible that a 32-bit syscall implementation
                 * takes a 64-bit parameter but nonetheless assumes that
index b15aa40..5a25ada 100644 (file)
@@ -37,5 +37,4 @@ INDIRECT_THUNK(dx)
 INDIRECT_THUNK(si)
 INDIRECT_THUNK(di)
 INDIRECT_THUNK(bp)
-INDIRECT_THUNK(sp)
 #endif /* CONFIG_RETPOLINE */
index 817f672..858f8c3 100644 (file)
 # define __ASM_FORM_COMMA(x) " " #x ","
 #endif
 
-#ifdef CONFIG_X86_32
+#ifndef __x86_64__
+/* 32 bit */
 # define __ASM_SEL(a,b) __ASM_FORM(a)
 # define __ASM_SEL_RAW(a,b) __ASM_FORM_RAW(a)
 #else
+/* 64 bit */
 # define __ASM_SEL(a,b) __ASM_FORM(b)
 # define __ASM_SEL_RAW(a,b) __ASM_FORM_RAW(b)
 #endif
index 0681d25..814ef83 100644 (file)
 #define wmb()  asm volatile("sfence" ::: "memory")
 #endif
 
+/**
+ * array_index_mask_nospec() - generate a mask that is ~0UL when the
+ *     bounds check succeeds and 0 otherwise
+ * @index: array element index
+ * @size: number of elements in array
+ *
+ * Returns:
+ *     0 - (index < size)
+ */
+static inline unsigned long array_index_mask_nospec(unsigned long index,
+               unsigned long size)
+{
+       unsigned long mask;
+
+       asm ("cmp %1,%2; sbb %0,%0;"
+                       :"=r" (mask)
+                       :"r"(size),"r" (index)
+                       :"cc");
+       return mask;
+}
+
+/* Override the default implementation from linux/nospec.h. */
+#define array_index_mask_nospec array_index_mask_nospec
+
+/* Prevent speculative execution past this barrier. */
+#define barrier_nospec() alternative_2("", "mfence", X86_FEATURE_MFENCE_RDTSC, \
+                                          "lfence", X86_FEATURE_LFENCE_RDTSC)
+
 #ifdef CONFIG_X86_PPRO_FENCE
 #define dma_rmb()      rmb()
 #else
index adfc847..fb163f0 100644 (file)
@@ -59,7 +59,6 @@ static inline u16 find_equiv_id(struct equiv_cpu_entry *equiv_cpu_table,
 
 extern int __apply_microcode_amd(struct microcode_amd *mc_amd);
 extern int apply_microcode_amd(int cpu);
-extern enum ucode_state load_microcode_amd(int cpu, u8 family, const u8 *data, size_t size);
 
 #define PATCH_MAX_SIZE PAGE_SIZE
 extern u8 amd_ucode_patch[PATCH_MAX_SIZE];
index 77d8b28..5a10ac8 100644 (file)
@@ -147,8 +147,7 @@ static __always_inline unsigned long long rdtsc_ordered(void)
         * that some other imaginary CPU is updating continuously with a
         * time stamp.
         */
-       alternative_2("", "mfence", X86_FEATURE_MFENCE_RDTSC,
-                         "lfence", X86_FEATURE_LFENCE_RDTSC);
+       barrier_nospec();
        return rdtsc();
 }
 
index 492370b..66094a0 100644 (file)
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 
-#ifndef __NOSPEC_BRANCH_H__
-#define __NOSPEC_BRANCH_H__
+#ifndef _ASM_X86_NOSPEC_BRANCH_H_
+#define _ASM_X86_NOSPEC_BRANCH_H_
 
 #include <asm/alternative.h>
 #include <asm/alternative-asm.h>
@@ -178,7 +178,7 @@ extern char __indirect_thunk_end[];
  * On VMEXIT we must ensure that no RSB predictions learned in the guest
  * can be followed in the host, by overwriting the RSB completely. Both
  * retpoline and IBRS mitigations for Spectre v2 need this; only on future
- * CPUs with IBRS_ATT *might* it be avoided.
+ * CPUs with IBRS_ALL *might* it be avoided.
  */
 static inline void vmexit_fill_RSB(void)
 {
@@ -195,4 +195,4 @@ static inline void vmexit_fill_RSB(void)
 }
 
 #endif /* __ASSEMBLY__ */
-#endif /* __NOSPEC_BRANCH_H__ */
+#endif /* _ASM_X86_NOSPEC_BRANCH_H_ */
index 86bccb4..9e77cea 100644 (file)
@@ -113,7 +113,7 @@ struct cpuinfo_x86 {
        char                    x86_vendor_id[16];
        char                    x86_model_id[64];
        /* in KB - valid for CPUS which support this call: */
-       int                     x86_cache_size;
+       unsigned int            x86_cache_size;
        int                     x86_cache_alignment;    /* In bytes */
        /* Cache QoS architectural values: */
        int                     x86_cache_max_rmid;     /* max index */
index 14c63c7..6b6e16d 100644 (file)
@@ -400,10 +400,11 @@ enum vmcs_field {
 #define IDENTITY_PAGETABLE_PRIVATE_MEMSLOT     (KVM_USER_MEM_SLOTS + 2)
 
 #define VMX_NR_VPIDS                           (1 << 16)
+#define VMX_VPID_EXTENT_INDIVIDUAL_ADDR                0
 #define VMX_VPID_EXTENT_SINGLE_CONTEXT         1
 #define VMX_VPID_EXTENT_ALL_CONTEXT            2
+#define VMX_VPID_EXTENT_SINGLE_NON_GLOBAL      3
 
-#define VMX_EPT_EXTENT_INDIVIDUAL_ADDR         0
 #define VMX_EPT_EXTENT_CONTEXT                 1
 #define VMX_EPT_EXTENT_GLOBAL                  2
 #define VMX_EPT_EXTENT_SHIFT                   24
@@ -420,8 +421,10 @@ enum vmcs_field {
 #define VMX_EPT_EXTENT_GLOBAL_BIT              (1ull << 26)
 
 #define VMX_VPID_INVVPID_BIT                    (1ull << 0) /* (32 - 32) */
+#define VMX_VPID_EXTENT_INDIVIDUAL_ADDR_BIT     (1ull << 8) /* (40 - 32) */
 #define VMX_VPID_EXTENT_SINGLE_CONTEXT_BIT      (1ull << 9) /* (41 - 32) */
 #define VMX_VPID_EXTENT_GLOBAL_CONTEXT_BIT      (1ull << 10) /* (42 - 32) */
+#define VMX_VPID_EXTENT_SINGLE_NON_GLOBAL_BIT   (1ull << 11) /* (43 - 32) */
 
 #define VMX_EPT_DEFAULT_GAW                    3
 #define VMX_EPT_MAX_GAW                                0x4
index 9ee8506..62210da 100644 (file)
@@ -13,7 +13,6 @@ extern void map_vsyscall(void);
  */
 extern bool emulate_vsyscall(struct pt_regs *regs, unsigned long address);
 extern bool vsyscall_enabled(void);
-extern unsigned long vsyscall_pgprot;
 #else
 static inline void map_vsyscall(void) {}
 static inline bool emulate_vsyscall(struct pt_regs *regs, unsigned long address)
@@ -22,5 +21,6 @@ static inline bool emulate_vsyscall(struct pt_regs *regs, unsigned long address)
 }
 static inline bool vsyscall_enabled(void) { return false; }
 #endif
+extern unsigned long vsyscall_pgprot;
 
 #endif /* _ASM_X86_VSYSCALL_H */
index d6f375f..89829c3 100644 (file)
@@ -45,17 +45,6 @@ static int __init setup_noreplace_smp(char *str)
 }
 __setup("noreplace-smp", setup_noreplace_smp);
 
-#ifdef CONFIG_PARAVIRT
-static int __initdata_or_module noreplace_paravirt = 0;
-
-static int __init setup_noreplace_paravirt(char *str)
-{
-       noreplace_paravirt = 1;
-       return 1;
-}
-__setup("noreplace-paravirt", setup_noreplace_paravirt);
-#endif
-
 #define DPRINTK(fmt, args...)                                          \
 do {                                                                   \
        if (debug_alternative)                                          \
@@ -587,9 +576,6 @@ void __init_or_module apply_paravirt(struct paravirt_patch_site *start,
        struct paravirt_patch_site *p;
        char insnbuf[MAX_PATCH_LEN];
 
-       if (noreplace_paravirt)
-               return;
-
        for (p = start; p < end; p++) {
                unsigned int used;
 
index 8cacf62..ecaf7c9 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/init.h>
 #include <linux/utsname.h>
 #include <linux/cpu.h>
+#include <linux/module.h>
 
 #include <asm/nospec-branch.h>
 #include <asm/cmdline.h>
@@ -89,20 +90,42 @@ static const char *spectre_v2_strings[] = {
 };
 
 #undef pr_fmt
-#define pr_fmt(fmt)     "Spectre V2 mitigation: " fmt
+#define pr_fmt(fmt)     "Spectre V2 : " fmt
 
 static enum spectre_v2_mitigation spectre_v2_enabled = SPECTRE_V2_NONE;
 
+
+#ifdef RETPOLINE
+static bool spectre_v2_bad_module;
+
+bool retpoline_module_ok(bool has_retpoline)
+{
+       if (spectre_v2_enabled == SPECTRE_V2_NONE || has_retpoline)
+               return true;
+
+       pr_err("System may be vulnerable to spectre v2\n");
+       spectre_v2_bad_module = true;
+       return false;
+}
+
+static inline const char *spectre_v2_module_string(void)
+{
+       return spectre_v2_bad_module ? " - vulnerable module loaded" : "";
+}
+#else
+static inline const char *spectre_v2_module_string(void) { return ""; }
+#endif
+
 static void __init spec2_print_if_insecure(const char *reason)
 {
        if (boot_cpu_has_bug(X86_BUG_SPECTRE_V2))
-               pr_info("%s\n", reason);
+               pr_info("%s selected on command line.\n", reason);
 }
 
 static void __init spec2_print_if_secure(const char *reason)
 {
        if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2))
-               pr_info("%s\n", reason);
+               pr_info("%s selected on command line.\n", reason);
 }
 
 static inline bool retp_compiler(void)
@@ -117,42 +140,68 @@ static inline bool match_option(const char *arg, int arglen, const char *opt)
        return len == arglen && !strncmp(arg, opt, len);
 }
 
+static const struct {
+       const char *option;
+       enum spectre_v2_mitigation_cmd cmd;
+       bool secure;
+} mitigation_options[] = {
+       { "off",               SPECTRE_V2_CMD_NONE,              false },
+       { "on",                SPECTRE_V2_CMD_FORCE,             true },
+       { "retpoline",         SPECTRE_V2_CMD_RETPOLINE,         false },
+       { "retpoline,amd",     SPECTRE_V2_CMD_RETPOLINE_AMD,     false },
+       { "retpoline,generic", SPECTRE_V2_CMD_RETPOLINE_GENERIC, false },
+       { "auto",              SPECTRE_V2_CMD_AUTO,              false },
+};
+
 static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void)
 {
        char arg[20];
-       int ret;
-
-       ret = cmdline_find_option(boot_command_line, "spectre_v2", arg,
-                                 sizeof(arg));
-       if (ret > 0)  {
-               if (match_option(arg, ret, "off")) {
-                       goto disable;
-               } else if (match_option(arg, ret, "on")) {
-                       spec2_print_if_secure("force enabled on command line.");
-                       return SPECTRE_V2_CMD_FORCE;
-               } else if (match_option(arg, ret, "retpoline")) {
-                       spec2_print_if_insecure("retpoline selected on command line.");
-                       return SPECTRE_V2_CMD_RETPOLINE;
-               } else if (match_option(arg, ret, "retpoline,amd")) {
-                       if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) {
-                               pr_err("retpoline,amd selected but CPU is not AMD. Switching to AUTO select\n");
-                               return SPECTRE_V2_CMD_AUTO;
-                       }
-                       spec2_print_if_insecure("AMD retpoline selected on command line.");
-                       return SPECTRE_V2_CMD_RETPOLINE_AMD;
-               } else if (match_option(arg, ret, "retpoline,generic")) {
-                       spec2_print_if_insecure("generic retpoline selected on command line.");
-                       return SPECTRE_V2_CMD_RETPOLINE_GENERIC;
-               } else if (match_option(arg, ret, "auto")) {
+       int ret, i;
+       enum spectre_v2_mitigation_cmd cmd = SPECTRE_V2_CMD_AUTO;
+
+       if (cmdline_find_option_bool(boot_command_line, "nospectre_v2"))
+               return SPECTRE_V2_CMD_NONE;
+       else {
+               ret = cmdline_find_option(boot_command_line, "spectre_v2", arg,
+                                         sizeof(arg));
+               if (ret < 0)
+                       return SPECTRE_V2_CMD_AUTO;
+
+               for (i = 0; i < ARRAY_SIZE(mitigation_options); i++) {
+                       if (!match_option(arg, ret, mitigation_options[i].option))
+                               continue;
+                       cmd = mitigation_options[i].cmd;
+                       break;
+               }
+
+               if (i >= ARRAY_SIZE(mitigation_options)) {
+                       pr_err("unknown option (%s). Switching to AUTO select\n",
+                              mitigation_options[i].option);
                        return SPECTRE_V2_CMD_AUTO;
                }
        }
 
-       if (!cmdline_find_option_bool(boot_command_line, "nospectre_v2"))
+       if ((cmd == SPECTRE_V2_CMD_RETPOLINE ||
+            cmd == SPECTRE_V2_CMD_RETPOLINE_AMD ||
+            cmd == SPECTRE_V2_CMD_RETPOLINE_GENERIC) &&
+           !IS_ENABLED(CONFIG_RETPOLINE)) {
+               pr_err("%s selected but not compiled in. Switching to AUTO select\n",
+                      mitigation_options[i].option);
                return SPECTRE_V2_CMD_AUTO;
-disable:
-       spec2_print_if_insecure("disabled on command line.");
-       return SPECTRE_V2_CMD_NONE;
+       }
+
+       if (cmd == SPECTRE_V2_CMD_RETPOLINE_AMD &&
+           boot_cpu_data.x86_vendor != X86_VENDOR_AMD) {
+               pr_err("retpoline,amd selected but CPU is not AMD. Switching to AUTO select\n");
+               return SPECTRE_V2_CMD_AUTO;
+       }
+
+       if (mitigation_options[i].secure)
+               spec2_print_if_secure(mitigation_options[i].option);
+       else
+               spec2_print_if_insecure(mitigation_options[i].option);
+
+       return cmd;
 }
 
 /* Check for Skylake-like CPUs (for RSB handling) */
@@ -190,10 +239,10 @@ static void __init spectre_v2_select_mitigation(void)
                return;
 
        case SPECTRE_V2_CMD_FORCE:
-               /* FALLTRHU */
        case SPECTRE_V2_CMD_AUTO:
-               goto retpoline_auto;
-
+               if (IS_ENABLED(CONFIG_RETPOLINE))
+                       goto retpoline_auto;
+               break;
        case SPECTRE_V2_CMD_RETPOLINE_AMD:
                if (IS_ENABLED(CONFIG_RETPOLINE))
                        goto retpoline_amd;
@@ -268,7 +317,7 @@ ssize_t cpu_show_spectre_v1(struct device *dev,
 {
        if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V1))
                return sprintf(buf, "Not affected\n");
-       return sprintf(buf, "Vulnerable\n");
+       return sprintf(buf, "Mitigation: __user pointer sanitization\n");
 }
 
 ssize_t cpu_show_spectre_v2(struct device *dev,
@@ -277,6 +326,7 @@ ssize_t cpu_show_spectre_v2(struct device *dev,
        if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2))
                return sprintf(buf, "Not affected\n");
 
-       return sprintf(buf, "%s\n", spectre_v2_strings[spectre_v2_enabled]);
+       return sprintf(buf, "%s%s\n", spectre_v2_strings[spectre_v2_enabled],
+                      spectre_v2_module_string());
 }
 #endif
index f7f2ad3..8eabbaf 100644 (file)
@@ -955,7 +955,7 @@ static void identify_cpu(struct cpuinfo_x86 *c)
        int i;
 
        c->loops_per_jiffy = loops_per_jiffy;
-       c->x86_cache_size = -1;
+       c->x86_cache_size = 0;
        c->x86_vendor = X86_VENDOR_UNKNOWN;
        c->x86_model = c->x86_mask = 0; /* So far unknown... */
        c->x86_vendor_id[0] = '\0'; /* Unset */
index 4cfba43..101bfae 100644 (file)
@@ -152,7 +152,6 @@ static void raise_mce(struct mce *m)
        if (context == MCJ_CTX_RANDOM)
                return;
 
-#ifdef CONFIG_X86_LOCAL_APIC
        if (m->inject_flags & (MCJ_IRQ_BROADCAST | MCJ_NMI_BROADCAST)) {
                unsigned long start;
                int cpu;
@@ -193,9 +192,7 @@ static void raise_mce(struct mce *m)
                raise_local();
                put_cpu();
                put_online_cpus();
-       } else
-#endif
-       {
+       } else {
                preempt_disable();
                raise_local();
                preempt_enable();
index 2a0f44d..6da6f9c 100644 (file)
@@ -131,6 +131,9 @@ static size_t compute_container_size(u8 *data, u32 total_size)
        return size;
 }
 
+static enum ucode_state
+load_microcode_amd(bool save, u8 family, const u8 *data, size_t size);
+
 /*
  * Early load occurs before we can vmalloc(). So we look for the microcode
  * patch container file in initrd, traverse equivalent cpu table, look for a
@@ -438,7 +441,7 @@ int __init save_microcode_in_initrd_amd(void)
        eax   = cpuid_eax(0x00000001);
        eax   = ((eax >> 8) & 0xf) + ((eax >> 20) & 0xff);
 
-       ret = load_microcode_amd(smp_processor_id(), eax, container, container_size);
+       ret = load_microcode_amd(true, eax, container, container_size);
        if (ret != UCODE_OK)
                retval = -EINVAL;
 
@@ -854,7 +857,8 @@ static enum ucode_state __load_microcode_amd(u8 family, const u8 *data,
        return UCODE_OK;
 }
 
-enum ucode_state load_microcode_amd(int cpu, u8 family, const u8 *data, size_t size)
+static enum ucode_state
+load_microcode_amd(bool save, u8 family, const u8 *data, size_t size)
 {
        enum ucode_state ret;
 
@@ -868,8 +872,8 @@ enum ucode_state load_microcode_amd(int cpu, u8 family, const u8 *data, size_t s
 
 #ifdef CONFIG_X86_32
        /* save BSP's matching patch for early load */
-       if (cpu_data(cpu).cpu_index == boot_cpu_data.cpu_index) {
-               struct ucode_patch *p = find_patch(cpu);
+       if (save) {
+               struct ucode_patch *p = find_patch(0);
                if (p) {
                        memset(amd_ucode_patch, 0, PATCH_MAX_SIZE);
                        memcpy(amd_ucode_patch, p->data, min_t(u32, ksize(p->data),
@@ -901,11 +905,12 @@ static enum ucode_state request_microcode_amd(int cpu, struct device *device,
 {
        char fw_name[36] = "amd-ucode/microcode_amd.bin";
        struct cpuinfo_x86 *c = &cpu_data(cpu);
+       bool bsp = c->cpu_index == boot_cpu_data.cpu_index;
        enum ucode_state ret = UCODE_NFOUND;
        const struct firmware *fw;
 
        /* reload ucode container only on the boot cpu */
-       if (!refresh_fw || c->cpu_index != boot_cpu_data.cpu_index)
+       if (!refresh_fw || !bsp)
                return UCODE_OK;
 
        if (c->x86 >= 0x15)
@@ -922,7 +927,7 @@ static enum ucode_state request_microcode_amd(int cpu, struct device *device,
                goto fw_release;
        }
 
-       ret = load_microcode_amd(cpu, c->x86, fw->data, fw->size);
+       ret = load_microcode_amd(bsp, c->x86, fw->data, fw->size);
 
  fw_release:
        release_firmware(fw);
index b3e94ef..ce5f8a2 100644 (file)
@@ -44,7 +44,7 @@
 
 static struct microcode_ops    *microcode_ops;
 
-static bool dis_ucode_ldr;
+static bool dis_ucode_ldr = true;
 
 static int __init disable_loader(char *str)
 {
@@ -81,6 +81,7 @@ struct cpu_info_ctx {
 
 static bool __init check_loader_disabled_bsp(void)
 {
+       u32 a, b, c, d;
 #ifdef CONFIG_X86_32
        const char *cmdline = (const char *)__pa_nodebug(boot_command_line);
        const char *opt     = "dis_ucode_ldr";
@@ -93,8 +94,20 @@ static bool __init check_loader_disabled_bsp(void)
        bool *res = &dis_ucode_ldr;
 #endif
 
-       if (cmdline_find_option_bool(cmdline, option))
-               *res = true;
+       a = 1;
+       c = 0;
+       native_cpuid(&a, &b, &c, &d);
+
+       /*
+        * CPUID(1).ECX[31]: reserved for hypervisor use. This is still not
+        * completely accurate as xen pv guests don't see that CPUID bit set but
+        * that's good enough as they don't land on the BSP path anyway.
+        */
+       if (c & BIT(31))
+               return *res;
+
+       if (cmdline_find_option_bool(cmdline, option) <= 0)
+               *res = false;
 
        return *res;
 }
@@ -122,9 +135,7 @@ void __init load_ucode_bsp(void)
 {
        int vendor;
        unsigned int family;
-
-       if (check_loader_disabled_bsp())
-               return;
+       bool intel = true;
 
        if (!have_cpuid_p())
                return;
@@ -134,16 +145,27 @@ void __init load_ucode_bsp(void)
 
        switch (vendor) {
        case X86_VENDOR_INTEL:
-               if (family >= 6)
-                       load_ucode_intel_bsp();
+               if (family < 6)
+                       return;
                break;
+
        case X86_VENDOR_AMD:
-               if (family >= 0x10)
-                       load_ucode_amd_bsp(family);
+               if (family < 0x10)
+                       return;
+               intel = false;
                break;
+
        default:
-               break;
+               return;
        }
+
+       if (check_loader_disabled_bsp())
+               return;
+
+       if (intel)
+               load_ucode_intel_bsp();
+       else
+               load_ucode_amd_bsp(family);
 }
 
 static bool check_loader_disabled_ap(void)
@@ -162,9 +184,6 @@ void load_ucode_ap(void)
        if (check_loader_disabled_ap())
                return;
 
-       if (!have_cpuid_p())
-               return;
-
        vendor = x86_vendor();
        family = x86_family();
 
index 2c76a18..2f38a99 100644 (file)
@@ -1075,7 +1075,7 @@ static struct microcode_ops microcode_intel_ops = {
 
 static int __init calc_llc_size_per_core(struct cpuinfo_x86 *c)
 {
-       u64 llc_size = c->x86_cache_size * 1024;
+       u64 llc_size = c->x86_cache_size * 1024ULL;
 
        do_div(llc_size, c->x86_max_cores);
 
index 5b2f230..b52a8d0 100644 (file)
@@ -188,8 +188,8 @@ static void release_pmc_hardware(void) {}
 
 static bool check_hw_exists(void)
 {
-       u64 val, val_fail, val_new= ~0;
-       int i, reg, reg_fail, ret = 0;
+       u64 val, val_fail = -1, val_new= ~0;
+       int i, reg, reg_fail = -1, ret = 0;
        int bios_fail = 0;
        int reg_safe = -1;
 
index 18ca99f..935225c 100644 (file)
@@ -87,8 +87,8 @@ static int show_cpuinfo(struct seq_file *m, void *v)
        }
 
        /* Cache size */
-       if (c->x86_cache_size >= 0)
-               seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size);
+       if (c->x86_cache_size)
+               seq_printf(m, "cache size\t: %u KB\n", c->x86_cache_size);
 
        show_cpuinfo_core(m, c, cpu);
        show_cpuinfo_misc(m, c);
index 8f1a3f4..70284d3 100644 (file)
@@ -669,14 +669,17 @@ __PAGE_ALIGNED_BSS
 initial_pg_pmd:
        .fill 1024*KPMDS,4,0
 #else
-ENTRY(initial_page_table)
+.globl initial_page_table
+initial_page_table:
        .fill 1024,4,0
 #endif
 initial_pg_fixmap:
        .fill 1024,4,0
-ENTRY(empty_zero_page)
+.globl empty_zero_page
+empty_zero_page:
        .fill 4096,1,0
-ENTRY(swapper_pg_dir)
+.globl swapper_pg_dir
+swapper_pg_dir:
        .fill 1024,4,0
 
 /*
index c1b21d6..2754dad 100644 (file)
@@ -81,10 +81,9 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 /*
  * Free current thread data structures etc..
  */
-void exit_thread(void)
+void exit_thread(struct task_struct *tsk)
 {
-       struct task_struct *me = current;
-       struct thread_struct *t = &me->thread;
+       struct thread_struct *t = &tsk->thread;
        unsigned long *bp = t->io_bitmap_ptr;
        struct fpu *fpu = &t->fpu;
 
index 639a6e3..53b7f53 100644 (file)
@@ -22,7 +22,8 @@ config KVM
        depends on HAVE_KVM
        depends on HIGH_RES_TIMERS
        # for TASKSTATS/TASK_DELAY_ACCT:
-       depends on NET
+       depends on NET && MULTIUSER
+       depends on X86_LOCAL_APIC
        select PREEMPT_NOTIFIERS
        select MMU_NOTIFIER
        select ANON_INODES
index e4eb1d2..8864fec 100644 (file)
@@ -26,6 +26,7 @@
 #include <asm/kvm_emulate.h>
 #include <linux/stringify.h>
 #include <asm/debugreg.h>
+#include <asm/nospec-branch.h>
 
 #include "x86.h"
 #include "tss.h"
@@ -1000,8 +1001,8 @@ static u8 test_cc(unsigned int condition, unsigned long flags)
        void (*fop)(void) = (void *)em_setcc + 4 * (condition & 0xf);
 
        flags = (flags & EFLAGS_MASK) | X86_EFLAGS_IF;
-       asm("push %[flags]; popf; call *%[fastop]"
-           : "=a"(rc) : [fastop]"r"(fop), [flags]"r"(flags));
+       asm("push %[flags]; popf; " CALL_NOSPEC
+           : "=a"(rc) : [thunk_target]"r"(fop), [flags]"r"(flags));
        return rc;
 }
 
@@ -5297,9 +5298,9 @@ static int fastop(struct x86_emulate_ctxt *ctxt, void (*fop)(struct fastop *))
        ulong flags = (ctxt->eflags & EFLAGS_MASK) | X86_EFLAGS_IF;
        if (!(ctxt->d & ByteOp))
                fop += __ffs(ctxt->dst.bytes) * FASTOP_SIZE;
-       asm("push %[flags]; popf; call *%[fastop]; pushf; pop %[flags]\n"
+       asm("push %[flags]; popf; " CALL_NOSPEC "; pushf; pop %[flags]\n"
            : "+a"(ctxt->dst.val), "+d"(ctxt->src.val), [flags]"+D"(flags),
-             [fastop]"+S"(fop)
+             [thunk_target]"+S"(fop)
            : "c"(ctxt->src2.val));
        ctxt->eflags = (ctxt->eflags & ~EFLAGS_MASK) | (flags & EFLAGS_MASK);
        if (!fop) /* exception is returned in fop variable */
index 1049c3c..2b71f2c 100644 (file)
@@ -4503,7 +4503,7 @@ void kvm_mmu_setup(struct kvm_vcpu *vcpu)
 typedef bool (*slot_level_handler) (struct kvm *kvm, unsigned long *rmap);
 
 /* The caller should hold mmu-lock before calling this function. */
-static bool
+static __always_inline bool
 slot_handle_level_range(struct kvm *kvm, struct kvm_memory_slot *memslot,
                        slot_level_handler fn, int start_level, int end_level,
                        gfn_t start_gfn, gfn_t end_gfn, bool lock_flush_tlb)
@@ -4533,7 +4533,7 @@ slot_handle_level_range(struct kvm *kvm, struct kvm_memory_slot *memslot,
        return flush;
 }
 
-static bool
+static __always_inline bool
 slot_handle_level(struct kvm *kvm, struct kvm_memory_slot *memslot,
                  slot_level_handler fn, int start_level, int end_level,
                  bool lock_flush_tlb)
@@ -4544,7 +4544,7 @@ slot_handle_level(struct kvm *kvm, struct kvm_memory_slot *memslot,
                        lock_flush_tlb);
 }
 
-static bool
+static __always_inline bool
 slot_handle_all_level(struct kvm *kvm, struct kvm_memory_slot *memslot,
                      slot_level_handler fn, bool lock_flush_tlb)
 {
@@ -4552,7 +4552,7 @@ slot_handle_all_level(struct kvm *kvm, struct kvm_memory_slot *memslot,
                                 PT_MAX_HUGEPAGE_LEVEL, lock_flush_tlb);
 }
 
-static bool
+static __always_inline bool
 slot_handle_large_level(struct kvm *kvm, struct kvm_memory_slot *memslot,
                        slot_level_handler fn, bool lock_flush_tlb)
 {
@@ -4560,7 +4560,7 @@ slot_handle_large_level(struct kvm *kvm, struct kvm_memory_slot *memslot,
                                 PT_MAX_HUGEPAGE_LEVEL, lock_flush_tlb);
 }
 
-static bool
+static __always_inline bool
 slot_handle_leaf(struct kvm *kvm, struct kvm_memory_slot *memslot,
                 slot_level_handler fn, bool lock_flush_tlb)
 {
index f8d785a..8495178 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/slab.h>
 #include <linux/tboot.h>
 #include <linux/hrtimer.h>
+#include <linux/nospec.h>
 #include "kvm_cache_regs.h"
 #include "x86.h"
 
@@ -125,6 +126,12 @@ module_param_named(pml, enable_pml, bool, S_IRUGO);
 
 #define VMX_MISC_EMULATED_PREEMPTION_TIMER_RATE 5
 
+#define VMX_VPID_EXTENT_SUPPORTED_MASK         \
+       (VMX_VPID_EXTENT_INDIVIDUAL_ADDR_BIT |  \
+       VMX_VPID_EXTENT_SINGLE_CONTEXT_BIT |    \
+       VMX_VPID_EXTENT_GLOBAL_CONTEXT_BIT |    \
+       VMX_VPID_EXTENT_SINGLE_NON_GLOBAL_BIT)
+
 /*
  * These 2 parameters are used to config the controls for Pause-Loop Exiting:
  * ple_gap:    upper bound on the amount of time between two successive
@@ -827,21 +834,18 @@ static const unsigned short vmcs_field_to_offset_table[] = {
 
 static inline short vmcs_field_to_offset(unsigned long field)
 {
-       BUILD_BUG_ON(ARRAY_SIZE(vmcs_field_to_offset_table) > SHRT_MAX);
+       const size_t size = ARRAY_SIZE(vmcs_field_to_offset_table);
+       unsigned short offset;
 
-       if (field >= ARRAY_SIZE(vmcs_field_to_offset_table))
+       BUILD_BUG_ON(size > SHRT_MAX);
+       if (field >= size)
                return -ENOENT;
 
-       /*
-        * FIXME: Mitigation for CVE-2017-5753.  To be replaced with a
-        * generic mechanism.
-        */
-       asm("lfence");
-
-       if (vmcs_field_to_offset_table[field] == 0)
+       field = array_index_nospec(field, size);
+       offset = vmcs_field_to_offset_table[field];
+       if (offset == 0)
                return -ENOENT;
-
-       return vmcs_field_to_offset_table[field];
+       return offset;
 }
 
 static inline struct vmcs12 *get_vmcs12(struct kvm_vcpu *vcpu)
@@ -2659,8 +2663,7 @@ static void nested_vmx_setup_ctls_msrs(struct vcpu_vmx *vmx)
         */
        if (enable_vpid)
                vmx->nested.nested_vmx_vpid_caps = VMX_VPID_INVVPID_BIT |
-                               VMX_VPID_EXTENT_SINGLE_CONTEXT_BIT |
-                               VMX_VPID_EXTENT_GLOBAL_CONTEXT_BIT;
+                       VMX_VPID_EXTENT_SUPPORTED_MASK;
        else
                vmx->nested.nested_vmx_vpid_caps = 0;
 
@@ -4514,7 +4517,7 @@ static int vmx_cpu_uses_apicv(struct kvm_vcpu *vcpu)
        return enable_apicv && lapic_in_kernel(vcpu);
 }
 
-static int vmx_complete_nested_posted_interrupt(struct kvm_vcpu *vcpu)
+static void vmx_complete_nested_posted_interrupt(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
        int max_irr;
@@ -4525,19 +4528,15 @@ static int vmx_complete_nested_posted_interrupt(struct kvm_vcpu *vcpu)
            vmx->nested.pi_pending) {
                vmx->nested.pi_pending = false;
                if (!pi_test_and_clear_on(vmx->nested.pi_desc))
-                       return 0;
+                       return;
 
                max_irr = find_last_bit(
                        (unsigned long *)vmx->nested.pi_desc->pir, 256);
 
                if (max_irr == 256)
-                       return 0;
+                       return;
 
                vapic_page = kmap(vmx->nested.virtual_apic_page);
-               if (!vapic_page) {
-                       WARN_ON(1);
-                       return -ENOMEM;
-               }
                __kvm_apic_update_irr(vmx->nested.pi_desc->pir, vapic_page);
                kunmap(vmx->nested.virtual_apic_page);
 
@@ -4548,7 +4547,6 @@ static int vmx_complete_nested_posted_interrupt(struct kvm_vcpu *vcpu)
                        vmcs_write16(GUEST_INTR_STATUS, status);
                }
        }
-       return 0;
 }
 
 static inline bool kvm_vcpu_trigger_posted_interrupt(struct kvm_vcpu *vcpu)
@@ -4595,14 +4593,15 @@ static int vmx_deliver_nested_posted_interrupt(struct kvm_vcpu *vcpu,
 
        if (is_guest_mode(vcpu) &&
            vector == vmx->nested.posted_intr_nv) {
-               /* the PIR and ON have been set by L1. */
-               kvm_vcpu_trigger_posted_interrupt(vcpu);
                /*
                 * If a posted intr is not recognized by hardware,
                 * we will accomplish it in the next vmentry.
                 */
                vmx->nested.pi_pending = true;
                kvm_make_request(KVM_REQ_EVENT, vcpu);
+               /* the PIR and ON have been set by L1. */
+               if (!kvm_vcpu_trigger_posted_interrupt(vcpu))
+                       kvm_vcpu_kick(vcpu);
                return 0;
        }
        return -1;
@@ -7367,7 +7366,7 @@ static int handle_invept(struct kvm_vcpu *vcpu)
 
        types = (vmx->nested.nested_vmx_ept_caps >> VMX_EPT_EXTENT_SHIFT) & 6;
 
-       if (!(types & (1UL << type))) {
+       if (type >= 32 || !(types & (1 << type))) {
                nested_vmx_failValid(vcpu,
                                VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
                skip_emulated_instruction(vcpu);
@@ -7424,9 +7423,10 @@ static int handle_invvpid(struct kvm_vcpu *vcpu)
        vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO);
        type = kvm_register_readl(vcpu, (vmx_instruction_info >> 28) & 0xf);
 
-       types = (vmx->nested.nested_vmx_vpid_caps >> 8) & 0x7;
+       types = (vmx->nested.nested_vmx_vpid_caps &
+                       VMX_VPID_EXTENT_SUPPORTED_MASK) >> 8;
 
-       if (!(types & (1UL << type))) {
+       if (type >= 32 || !(types & (1 << type))) {
                nested_vmx_failValid(vcpu,
                        VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
                skip_emulated_instruction(vcpu);
@@ -7446,21 +7446,27 @@ static int handle_invvpid(struct kvm_vcpu *vcpu)
        }
 
        switch (type) {
+       case VMX_VPID_EXTENT_INDIVIDUAL_ADDR:
        case VMX_VPID_EXTENT_SINGLE_CONTEXT:
-               /*
-                * Old versions of KVM use the single-context version so we
-                * have to support it; just treat it the same as all-context.
-                */
+       case VMX_VPID_EXTENT_SINGLE_NON_GLOBAL:
+               if (!vpid) {
+                       nested_vmx_failValid(vcpu,
+                               VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
+                       skip_emulated_instruction(vcpu);
+                       return 1;
+               }
+               break;
        case VMX_VPID_EXTENT_ALL_CONTEXT:
-               __vmx_flush_tlb(vcpu, to_vmx(vcpu)->nested.vpid02);
-               nested_vmx_succeed(vcpu);
                break;
        default:
-               /* Trap individual address invalidation invvpid calls */
-               BUG_ON(1);
-               break;
+               WARN_ON_ONCE(1);
+               skip_emulated_instruction(vcpu);
+               return 1;
        }
 
+       __vmx_flush_tlb(vcpu, vmx->nested.vpid02);
+       nested_vmx_succeed(vcpu);
+
        skip_emulated_instruction(vcpu);
        return 1;
 }
@@ -8376,13 +8382,13 @@ static void vmx_handle_external_intr(struct kvm_vcpu *vcpu)
                        "pushf\n\t"
                        "orl $0x200, (%%" _ASM_SP ")\n\t"
                        __ASM_SIZE(push) " $%c[cs]\n\t"
-                       "call *%[entry]\n\t"
+                       CALL_NOSPEC
                        :
 #ifdef CONFIG_X86_64
                        [sp]"=&r"(tmp)
 #endif
                        :
-                       [entry]"r"(entry),
+                       THUNK_TARGET(entry),
                        [ss]"i"(__KERNEL_DS),
                        [cs]"i"(__KERNEL_CS)
                        );
@@ -9239,11 +9245,6 @@ static inline bool nested_vmx_merge_msr_bitmap(struct kvm_vcpu *vcpu,
                return false;
        }
        msr_bitmap = (unsigned long *)kmap(page);
-       if (!msr_bitmap) {
-               nested_release_page_clean(page);
-               WARN_ON(1);
-               return false;
-       }
 
        if (nested_cpu_has_virt_x2apic_mode(vmcs12)) {
                if (nested_cpu_has_apic_reg_virt(vmcs12))
@@ -10165,7 +10166,8 @@ static int vmx_check_nested_events(struct kvm_vcpu *vcpu, bool external_intr)
                return 0;
        }
 
-       return vmx_complete_nested_posted_interrupt(vcpu);
+       vmx_complete_nested_posted_interrupt(vcpu);
+       return 0;
 }
 
 static u32 vmx_get_preemption_timer_value(struct kvm_vcpu *vcpu)
index 3900d34..f37f0c7 100644 (file)
@@ -2755,6 +2755,12 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
        kvm_x86_ops->vcpu_put(vcpu);
        kvm_put_guest_fpu(vcpu);
        vcpu->arch.last_host_tsc = rdtsc();
+       /*
+        * If userspace has set any breakpoints or watchpoints, dr6 is restored
+        * on every vmexit, but if not, we might have a stale dr6 from the
+        * guest. do_debug expects dr6 to be cleared after it runs, do the same.
+        */
+       set_debugreg(0, 6);
 }
 
 static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu,
@@ -8204,6 +8210,13 @@ static int apf_put_user(struct kvm_vcpu *vcpu, u32 val)
                                      sizeof(val));
 }
 
+static int apf_get_user(struct kvm_vcpu *vcpu, u32 *val)
+{
+
+       return kvm_read_guest_cached(vcpu->kvm, &vcpu->arch.apf.data, val,
+                                     sizeof(u32));
+}
+
 void kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
                                     struct kvm_async_pf *work)
 {
@@ -8230,6 +8243,7 @@ void kvm_arch_async_page_present(struct kvm_vcpu *vcpu,
                                 struct kvm_async_pf *work)
 {
        struct x86_exception fault;
+       u32 val;
 
        if (work->wakeup_all)
                work->arch.token = ~0; /* broadcast wakeup */
@@ -8237,14 +8251,24 @@ void kvm_arch_async_page_present(struct kvm_vcpu *vcpu,
                kvm_del_async_pf_gfn(vcpu, work->arch.gfn);
        trace_kvm_async_pf_ready(work->arch.token, work->gva);
 
-       if ((vcpu->arch.apf.msr_val & KVM_ASYNC_PF_ENABLED) &&
-           !apf_put_user(vcpu, KVM_PV_REASON_PAGE_READY)) {
-               fault.vector = PF_VECTOR;
-               fault.error_code_valid = true;
-               fault.error_code = 0;
-               fault.nested_page_fault = false;
-               fault.address = work->arch.token;
-               kvm_inject_page_fault(vcpu, &fault);
+       if (vcpu->arch.apf.msr_val & KVM_ASYNC_PF_ENABLED &&
+           !apf_get_user(vcpu, &val)) {
+               if (val == KVM_PV_REASON_PAGE_NOT_PRESENT &&
+                   vcpu->arch.exception.pending &&
+                   vcpu->arch.exception.nr == PF_VECTOR &&
+                   !apf_put_user(vcpu, 0)) {
+                       vcpu->arch.exception.pending = false;
+                       vcpu->arch.exception.nr = 0;
+                       vcpu->arch.exception.has_error_code = false;
+                       vcpu->arch.exception.error_code = 0;
+               } else if (!apf_put_user(vcpu, KVM_PV_REASON_PAGE_READY)) {
+                       fault.vector = PF_VECTOR;
+                       fault.error_code_valid = true;
+                       fault.error_code = 0;
+                       fault.nested_page_fault = false;
+                       fault.address = work->arch.token;
+                       kvm_inject_page_fault(vcpu, &fault);
+               }
        }
        vcpu->arch.apf.halted = false;
        vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
index 46668cd..490b2ee 100644 (file)
@@ -38,6 +38,8 @@ ENTRY(__get_user_1)
        GET_THREAD_INFO(%_ASM_DX)
        cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
        jae bad_get_user
+       sbb %_ASM_DX, %_ASM_DX          /* array_index_mask_nospec() */
+       and %_ASM_DX, %_ASM_AX
        ASM_STAC
 1:     movzbl (%_ASM_AX),%edx
        xor %eax,%eax
@@ -51,6 +53,8 @@ ENTRY(__get_user_2)
        GET_THREAD_INFO(%_ASM_DX)
        cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
        jae bad_get_user
+       sbb %_ASM_DX, %_ASM_DX          /* array_index_mask_nospec() */
+       and %_ASM_DX, %_ASM_AX
        ASM_STAC
 2:     movzwl -1(%_ASM_AX),%edx
        xor %eax,%eax
@@ -64,6 +68,8 @@ ENTRY(__get_user_4)
        GET_THREAD_INFO(%_ASM_DX)
        cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
        jae bad_get_user
+       sbb %_ASM_DX, %_ASM_DX          /* array_index_mask_nospec() */
+       and %_ASM_DX, %_ASM_AX
        ASM_STAC
 3:     movl -3(%_ASM_AX),%edx
        xor %eax,%eax
@@ -78,6 +84,8 @@ ENTRY(__get_user_8)
        GET_THREAD_INFO(%_ASM_DX)
        cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
        jae bad_get_user
+       sbb %_ASM_DX, %_ASM_DX          /* array_index_mask_nospec() */
+       and %_ASM_DX, %_ASM_AX
        ASM_STAC
 4:     movq -7(%_ASM_AX),%rdx
        xor %eax,%eax
@@ -89,6 +97,8 @@ ENTRY(__get_user_8)
        GET_THREAD_INFO(%_ASM_DX)
        cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
        jae bad_get_user_8
+       sbb %_ASM_DX, %_ASM_DX          /* array_index_mask_nospec() */
+       and %_ASM_DX, %_ASM_AX
        ASM_STAC
 4:     movl -7(%_ASM_AX),%edx
 5:     movl -3(%_ASM_AX),%ecx
index e611a12..3d06b48 100644 (file)
@@ -36,7 +36,6 @@ GENERATE_THUNK(_ASM_DX)
 GENERATE_THUNK(_ASM_SI)
 GENERATE_THUNK(_ASM_DI)
 GENERATE_THUNK(_ASM_BP)
-GENERATE_THUNK(_ASM_SP)
 #ifdef CONFIG_64BIT
 GENERATE_THUNK(r8)
 GENERATE_THUNK(r9)
index 9b0c63b..1b2dac1 100644 (file)
@@ -5,8 +5,8 @@
 #DEBUG = -DDEBUGGING
 DEBUG  =
 PARANOID = -DPARANOID
-EXTRA_CFLAGS   := $(PARANOID) $(DEBUG) -fno-builtin $(MATH_EMULATION)
-EXTRA_AFLAGS   := $(PARANOID)
+ccflags-y += $(PARANOID) $(DEBUG) -fno-builtin $(MATH_EMULATION)
+asflags-y += $(PARANOID)
 
 # From 'C' language sources:
 C_OBJS =fpu_entry.o errors.o \
index b77360f..19b33b5 100644 (file)
@@ -168,7 +168,7 @@ static int compare(FPU_REG const *b, int tagb)
 /* This function requires that st(0) is not empty */
 int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag)
 {
-       int f = 0, c;
+       int f, c;
 
        c = compare(loaded_data, loaded_tag);
 
@@ -189,12 +189,12 @@ int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag)
                case COMP_No_Comp:
                        f = SW_C3 | SW_C2 | SW_C0;
                        break;
-#ifdef PARANOID
                default:
+#ifdef PARANOID
                        EXCEPTION(EX_INTERNAL | 0x121);
+#endif /* PARANOID */
                        f = SW_C3 | SW_C2 | SW_C0;
                        break;
-#endif /* PARANOID */
                }
        setcc(f);
        if (c & COMP_Denormal) {
@@ -205,7 +205,7 @@ int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag)
 
 static int compare_st_st(int nr)
 {
-       int f = 0, c;
+       int f, c;
        FPU_REG *st_ptr;
 
        if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) {
@@ -235,12 +235,12 @@ static int compare_st_st(int nr)
                case COMP_No_Comp:
                        f = SW_C3 | SW_C2 | SW_C0;
                        break;
-#ifdef PARANOID
                default:
+#ifdef PARANOID
                        EXCEPTION(EX_INTERNAL | 0x122);
+#endif /* PARANOID */
                        f = SW_C3 | SW_C2 | SW_C0;
                        break;
-#endif /* PARANOID */
                }
        setcc(f);
        if (c & COMP_Denormal) {
@@ -283,12 +283,12 @@ static int compare_i_st_st(int nr)
        case COMP_No_Comp:
                f = X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF;
                break;
-#ifdef PARANOID
        default:
+#ifdef PARANOID
                EXCEPTION(EX_INTERNAL | 0x122);
+#endif /* PARANOID */
                f = 0;
                break;
-#endif /* PARANOID */
        }
        FPU_EFLAGS = (FPU_EFLAGS & ~(X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF)) | f;
        if (c & COMP_Denormal) {
index b9c78f3..53ab3f3 100644 (file)
@@ -348,11 +348,11 @@ void iounmap(volatile void __iomem *addr)
            (void __force *)addr < phys_to_virt(ISA_END_ADDRESS))
                return;
 
+       mmiotrace_iounmap(addr);
+
        addr = (volatile void __iomem *)
                (PAGE_MASK & (unsigned long __force)addr);
 
-       mmiotrace_iounmap(addr);
-
        /* Use the vm area unlocked, assuming the caller
           ensures there isn't another iounmap for the same address
           in parallel. Reuse of the virtual address is prevented by
index 2298434..7a72e32 100644 (file)
@@ -363,7 +363,7 @@ void __init kaiser_init(void)
        kaiser_add_user_map_ptrs_early(__entry_text_start, __entry_text_end,
                                       __PAGE_KERNEL_RX);
 
-#if defined(CONFIG_FUNCTION_GRAPH_TRACER) || defined(CONFIG_KASAN)
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
        kaiser_add_user_map_ptrs_early(__irqentry_text_start,
                                       __irqentry_text_end,
                                       __PAGE_KERNEL_RX);
index ddb2244..76604c8 100644 (file)
@@ -434,17 +434,18 @@ int register_kmmio_probe(struct kmmio_probe *p)
        unsigned long flags;
        int ret = 0;
        unsigned long size = 0;
+       unsigned long addr = p->addr & PAGE_MASK;
        const unsigned long size_lim = p->len + (p->addr & ~PAGE_MASK);
        unsigned int l;
        pte_t *pte;
 
        spin_lock_irqsave(&kmmio_lock, flags);
-       if (get_kmmio_probe(p->addr)) {
+       if (get_kmmio_probe(addr)) {
                ret = -EEXIST;
                goto out;
        }
 
-       pte = lookup_address(p->addr, &l);
+       pte = lookup_address(addr, &l);
        if (!pte) {
                ret = -EINVAL;
                goto out;
@@ -453,7 +454,7 @@ int register_kmmio_probe(struct kmmio_probe *p)
        kmmio_count++;
        list_add_rcu(&p->list, &kmmio_probes);
        while (size < size_lim) {
-               if (add_kmmio_fault_page(p->addr + size))
+               if (add_kmmio_fault_page(addr + size))
                        pr_err("Unable to set page fault.\n");
                size += page_level_size(l);
        }
@@ -527,19 +528,20 @@ void unregister_kmmio_probe(struct kmmio_probe *p)
 {
        unsigned long flags;
        unsigned long size = 0;
+       unsigned long addr = p->addr & PAGE_MASK;
        const unsigned long size_lim = p->len + (p->addr & ~PAGE_MASK);
        struct kmmio_fault_page *release_list = NULL;
        struct kmmio_delayed_release *drelease;
        unsigned int l;
        pte_t *pte;
 
-       pte = lookup_address(p->addr, &l);
+       pte = lookup_address(addr, &l);
        if (!pte)
                return;
 
        spin_lock_irqsave(&kmmio_lock, flags);
        while (size < size_lim) {
-               release_kmmio_fault_page(p->addr + size, &release_list);
+               release_kmmio_fault_page(addr + size, &release_list);
                size += page_level_size(l);
        }
        list_del_rcu(&p->list);
index 5513084..c0533fb 100644 (file)
@@ -196,6 +196,7 @@ static int xo15_sci_remove(struct acpi_device *device)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int xo15_sci_resume(struct device *dev)
 {
        /* Enable all EC events */
@@ -207,6 +208,7 @@ static int xo15_sci_resume(struct device *dev)
 
        return 0;
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(xo15_sci_pm, NULL, xo15_sci_resume);
 
index 82044f7..bdad9be 100644 (file)
@@ -16,6 +16,7 @@ config XTENSA
        select GENERIC_SCHED_CLOCK
        select HAVE_DMA_API_DEBUG
        select HAVE_DMA_ATTRS
+       select HAVE_EXIT_THREAD
        select HAVE_FUNCTION_TRACER
        select HAVE_FUTEX_CMPXCHG if !MMU
        select HAVE_IRQ_TIME_ACCOUNTING
index b39531b..72bfc1c 100644 (file)
@@ -109,7 +109,6 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
                              u32 oldval, u32 newval)
 {
        int ret = 0;
-       u32 prev;
 
        if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
                return -EFAULT;
@@ -120,26 +119,24 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
 
        __asm__ __volatile__ (
        "       # futex_atomic_cmpxchg_inatomic\n"
-       "1:     l32i    %1, %3, 0\n"
-       "       mov     %0, %5\n"
-       "       wsr     %1, scompare1\n"
-       "2:     s32c1i  %0, %3, 0\n"
-       "3:\n"
+       "       wsr     %5, scompare1\n"
+       "1:     s32c1i  %1, %4, 0\n"
+       "       s32i    %1, %6, 0\n"
+       "2:\n"
        "       .section .fixup,\"ax\"\n"
        "       .align 4\n"
-       "4:     .long   3b\n"
-       "5:     l32r    %1, 4b\n"
-       "       movi    %0, %6\n"
+       "3:     .long   2b\n"
+       "4:     l32r    %1, 3b\n"
+       "       movi    %0, %7\n"
        "       jx      %1\n"
        "       .previous\n"
        "       .section __ex_table,\"a\"\n"
-       "       .long 1b,5b,2b,5b\n"
+       "       .long 1b,4b\n"
        "       .previous\n"
-       : "+r" (ret), "=&r" (prev), "+m" (*uaddr)
-       : "r" (uaddr), "r" (oldval), "r" (newval), "I" (-EFAULT)
+       : "+r" (ret), "+r" (newval), "+m" (*uaddr), "+m" (*uval)
+       : "r" (uaddr), "r" (oldval), "r" (uval), "I" (-EFAULT)
        : "memory");
 
-       *uval = prev;
        return ret;
 }
 
index 1c85323..17a378c 100644 (file)
@@ -113,10 +113,10 @@ void arch_cpu_idle(void)
 /*
  * This is called when the thread calls exit().
  */
-void exit_thread(void)
+void exit_thread(struct task_struct *tsk)
 {
 #if XTENSA_HAVE_COPROCESSORS
-       coprocessor_release_all(current_thread_info());
+       coprocessor_release_all(task_thread_info(tsk));
 #endif
 }
 
index f30d601..9d89b99 100644 (file)
@@ -40,29 +40,34 @@ ifndef CONFIG_MODULE_SIG_HASH
 $(error Could not determine digest type to use from kernel config)
 endif
 
+redirect_openssl       = 2>&1
+quiet_redirect_openssl = 2>&1
+silent_redirect_openssl = 2>/dev/null
+
 # We do it this way rather than having a boolean option for enabling an
 # external private key, because 'make randconfig' might enable such a
 # boolean option and we unfortunately can't make it depend on !RANDCONFIG.
 ifeq ($(CONFIG_MODULE_SIG_KEY),"certs/signing_key.pem")
 $(obj)/signing_key.pem: $(obj)/x509.genkey
-       @echo "###"
-       @echo "### Now generating an X.509 key pair to be used for signing modules."
-       @echo "###"
-       @echo "### If this takes a long time, you might wish to run rngd in the"
-       @echo "### background to keep the supply of entropy topped up.  It"
-       @echo "### needs to be run as root, and uses a hardware random"
-       @echo "### number generator if one is available."
-       @echo "###"
-       openssl req -new -nodes -utf8 -$(CONFIG_MODULE_SIG_HASH) -days 36500 \
+       @$(kecho) "###"
+       @$(kecho) "### Now generating an X.509 key pair to be used for signing modules."
+       @$(kecho) "###"
+       @$(kecho) "### If this takes a long time, you might wish to run rngd in the"
+       @$(kecho) "### background to keep the supply of entropy topped up.  It"
+       @$(kecho) "### needs to be run as root, and uses a hardware random"
+       @$(kecho) "### number generator if one is available."
+       @$(kecho) "###"
+       $(Q)openssl req -new -nodes -utf8 -$(CONFIG_MODULE_SIG_HASH) -days 36500 \
                -batch -x509 -config $(obj)/x509.genkey \
                -outform PEM -out $(obj)/signing_key.pem \
-               -keyout $(obj)/signing_key.pem 2>&1
-       @echo "###"
-       @echo "### Key pair generated."
-       @echo "###"
+               -keyout $(obj)/signing_key.pem \
+               $($(quiet)redirect_openssl)
+       @$(kecho) "###"
+       @$(kecho) "### Key pair generated."
+       @$(kecho) "###"
 
 $(obj)/x509.genkey:
-       @echo Generating X.509 key generation config
+       @$(kecho) Generating X.509 key generation config
        @echo  >$@ "[ req ]"
        @echo >>$@ "default_bits = 4096"
        @echo >>$@ "distinguished_name = req_distinguished_name"
index 3240d39..7a9f4d3 100644 (file)
@@ -1390,6 +1390,20 @@ config CRYPTO_SERPENT_AVX2_X86_64
          See also:
          <http://www.cl.cam.ac.uk/~rja14/serpent.html>
 
+config CRYPTO_SPECK
+       tristate "Speck cipher algorithm"
+       select CRYPTO_ALGAPI
+       help
+         Speck is a lightweight block cipher that is tuned for optimal
+         performance in software (rather than hardware).
+
+         Speck may not be as secure as AES, and should only be used on systems
+         where AES is not fast enough.
+
+         See also: <https://eprint.iacr.org/2013/404.pdf>
+
+         If unsure, say N.
+
 config CRYPTO_TEA
        tristate "TEA, XTEA and XETA cipher algorithms"
        select CRYPTO_ALGAPI
index 8507d1f..7ae15c4 100644 (file)
@@ -98,6 +98,7 @@ obj-$(CONFIG_CRYPTO_TEA) += tea.o
 obj-$(CONFIG_CRYPTO_KHAZAD) += khazad.o
 obj-$(CONFIG_CRYPTO_ANUBIS) += anubis.o
 obj-$(CONFIG_CRYPTO_SEED) += seed.o
+obj-$(CONFIG_CRYPTO_SPECK) += speck.o
 obj-$(CONFIG_CRYPTO_SALSA20) += salsa20_generic.o
 obj-$(CONFIG_CRYPTO_CHACHA20) += chacha20_generic.o
 obj-$(CONFIG_CRYPTO_POLY1305) += poly1305_generic.o
index f9caf0f..7006dbf 100644 (file)
@@ -637,5 +637,16 @@ struct hash_alg_common *ahash_attr_alg(struct rtattr *rta, u32 type, u32 mask)
 }
 EXPORT_SYMBOL_GPL(ahash_attr_alg);
 
+bool crypto_hash_alg_has_setkey(struct hash_alg_common *halg)
+{
+       struct crypto_alg *alg = &halg->base;
+
+       if (alg->cra_type != &crypto_ahash_type)
+               return crypto_shash_alg_has_setkey(__crypto_shash_alg(alg));
+
+       return __crypto_ahash_alg(alg)->setkey != NULL;
+}
+EXPORT_SYMBOL_GPL(crypto_hash_alg_has_setkey);
+
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Asynchronous cryptographic hash type");
index 26a504d..10a5a3e 100644 (file)
@@ -654,7 +654,8 @@ static int cryptd_create_hash(struct crypto_template *tmpl, struct rtattr **tb,
        inst->alg.finup  = cryptd_hash_finup_enqueue;
        inst->alg.export = cryptd_hash_export;
        inst->alg.import = cryptd_hash_import;
-       inst->alg.setkey = cryptd_hash_setkey;
+       if (crypto_shash_alg_has_setkey(salg))
+               inst->alg.setkey = cryptd_hash_setkey;
        inst->alg.digest = cryptd_hash_digest_enqueue;
 
        err = ahash_register_instance(tmpl, inst);
index 2df9835..bca9923 100644 (file)
@@ -51,17 +51,6 @@ int crypto_poly1305_init(struct shash_desc *desc)
 }
 EXPORT_SYMBOL_GPL(crypto_poly1305_init);
 
-int crypto_poly1305_setkey(struct crypto_shash *tfm,
-                          const u8 *key, unsigned int keylen)
-{
-       /* Poly1305 requires a unique key for each tag, which implies that
-        * we can't set it on the tfm that gets accessed by multiple users
-        * simultaneously. Instead we expect the key as the first 32 bytes in
-        * the update() call. */
-       return -ENOTSUPP;
-}
-EXPORT_SYMBOL_GPL(crypto_poly1305_setkey);
-
 static void poly1305_setrkey(struct poly1305_desc_ctx *dctx, const u8 *key)
 {
        /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
@@ -80,6 +69,11 @@ static void poly1305_setskey(struct poly1305_desc_ctx *dctx, const u8 *key)
        dctx->s[3] = le32_to_cpuvp(key + 12);
 }
 
+/*
+ * Poly1305 requires a unique key for each tag, which implies that we can't set
+ * it on the tfm that gets accessed by multiple users simultaneously. Instead we
+ * expect the key as the first 32 bytes in the update() call.
+ */
 unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx,
                                        const u8 *src, unsigned int srclen)
 {
@@ -285,7 +279,6 @@ static struct shash_alg poly1305_alg = {
        .init           = crypto_poly1305_init,
        .update         = crypto_poly1305_update,
        .final          = crypto_poly1305_final,
-       .setkey         = crypto_poly1305_setkey,
        .descsize       = sizeof(struct poly1305_desc_ctx),
        .base           = {
                .cra_name               = "poly1305",
diff --git a/crypto/speck.c b/crypto/speck.c
new file mode 100644 (file)
index 0000000..58aa9f7
--- /dev/null
@@ -0,0 +1,307 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Speck: a lightweight block cipher
+ *
+ * Copyright (c) 2018 Google, Inc
+ *
+ * Speck has 10 variants, including 5 block sizes.  For now we only implement
+ * the variants Speck128/128, Speck128/192, Speck128/256, Speck64/96, and
+ * Speck64/128.   Speck${B}/${K} denotes the variant with a block size of B bits
+ * and a key size of K bits.  The Speck128 variants are believed to be the most
+ * secure variants, and they use the same block size and key sizes as AES.  The
+ * Speck64 variants are less secure, but on 32-bit processors are usually
+ * faster.  The remaining variants (Speck32, Speck48, and Speck96) are even less
+ * secure and/or not as well suited for implementation on either 32-bit or
+ * 64-bit processors, so are omitted.
+ *
+ * Reference: "The Simon and Speck Families of Lightweight Block Ciphers"
+ * https://eprint.iacr.org/2013/404.pdf
+ *
+ * In a correspondence, the Speck designers have also clarified that the words
+ * should be interpreted in little-endian format, and the words should be
+ * ordered such that the first word of each block is 'y' rather than 'x', and
+ * the first key word (rather than the last) becomes the first round key.
+ */
+
+#include <asm/unaligned.h>
+#include <crypto/speck.h>
+#include <linux/bitops.h>
+#include <linux/crypto.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
+/* Speck128 */
+
+static __always_inline void speck128_round(u64 *x, u64 *y, u64 k)
+{
+       *x = ror64(*x, 8);
+       *x += *y;
+       *x ^= k;
+       *y = rol64(*y, 3);
+       *y ^= *x;
+}
+
+static __always_inline void speck128_unround(u64 *x, u64 *y, u64 k)
+{
+       *y ^= *x;
+       *y = ror64(*y, 3);
+       *x ^= k;
+       *x -= *y;
+       *x = rol64(*x, 8);
+}
+
+void crypto_speck128_encrypt(const struct speck128_tfm_ctx *ctx,
+                            u8 *out, const u8 *in)
+{
+       u64 y = get_unaligned_le64(in);
+       u64 x = get_unaligned_le64(in + 8);
+       int i;
+
+       for (i = 0; i < ctx->nrounds; i++)
+               speck128_round(&x, &y, ctx->round_keys[i]);
+
+       put_unaligned_le64(y, out);
+       put_unaligned_le64(x, out + 8);
+}
+EXPORT_SYMBOL_GPL(crypto_speck128_encrypt);
+
+static void speck128_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+       crypto_speck128_encrypt(crypto_tfm_ctx(tfm), out, in);
+}
+
+void crypto_speck128_decrypt(const struct speck128_tfm_ctx *ctx,
+                            u8 *out, const u8 *in)
+{
+       u64 y = get_unaligned_le64(in);
+       u64 x = get_unaligned_le64(in + 8);
+       int i;
+
+       for (i = ctx->nrounds - 1; i >= 0; i--)
+               speck128_unround(&x, &y, ctx->round_keys[i]);
+
+       put_unaligned_le64(y, out);
+       put_unaligned_le64(x, out + 8);
+}
+EXPORT_SYMBOL_GPL(crypto_speck128_decrypt);
+
+static void speck128_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+       crypto_speck128_decrypt(crypto_tfm_ctx(tfm), out, in);
+}
+
+int crypto_speck128_setkey(struct speck128_tfm_ctx *ctx, const u8 *key,
+                          unsigned int keylen)
+{
+       u64 l[3];
+       u64 k;
+       int i;
+
+       switch (keylen) {
+       case SPECK128_128_KEY_SIZE:
+               k = get_unaligned_le64(key);
+               l[0] = get_unaligned_le64(key + 8);
+               ctx->nrounds = SPECK128_128_NROUNDS;
+               for (i = 0; i < ctx->nrounds; i++) {
+                       ctx->round_keys[i] = k;
+                       speck128_round(&l[0], &k, i);
+               }
+               break;
+       case SPECK128_192_KEY_SIZE:
+               k = get_unaligned_le64(key);
+               l[0] = get_unaligned_le64(key + 8);
+               l[1] = get_unaligned_le64(key + 16);
+               ctx->nrounds = SPECK128_192_NROUNDS;
+               for (i = 0; i < ctx->nrounds; i++) {
+                       ctx->round_keys[i] = k;
+                       speck128_round(&l[i % 2], &k, i);
+               }
+               break;
+       case SPECK128_256_KEY_SIZE:
+               k = get_unaligned_le64(key);
+               l[0] = get_unaligned_le64(key + 8);
+               l[1] = get_unaligned_le64(key + 16);
+               l[2] = get_unaligned_le64(key + 24);
+               ctx->nrounds = SPECK128_256_NROUNDS;
+               for (i = 0; i < ctx->nrounds; i++) {
+                       ctx->round_keys[i] = k;
+                       speck128_round(&l[i % 3], &k, i);
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_speck128_setkey);
+
+static int speck128_setkey(struct crypto_tfm *tfm, const u8 *key,
+                          unsigned int keylen)
+{
+       return crypto_speck128_setkey(crypto_tfm_ctx(tfm), key, keylen);
+}
+
+/* Speck64 */
+
+static __always_inline void speck64_round(u32 *x, u32 *y, u32 k)
+{
+       *x = ror32(*x, 8);
+       *x += *y;
+       *x ^= k;
+       *y = rol32(*y, 3);
+       *y ^= *x;
+}
+
+static __always_inline void speck64_unround(u32 *x, u32 *y, u32 k)
+{
+       *y ^= *x;
+       *y = ror32(*y, 3);
+       *x ^= k;
+       *x -= *y;
+       *x = rol32(*x, 8);
+}
+
+void crypto_speck64_encrypt(const struct speck64_tfm_ctx *ctx,
+                           u8 *out, const u8 *in)
+{
+       u32 y = get_unaligned_le32(in);
+       u32 x = get_unaligned_le32(in + 4);
+       int i;
+
+       for (i = 0; i < ctx->nrounds; i++)
+               speck64_round(&x, &y, ctx->round_keys[i]);
+
+       put_unaligned_le32(y, out);
+       put_unaligned_le32(x, out + 4);
+}
+EXPORT_SYMBOL_GPL(crypto_speck64_encrypt);
+
+static void speck64_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+       crypto_speck64_encrypt(crypto_tfm_ctx(tfm), out, in);
+}
+
+void crypto_speck64_decrypt(const struct speck64_tfm_ctx *ctx,
+                           u8 *out, const u8 *in)
+{
+       u32 y = get_unaligned_le32(in);
+       u32 x = get_unaligned_le32(in + 4);
+       int i;
+
+       for (i = ctx->nrounds - 1; i >= 0; i--)
+               speck64_unround(&x, &y, ctx->round_keys[i]);
+
+       put_unaligned_le32(y, out);
+       put_unaligned_le32(x, out + 4);
+}
+EXPORT_SYMBOL_GPL(crypto_speck64_decrypt);
+
+static void speck64_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+       crypto_speck64_decrypt(crypto_tfm_ctx(tfm), out, in);
+}
+
+int crypto_speck64_setkey(struct speck64_tfm_ctx *ctx, const u8 *key,
+                         unsigned int keylen)
+{
+       u32 l[3];
+       u32 k;
+       int i;
+
+       switch (keylen) {
+       case SPECK64_96_KEY_SIZE:
+               k = get_unaligned_le32(key);
+               l[0] = get_unaligned_le32(key + 4);
+               l[1] = get_unaligned_le32(key + 8);
+               ctx->nrounds = SPECK64_96_NROUNDS;
+               for (i = 0; i < ctx->nrounds; i++) {
+                       ctx->round_keys[i] = k;
+                       speck64_round(&l[i % 2], &k, i);
+               }
+               break;
+       case SPECK64_128_KEY_SIZE:
+               k = get_unaligned_le32(key);
+               l[0] = get_unaligned_le32(key + 4);
+               l[1] = get_unaligned_le32(key + 8);
+               l[2] = get_unaligned_le32(key + 12);
+               ctx->nrounds = SPECK64_128_NROUNDS;
+               for (i = 0; i < ctx->nrounds; i++) {
+                       ctx->round_keys[i] = k;
+                       speck64_round(&l[i % 3], &k, i);
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_speck64_setkey);
+
+static int speck64_setkey(struct crypto_tfm *tfm, const u8 *key,
+                         unsigned int keylen)
+{
+       return crypto_speck64_setkey(crypto_tfm_ctx(tfm), key, keylen);
+}
+
+/* Algorithm definitions */
+
+static struct crypto_alg speck_algs[] = {
+       {
+               .cra_name               = "speck128",
+               .cra_driver_name        = "speck128-generic",
+               .cra_priority           = 100,
+               .cra_flags              = CRYPTO_ALG_TYPE_CIPHER,
+               .cra_blocksize          = SPECK128_BLOCK_SIZE,
+               .cra_ctxsize            = sizeof(struct speck128_tfm_ctx),
+               .cra_module             = THIS_MODULE,
+               .cra_u                  = {
+                       .cipher = {
+                               .cia_min_keysize        = SPECK128_128_KEY_SIZE,
+                               .cia_max_keysize        = SPECK128_256_KEY_SIZE,
+                               .cia_setkey             = speck128_setkey,
+                               .cia_encrypt            = speck128_encrypt,
+                               .cia_decrypt            = speck128_decrypt
+                       }
+               }
+       }, {
+               .cra_name               = "speck64",
+               .cra_driver_name        = "speck64-generic",
+               .cra_priority           = 100,
+               .cra_flags              = CRYPTO_ALG_TYPE_CIPHER,
+               .cra_blocksize          = SPECK64_BLOCK_SIZE,
+               .cra_ctxsize            = sizeof(struct speck64_tfm_ctx),
+               .cra_module             = THIS_MODULE,
+               .cra_u                  = {
+                       .cipher = {
+                               .cia_min_keysize        = SPECK64_96_KEY_SIZE,
+                               .cia_max_keysize        = SPECK64_128_KEY_SIZE,
+                               .cia_setkey             = speck64_setkey,
+                               .cia_encrypt            = speck64_encrypt,
+                               .cia_decrypt            = speck64_decrypt
+                       }
+               }
+       }
+};
+
+static int __init speck_module_init(void)
+{
+       return crypto_register_algs(speck_algs, ARRAY_SIZE(speck_algs));
+}
+
+static void __exit speck_module_exit(void)
+{
+       crypto_unregister_algs(speck_algs, ARRAY_SIZE(speck_algs));
+}
+
+module_init(speck_module_init);
+module_exit(speck_module_exit);
+
+MODULE_DESCRIPTION("Speck block cipher (generic)");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Eric Biggers <ebiggers@google.com>");
+MODULE_ALIAS_CRYPTO("speck128");
+MODULE_ALIAS_CRYPTO("speck128-generic");
+MODULE_ALIAS_CRYPTO("speck64");
+MODULE_ALIAS_CRYPTO("speck64-generic");
index f522828..1d92b5d 100644 (file)
@@ -291,11 +291,13 @@ static void sg_init_aead(struct scatterlist *sg, char *xbuf[XBUFSIZE],
        }
 
        sg_init_table(sg, np + 1);
-       np--;
+       if (rem)
+               np--;
        for (k = 0; k < np; k++)
                sg_set_buf(&sg[k + 1], xbuf[k], PAGE_SIZE);
 
-       sg_set_buf(&sg[k + 1], xbuf[k], rem);
+       if (rem)
+               sg_set_buf(&sg[k + 1], xbuf[k], rem);
 }
 
 static void test_aead_speed(const char *algo, int enc, unsigned int secs,
index 6d4da8f..a4aef61 100644 (file)
@@ -3114,6 +3114,36 @@ static const struct alg_test_desc alg_test_descs[] = {
                        }
                }
        }, {
+               .alg = "ecb(speck128)",
+               .test = alg_test_skcipher,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = speck128_enc_tv_template,
+                                       .count = ARRAY_SIZE(speck128_enc_tv_template)
+                               },
+                               .dec = {
+                                       .vecs = speck128_dec_tv_template,
+                                       .count = ARRAY_SIZE(speck128_dec_tv_template)
+                               }
+                       }
+               }
+       }, {
+               .alg = "ecb(speck64)",
+               .test = alg_test_skcipher,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = speck64_enc_tv_template,
+                                       .count = ARRAY_SIZE(speck64_enc_tv_template)
+                               },
+                               .dec = {
+                                       .vecs = speck64_dec_tv_template,
+                                       .count = ARRAY_SIZE(speck64_dec_tv_template)
+                               }
+                       }
+               }
+       }, {
                .alg = "ecb(tea)",
                .test = alg_test_skcipher,
                .suite = {
@@ -3859,6 +3889,36 @@ static const struct alg_test_desc alg_test_descs[] = {
                        }
                }
        }, {
+               .alg = "xts(speck128)",
+               .test = alg_test_skcipher,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = speck128_xts_enc_tv_template,
+                                       .count = ARRAY_SIZE(speck128_xts_enc_tv_template)
+                               },
+                               .dec = {
+                                       .vecs = speck128_xts_dec_tv_template,
+                                       .count = ARRAY_SIZE(speck128_xts_dec_tv_template)
+                               }
+                       }
+               }
+       }, {
+               .alg = "xts(speck64)",
+               .test = alg_test_skcipher,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = speck64_xts_enc_tv_template,
+                                       .count = ARRAY_SIZE(speck64_xts_enc_tv_template)
+                               },
+                               .dec = {
+                                       .vecs = speck64_xts_dec_tv_template,
+                                       .count = ARRAY_SIZE(speck64_xts_dec_tv_template)
+                               }
+                       }
+               }
+       }, {
                .alg = "xts(twofish)",
                .test = alg_test_skcipher,
                .suite = {
index ba6530d..0bb950e 100644 (file)
@@ -12589,6 +12589,1492 @@ static struct cipher_testvec serpent_xts_dec_tv_template[] = {
        },
 };
 
+/*
+ * Speck test vectors taken from the original paper:
+ * "The Simon and Speck Families of Lightweight Block Ciphers"
+ * https://eprint.iacr.org/2013/404.pdf
+ *
+ * Note that the paper does not make byte and word order clear.  But it was
+ * confirmed with the authors that the intended orders are little endian byte
+ * order and (y, x) word order.  Equivalently, the printed test vectors, when
+ * looking at only the bytes (ignoring the whitespace that divides them into
+ * words), are backwards: the left-most byte is actually the one with the
+ * highest memory address, while the right-most byte is actually the one with
+ * the lowest memory address.
+ */
+
+static struct cipher_testvec speck128_enc_tv_template[] = {
+       { /* Speck128/128 */
+               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+               .klen   = 16,
+               .input  = "\x20\x6d\x61\x64\x65\x20\x69\x74"
+                         "\x20\x65\x71\x75\x69\x76\x61\x6c",
+               .ilen   = 16,
+               .result = "\x18\x0d\x57\x5c\xdf\xfe\x60\x78"
+                         "\x65\x32\x78\x79\x51\x98\x5d\xa6",
+               .rlen   = 16,
+       }, { /* Speck128/192 */
+               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17",
+               .klen   = 24,
+               .input  = "\x65\x6e\x74\x20\x74\x6f\x20\x43"
+                         "\x68\x69\x65\x66\x20\x48\x61\x72",
+               .ilen   = 16,
+               .result = "\x86\x18\x3c\xe0\x5d\x18\xbc\xf9"
+                         "\x66\x55\x13\x13\x3a\xcf\xe4\x1b",
+               .rlen   = 16,
+       }, { /* Speck128/256 */
+               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+               .klen   = 32,
+               .input  = "\x70\x6f\x6f\x6e\x65\x72\x2e\x20"
+                         "\x49\x6e\x20\x74\x68\x6f\x73\x65",
+               .ilen   = 16,
+               .result = "\x43\x8f\x18\x9c\x8d\xb4\xee\x4e"
+                         "\x3e\xf5\xc0\x05\x04\x01\x09\x41",
+               .rlen   = 16,
+       },
+};
+
+static struct cipher_testvec speck128_dec_tv_template[] = {
+       { /* Speck128/128 */
+               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+               .klen   = 16,
+               .input  = "\x18\x0d\x57\x5c\xdf\xfe\x60\x78"
+                         "\x65\x32\x78\x79\x51\x98\x5d\xa6",
+               .ilen   = 16,
+               .result = "\x20\x6d\x61\x64\x65\x20\x69\x74"
+                         "\x20\x65\x71\x75\x69\x76\x61\x6c",
+               .rlen   = 16,
+       }, { /* Speck128/192 */
+               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17",
+               .klen   = 24,
+               .input  = "\x86\x18\x3c\xe0\x5d\x18\xbc\xf9"
+                         "\x66\x55\x13\x13\x3a\xcf\xe4\x1b",
+               .ilen   = 16,
+               .result = "\x65\x6e\x74\x20\x74\x6f\x20\x43"
+                         "\x68\x69\x65\x66\x20\x48\x61\x72",
+               .rlen   = 16,
+       }, { /* Speck128/256 */
+               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+               .klen   = 32,
+               .input  = "\x43\x8f\x18\x9c\x8d\xb4\xee\x4e"
+                         "\x3e\xf5\xc0\x05\x04\x01\x09\x41",
+               .ilen   = 16,
+               .result = "\x70\x6f\x6f\x6e\x65\x72\x2e\x20"
+                         "\x49\x6e\x20\x74\x68\x6f\x73\x65",
+               .rlen   = 16,
+       },
+};
+
+/*
+ * Speck128-XTS test vectors, taken from the AES-XTS test vectors with the
+ * result recomputed with Speck128 as the cipher
+ */
+
+static struct cipher_testvec speck128_xts_enc_tv_template[] = {
+       {
+               .key    = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .ilen   = 32,
+               .result = "\xbe\xa0\xe7\x03\xd7\xfe\xab\x62"
+                         "\x3b\x99\x4a\x64\x74\x77\xac\xed"
+                         "\xd8\xf4\xa6\xcf\xae\xb9\x07\x42"
+                         "\x51\xd9\xb6\x1d\xe0\x5e\xbc\x54",
+               .rlen   = 32,
+       }, {
+               .key    = "\x11\x11\x11\x11\x11\x11\x11\x11"
+                         "\x11\x11\x11\x11\x11\x11\x11\x11"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22",
+               .klen   = 32,
+               .iv     = "\x33\x33\x33\x33\x33\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44",
+               .ilen   = 32,
+               .result = "\xfb\x53\x81\x75\x6f\x9f\x34\xad"
+                         "\x7e\x01\xed\x7b\xcc\xda\x4e\x4a"
+                         "\xd4\x84\xa4\x53\xd5\x88\x73\x1b"
+                         "\xfd\xcb\xae\x0d\xf3\x04\xee\xe6",
+               .rlen   = 32,
+       }, {
+               .key    = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8"
+                         "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22",
+               .klen   = 32,
+               .iv     = "\x33\x33\x33\x33\x33\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44",
+               .ilen   = 32,
+               .result = "\x21\x52\x84\x15\xd1\xf7\x21\x55"
+                         "\xd9\x75\x4a\xd3\xc5\xdb\x9f\x7d"
+                         "\xda\x63\xb2\xf1\x82\xb0\x89\x59"
+                         "\x86\xd4\xaa\xaa\xdd\xff\x4f\x92",
+               .rlen   = 32,
+       }, {
+               .key    = "\x27\x18\x28\x18\x28\x45\x90\x45"
+                         "\x23\x53\x60\x28\x74\x71\x35\x26"
+                         "\x31\x41\x59\x26\x53\x58\x97\x93"
+                         "\x23\x84\x62\x64\x33\x83\x27\x95",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+                         "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+               .ilen   = 512,
+               .result = "\x57\xb5\xf8\x71\x6e\x6d\xdd\x82"
+                         "\x53\xd0\xed\x2d\x30\xc1\x20\xef"
+                         "\x70\x67\x5e\xff\x09\x70\xbb\xc1"
+                         "\x3a\x7b\x48\x26\xd9\x0b\xf4\x48"
+                         "\xbe\xce\xb1\xc7\xb2\x67\xc4\xa7"
+                         "\x76\xf8\x36\x30\xb7\xb4\x9a\xd9"
+                         "\xf5\x9d\xd0\x7b\xc1\x06\x96\x44"
+                         "\x19\xc5\x58\x84\x63\xb9\x12\x68"
+                         "\x68\xc7\xaa\x18\x98\xf2\x1f\x5c"
+                         "\x39\xa6\xd8\x32\x2b\xc3\x51\xfd"
+                         "\x74\x79\x2e\xb4\x44\xd7\x69\xc4"
+                         "\xfc\x29\xe6\xed\x26\x1e\xa6\x9d"
+                         "\x1c\xbe\x00\x0e\x7f\x3a\xca\xfb"
+                         "\x6d\x13\x65\xa0\xf9\x31\x12\xe2"
+                         "\x26\xd1\xec\x2b\x0a\x8b\x59\x99"
+                         "\xa7\x49\xa0\x0e\x09\x33\x85\x50"
+                         "\xc3\x23\xca\x7a\xdd\x13\x45\x5f"
+                         "\xde\x4c\xa7\xcb\x00\x8a\x66\x6f"
+                         "\xa2\xb6\xb1\x2e\xe1\xa0\x18\xf6"
+                         "\xad\xf3\xbd\xeb\xc7\xef\x55\x4f"
+                         "\x79\x91\x8d\x36\x13\x7b\xd0\x4a"
+                         "\x6c\x39\xfb\x53\xb8\x6f\x02\x51"
+                         "\xa5\x20\xac\x24\x1c\x73\x59\x73"
+                         "\x58\x61\x3a\x87\x58\xb3\x20\x56"
+                         "\x39\x06\x2b\x4d\xd3\x20\x2b\x89"
+                         "\x3f\xa2\xf0\x96\xeb\x7f\xa4\xcd"
+                         "\x11\xae\xbd\xcb\x3a\xb4\xd9\x91"
+                         "\x09\x35\x71\x50\x65\xac\x92\xe3"
+                         "\x7b\x32\xc0\x7a\xdd\xd4\xc3\x92"
+                         "\x6f\xeb\x79\xde\x6f\xd3\x25\xc9"
+                         "\xcd\x63\xf5\x1e\x7a\x3b\x26\x9d"
+                         "\x77\x04\x80\xa9\xbf\x38\xb5\xbd"
+                         "\xb8\x05\x07\xbd\xfd\xab\x7b\xf8"
+                         "\x2a\x26\xcc\x49\x14\x6d\x55\x01"
+                         "\x06\x94\xd8\xb2\x2d\x53\x83\x1b"
+                         "\x8f\xd4\xdd\x57\x12\x7e\x18\xba"
+                         "\x8e\xe2\x4d\x80\xef\x7e\x6b\x9d"
+                         "\x24\xa9\x60\xa4\x97\x85\x86\x2a"
+                         "\x01\x00\x09\xf1\xcb\x4a\x24\x1c"
+                         "\xd8\xf6\xe6\x5b\xe7\x5d\xf2\xc4"
+                         "\x97\x1c\x10\xc6\x4d\x66\x4f\x98"
+                         "\x87\x30\xac\xd5\xea\x73\x49\x10"
+                         "\x80\xea\xe5\x5f\x4d\x5f\x03\x33"
+                         "\x66\x02\x35\x3d\x60\x06\x36\x4f"
+                         "\x14\x1c\xd8\x07\x1f\x78\xd0\xf8"
+                         "\x4f\x6c\x62\x7c\x15\xa5\x7c\x28"
+                         "\x7c\xcc\xeb\x1f\xd1\x07\x90\x93"
+                         "\x7e\xc2\xa8\x3a\x80\xc0\xf5\x30"
+                         "\xcc\x75\xcf\x16\x26\xa9\x26\x3b"
+                         "\xe7\x68\x2f\x15\x21\x5b\xe4\x00"
+                         "\xbd\x48\x50\xcd\x75\x70\xc4\x62"
+                         "\xbb\x41\xfb\x89\x4a\x88\x3b\x3b"
+                         "\x51\x66\x02\x69\x04\x97\x36\xd4"
+                         "\x75\xae\x0b\xa3\x42\xf8\xca\x79"
+                         "\x8f\x93\xe9\xcc\x38\xbd\xd6\xd2"
+                         "\xf9\x70\x4e\xc3\x6a\x8e\x25\xbd"
+                         "\xea\x15\x5a\xa0\x85\x7e\x81\x0d"
+                         "\x03\xe7\x05\x39\xf5\x05\x26\xee"
+                         "\xec\xaa\x1f\x3d\xc9\x98\x76\x01"
+                         "\x2c\xf4\xfc\xa3\x88\x77\x38\xc4"
+                         "\x50\x65\x50\x6d\x04\x1f\xdf\x5a"
+                         "\xaa\xf2\x01\xa9\xc1\x8d\xee\xca"
+                         "\x47\x26\xef\x39\xb8\xb4\xf2\xd1"
+                         "\xd6\xbb\x1b\x2a\xc1\x34\x14\xcf",
+               .rlen   = 512,
+       }, {
+               .key    = "\x27\x18\x28\x18\x28\x45\x90\x45"
+                         "\x23\x53\x60\x28\x74\x71\x35\x26"
+                         "\x62\x49\x77\x57\x24\x70\x93\x69"
+                         "\x99\x59\x57\x49\x66\x96\x76\x27"
+                         "\x31\x41\x59\x26\x53\x58\x97\x93"
+                         "\x23\x84\x62\x64\x33\x83\x27\x95"
+                         "\x02\x88\x41\x97\x16\x93\x99\x37"
+                         "\x51\x05\x82\x09\x74\x94\x45\x92",
+               .klen   = 64,
+               .iv     = "\xff\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+                         "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+               .ilen   = 512,
+               .result = "\xc5\x85\x2a\x4b\x73\xe4\xf6\xf1"
+                         "\x7e\xf9\xf6\xe9\xa3\x73\x36\xcb"
+                         "\xaa\xb6\x22\xb0\x24\x6e\x3d\x73"
+                         "\x92\x99\xde\xd3\x76\xed\xcd\x63"
+                         "\x64\x3a\x22\x57\xc1\x43\x49\xd4"
+                         "\x79\x36\x31\x19\x62\xae\x10\x7e"
+                         "\x7d\xcf\x7a\xe2\x6b\xce\x27\xfa"
+                         "\xdc\x3d\xd9\x83\xd3\x42\x4c\xe0"
+                         "\x1b\xd6\x1d\x1a\x6f\xd2\x03\x00"
+                         "\xfc\x81\x99\x8a\x14\x62\xf5\x7e"
+                         "\x0d\xe7\x12\xe8\x17\x9d\x0b\xec"
+                         "\xe2\xf7\xc9\xa7\x63\xd1\x79\xb6"
+                         "\x62\x62\x37\xfe\x0a\x4c\x4a\x37"
+                         "\x70\xc7\x5e\x96\x5f\xbc\x8e\x9e"
+                         "\x85\x3c\x4f\x26\x64\x85\xbc\x68"
+                         "\xb0\xe0\x86\x5e\x26\x41\xce\x11"
+                         "\x50\xda\x97\x14\xe9\x9e\xc7\x6d"
+                         "\x3b\xdc\x43\xde\x2b\x27\x69\x7d"
+                         "\xfc\xb0\x28\xbd\x8f\xb1\xc6\x31"
+                         "\x14\x4d\xf0\x74\x37\xfd\x07\x25"
+                         "\x96\x55\xe5\xfc\x9e\x27\x2a\x74"
+                         "\x1b\x83\x4d\x15\x83\xac\x57\xa0"
+                         "\xac\xa5\xd0\x38\xef\x19\x56\x53"
+                         "\x25\x4b\xfc\xce\x04\x23\xe5\x6b"
+                         "\xf6\xc6\x6c\x32\x0b\xb3\x12\xc5"
+                         "\xed\x22\x34\x1c\x5d\xed\x17\x06"
+                         "\x36\xa3\xe6\x77\xb9\x97\x46\xb8"
+                         "\xe9\x3f\x7e\xc7\xbc\x13\x5c\xdc"
+                         "\x6e\x3f\x04\x5e\xd1\x59\xa5\x82"
+                         "\x35\x91\x3d\x1b\xe4\x97\x9f\x92"
+                         "\x1c\x5e\x5f\x6f\x41\xd4\x62\xa1"
+                         "\x8d\x39\xfc\x42\xfb\x38\x80\xb9"
+                         "\x0a\xe3\xcc\x6a\x93\xd9\x7a\xb1"
+                         "\xe9\x69\xaf\x0a\x6b\x75\x38\xa7"
+                         "\xa1\xbf\xf7\xda\x95\x93\x4b\x78"
+                         "\x19\xf5\x94\xf9\xd2\x00\x33\x37"
+                         "\xcf\xf5\x9e\x9c\xf3\xcc\xa6\xee"
+                         "\x42\xb2\x9e\x2c\x5f\x48\x23\x26"
+                         "\x15\x25\x17\x03\x3d\xfe\x2c\xfc"
+                         "\xeb\xba\xda\xe0\x00\x05\xb6\xa6"
+                         "\x07\xb3\xe8\x36\x5b\xec\x5b\xbf"
+                         "\xd6\x5b\x00\x74\xc6\x97\xf1\x6a"
+                         "\x49\xa1\xc3\xfa\x10\x52\xb9\x14"
+                         "\xad\xb7\x73\xf8\x78\x12\xc8\x59"
+                         "\x17\x80\x4c\x57\x39\xf1\x6d\x80"
+                         "\x25\x77\x0f\x5e\x7d\xf0\xaf\x21"
+                         "\xec\xce\xb7\xc8\x02\x8a\xed\x53"
+                         "\x2c\x25\x68\x2e\x1f\x85\x5e\x67"
+                         "\xd1\x07\x7a\x3a\x89\x08\xe0\x34"
+                         "\xdc\xdb\x26\xb4\x6b\x77\xfc\x40"
+                         "\x31\x15\x72\xa0\xf0\x73\xd9\x3b"
+                         "\xd5\xdb\xfe\xfc\x8f\xa9\x44\xa2"
+                         "\x09\x9f\xc6\x33\xe5\xe2\x88\xe8"
+                         "\xf3\xf0\x1a\xf4\xce\x12\x0f\xd6"
+                         "\xf7\x36\xe6\xa4\xf4\x7a\x10\x58"
+                         "\xcc\x1f\x48\x49\x65\x47\x75\xe9"
+                         "\x28\xe1\x65\x7b\xf2\xc4\xb5\x07"
+                         "\xf2\xec\x76\xd8\x8f\x09\xf3\x16"
+                         "\xa1\x51\x89\x3b\xeb\x96\x42\xac"
+                         "\x65\xe0\x67\x63\x29\xdc\xb4\x7d"
+                         "\xf2\x41\x51\x6a\xcb\xde\x3c\xfb"
+                         "\x66\x8d\x13\xca\xe0\x59\x2a\x00"
+                         "\xc9\x53\x4c\xe6\x9e\xe2\x73\xd5"
+                         "\x67\x19\xb2\xbd\x9a\x63\xd7\x5c",
+               .rlen   = 512,
+               .also_non_np = 1,
+               .np     = 3,
+               .tap    = { 512 - 20, 4, 16 },
+       }
+};
+
+static struct cipher_testvec speck128_xts_dec_tv_template[] = {
+       {
+               .key    = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\xbe\xa0\xe7\x03\xd7\xfe\xab\x62"
+                         "\x3b\x99\x4a\x64\x74\x77\xac\xed"
+                         "\xd8\xf4\xa6\xcf\xae\xb9\x07\x42"
+                         "\x51\xd9\xb6\x1d\xe0\x5e\xbc\x54",
+               .ilen   = 32,
+               .result = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .rlen   = 32,
+       }, {
+               .key    = "\x11\x11\x11\x11\x11\x11\x11\x11"
+                         "\x11\x11\x11\x11\x11\x11\x11\x11"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22",
+               .klen   = 32,
+               .iv     = "\x33\x33\x33\x33\x33\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\xfb\x53\x81\x75\x6f\x9f\x34\xad"
+                         "\x7e\x01\xed\x7b\xcc\xda\x4e\x4a"
+                         "\xd4\x84\xa4\x53\xd5\x88\x73\x1b"
+                         "\xfd\xcb\xae\x0d\xf3\x04\xee\xe6",
+               .ilen   = 32,
+               .result = "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44",
+               .rlen   = 32,
+       }, {
+               .key    = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8"
+                         "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22",
+               .klen   = 32,
+               .iv     = "\x33\x33\x33\x33\x33\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x21\x52\x84\x15\xd1\xf7\x21\x55"
+                         "\xd9\x75\x4a\xd3\xc5\xdb\x9f\x7d"
+                         "\xda\x63\xb2\xf1\x82\xb0\x89\x59"
+                         "\x86\xd4\xaa\xaa\xdd\xff\x4f\x92",
+               .ilen   = 32,
+               .result = "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44",
+               .rlen   = 32,
+       }, {
+               .key    = "\x27\x18\x28\x18\x28\x45\x90\x45"
+                         "\x23\x53\x60\x28\x74\x71\x35\x26"
+                         "\x31\x41\x59\x26\x53\x58\x97\x93"
+                         "\x23\x84\x62\x64\x33\x83\x27\x95",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x57\xb5\xf8\x71\x6e\x6d\xdd\x82"
+                         "\x53\xd0\xed\x2d\x30\xc1\x20\xef"
+                         "\x70\x67\x5e\xff\x09\x70\xbb\xc1"
+                         "\x3a\x7b\x48\x26\xd9\x0b\xf4\x48"
+                         "\xbe\xce\xb1\xc7\xb2\x67\xc4\xa7"
+                         "\x76\xf8\x36\x30\xb7\xb4\x9a\xd9"
+                         "\xf5\x9d\xd0\x7b\xc1\x06\x96\x44"
+                         "\x19\xc5\x58\x84\x63\xb9\x12\x68"
+                         "\x68\xc7\xaa\x18\x98\xf2\x1f\x5c"
+                         "\x39\xa6\xd8\x32\x2b\xc3\x51\xfd"
+                         "\x74\x79\x2e\xb4\x44\xd7\x69\xc4"
+                         "\xfc\x29\xe6\xed\x26\x1e\xa6\x9d"
+                         "\x1c\xbe\x00\x0e\x7f\x3a\xca\xfb"
+                         "\x6d\x13\x65\xa0\xf9\x31\x12\xe2"
+                         "\x26\xd1\xec\x2b\x0a\x8b\x59\x99"
+                         "\xa7\x49\xa0\x0e\x09\x33\x85\x50"
+                         "\xc3\x23\xca\x7a\xdd\x13\x45\x5f"
+                         "\xde\x4c\xa7\xcb\x00\x8a\x66\x6f"
+                         "\xa2\xb6\xb1\x2e\xe1\xa0\x18\xf6"
+                         "\xad\xf3\xbd\xeb\xc7\xef\x55\x4f"
+                         "\x79\x91\x8d\x36\x13\x7b\xd0\x4a"
+                         "\x6c\x39\xfb\x53\xb8\x6f\x02\x51"
+                         "\xa5\x20\xac\x24\x1c\x73\x59\x73"
+                         "\x58\x61\x3a\x87\x58\xb3\x20\x56"
+                         "\x39\x06\x2b\x4d\xd3\x20\x2b\x89"
+                         "\x3f\xa2\xf0\x96\xeb\x7f\xa4\xcd"
+                         "\x11\xae\xbd\xcb\x3a\xb4\xd9\x91"
+                         "\x09\x35\x71\x50\x65\xac\x92\xe3"
+                         "\x7b\x32\xc0\x7a\xdd\xd4\xc3\x92"
+                         "\x6f\xeb\x79\xde\x6f\xd3\x25\xc9"
+                         "\xcd\x63\xf5\x1e\x7a\x3b\x26\x9d"
+                         "\x77\x04\x80\xa9\xbf\x38\xb5\xbd"
+                         "\xb8\x05\x07\xbd\xfd\xab\x7b\xf8"
+                         "\x2a\x26\xcc\x49\x14\x6d\x55\x01"
+                         "\x06\x94\xd8\xb2\x2d\x53\x83\x1b"
+                         "\x8f\xd4\xdd\x57\x12\x7e\x18\xba"
+                         "\x8e\xe2\x4d\x80\xef\x7e\x6b\x9d"
+                         "\x24\xa9\x60\xa4\x97\x85\x86\x2a"
+                         "\x01\x00\x09\xf1\xcb\x4a\x24\x1c"
+                         "\xd8\xf6\xe6\x5b\xe7\x5d\xf2\xc4"
+                         "\x97\x1c\x10\xc6\x4d\x66\x4f\x98"
+                         "\x87\x30\xac\xd5\xea\x73\x49\x10"
+                         "\x80\xea\xe5\x5f\x4d\x5f\x03\x33"
+                         "\x66\x02\x35\x3d\x60\x06\x36\x4f"
+                         "\x14\x1c\xd8\x07\x1f\x78\xd0\xf8"
+                         "\x4f\x6c\x62\x7c\x15\xa5\x7c\x28"
+                         "\x7c\xcc\xeb\x1f\xd1\x07\x90\x93"
+                         "\x7e\xc2\xa8\x3a\x80\xc0\xf5\x30"
+                         "\xcc\x75\xcf\x16\x26\xa9\x26\x3b"
+                         "\xe7\x68\x2f\x15\x21\x5b\xe4\x00"
+                         "\xbd\x48\x50\xcd\x75\x70\xc4\x62"
+                         "\xbb\x41\xfb\x89\x4a\x88\x3b\x3b"
+                         "\x51\x66\x02\x69\x04\x97\x36\xd4"
+                         "\x75\xae\x0b\xa3\x42\xf8\xca\x79"
+                         "\x8f\x93\xe9\xcc\x38\xbd\xd6\xd2"
+                         "\xf9\x70\x4e\xc3\x6a\x8e\x25\xbd"
+                         "\xea\x15\x5a\xa0\x85\x7e\x81\x0d"
+                         "\x03\xe7\x05\x39\xf5\x05\x26\xee"
+                         "\xec\xaa\x1f\x3d\xc9\x98\x76\x01"
+                         "\x2c\xf4\xfc\xa3\x88\x77\x38\xc4"
+                         "\x50\x65\x50\x6d\x04\x1f\xdf\x5a"
+                         "\xaa\xf2\x01\xa9\xc1\x8d\xee\xca"
+                         "\x47\x26\xef\x39\xb8\xb4\xf2\xd1"
+                         "\xd6\xbb\x1b\x2a\xc1\x34\x14\xcf",
+               .ilen   = 512,
+               .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+                         "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+               .rlen   = 512,
+       }, {
+               .key    = "\x27\x18\x28\x18\x28\x45\x90\x45"
+                         "\x23\x53\x60\x28\x74\x71\x35\x26"
+                         "\x62\x49\x77\x57\x24\x70\x93\x69"
+                         "\x99\x59\x57\x49\x66\x96\x76\x27"
+                         "\x31\x41\x59\x26\x53\x58\x97\x93"
+                         "\x23\x84\x62\x64\x33\x83\x27\x95"
+                         "\x02\x88\x41\x97\x16\x93\x99\x37"
+                         "\x51\x05\x82\x09\x74\x94\x45\x92",
+               .klen   = 64,
+               .iv     = "\xff\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\xc5\x85\x2a\x4b\x73\xe4\xf6\xf1"
+                         "\x7e\xf9\xf6\xe9\xa3\x73\x36\xcb"
+                         "\xaa\xb6\x22\xb0\x24\x6e\x3d\x73"
+                         "\x92\x99\xde\xd3\x76\xed\xcd\x63"
+                         "\x64\x3a\x22\x57\xc1\x43\x49\xd4"
+                         "\x79\x36\x31\x19\x62\xae\x10\x7e"
+                         "\x7d\xcf\x7a\xe2\x6b\xce\x27\xfa"
+                         "\xdc\x3d\xd9\x83\xd3\x42\x4c\xe0"
+                         "\x1b\xd6\x1d\x1a\x6f\xd2\x03\x00"
+                         "\xfc\x81\x99\x8a\x14\x62\xf5\x7e"
+                         "\x0d\xe7\x12\xe8\x17\x9d\x0b\xec"
+                         "\xe2\xf7\xc9\xa7\x63\xd1\x79\xb6"
+                         "\x62\x62\x37\xfe\x0a\x4c\x4a\x37"
+                         "\x70\xc7\x5e\x96\x5f\xbc\x8e\x9e"
+                         "\x85\x3c\x4f\x26\x64\x85\xbc\x68"
+                         "\xb0\xe0\x86\x5e\x26\x41\xce\x11"
+                         "\x50\xda\x97\x14\xe9\x9e\xc7\x6d"
+                         "\x3b\xdc\x43\xde\x2b\x27\x69\x7d"
+                         "\xfc\xb0\x28\xbd\x8f\xb1\xc6\x31"
+                         "\x14\x4d\xf0\x74\x37\xfd\x07\x25"
+                         "\x96\x55\xe5\xfc\x9e\x27\x2a\x74"
+                         "\x1b\x83\x4d\x15\x83\xac\x57\xa0"
+                         "\xac\xa5\xd0\x38\xef\x19\x56\x53"
+                         "\x25\x4b\xfc\xce\x04\x23\xe5\x6b"
+                         "\xf6\xc6\x6c\x32\x0b\xb3\x12\xc5"
+                         "\xed\x22\x34\x1c\x5d\xed\x17\x06"
+                         "\x36\xa3\xe6\x77\xb9\x97\x46\xb8"
+                         "\xe9\x3f\x7e\xc7\xbc\x13\x5c\xdc"
+                         "\x6e\x3f\x04\x5e\xd1\x59\xa5\x82"
+                         "\x35\x91\x3d\x1b\xe4\x97\x9f\x92"
+                         "\x1c\x5e\x5f\x6f\x41\xd4\x62\xa1"
+                         "\x8d\x39\xfc\x42\xfb\x38\x80\xb9"
+                         "\x0a\xe3\xcc\x6a\x93\xd9\x7a\xb1"
+                         "\xe9\x69\xaf\x0a\x6b\x75\x38\xa7"
+                         "\xa1\xbf\xf7\xda\x95\x93\x4b\x78"
+                         "\x19\xf5\x94\xf9\xd2\x00\x33\x37"
+                         "\xcf\xf5\x9e\x9c\xf3\xcc\xa6\xee"
+                         "\x42\xb2\x9e\x2c\x5f\x48\x23\x26"
+                         "\x15\x25\x17\x03\x3d\xfe\x2c\xfc"
+                         "\xeb\xba\xda\xe0\x00\x05\xb6\xa6"
+                         "\x07\xb3\xe8\x36\x5b\xec\x5b\xbf"
+                         "\xd6\x5b\x00\x74\xc6\x97\xf1\x6a"
+                         "\x49\xa1\xc3\xfa\x10\x52\xb9\x14"
+                         "\xad\xb7\x73\xf8\x78\x12\xc8\x59"
+                         "\x17\x80\x4c\x57\x39\xf1\x6d\x80"
+                         "\x25\x77\x0f\x5e\x7d\xf0\xaf\x21"
+                         "\xec\xce\xb7\xc8\x02\x8a\xed\x53"
+                         "\x2c\x25\x68\x2e\x1f\x85\x5e\x67"
+                         "\xd1\x07\x7a\x3a\x89\x08\xe0\x34"
+                         "\xdc\xdb\x26\xb4\x6b\x77\xfc\x40"
+                         "\x31\x15\x72\xa0\xf0\x73\xd9\x3b"
+                         "\xd5\xdb\xfe\xfc\x8f\xa9\x44\xa2"
+                         "\x09\x9f\xc6\x33\xe5\xe2\x88\xe8"
+                         "\xf3\xf0\x1a\xf4\xce\x12\x0f\xd6"
+                         "\xf7\x36\xe6\xa4\xf4\x7a\x10\x58"
+                         "\xcc\x1f\x48\x49\x65\x47\x75\xe9"
+                         "\x28\xe1\x65\x7b\xf2\xc4\xb5\x07"
+                         "\xf2\xec\x76\xd8\x8f\x09\xf3\x16"
+                         "\xa1\x51\x89\x3b\xeb\x96\x42\xac"
+                         "\x65\xe0\x67\x63\x29\xdc\xb4\x7d"
+                         "\xf2\x41\x51\x6a\xcb\xde\x3c\xfb"
+                         "\x66\x8d\x13\xca\xe0\x59\x2a\x00"
+                         "\xc9\x53\x4c\xe6\x9e\xe2\x73\xd5"
+                         "\x67\x19\xb2\xbd\x9a\x63\xd7\x5c",
+               .ilen   = 512,
+               .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+                         "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+               .rlen   = 512,
+               .also_non_np = 1,
+               .np     = 3,
+               .tap    = { 512 - 20, 4, 16 },
+       }
+};
+
+static struct cipher_testvec speck64_enc_tv_template[] = {
+       { /* Speck64/96 */
+               .key    = "\x00\x01\x02\x03\x08\x09\x0a\x0b"
+                         "\x10\x11\x12\x13",
+               .klen   = 12,
+               .input  = "\x65\x61\x6e\x73\x20\x46\x61\x74",
+               .ilen   = 8,
+               .result = "\x6c\x94\x75\x41\xec\x52\x79\x9f",
+               .rlen   = 8,
+       }, { /* Speck64/128 */
+               .key    = "\x00\x01\x02\x03\x08\x09\x0a\x0b"
+                         "\x10\x11\x12\x13\x18\x19\x1a\x1b",
+               .klen   = 16,
+               .input  = "\x2d\x43\x75\x74\x74\x65\x72\x3b",
+               .ilen   = 8,
+               .result = "\x8b\x02\x4e\x45\x48\xa5\x6f\x8c",
+               .rlen   = 8,
+       },
+};
+
+static struct cipher_testvec speck64_dec_tv_template[] = {
+       { /* Speck64/96 */
+               .key    = "\x00\x01\x02\x03\x08\x09\x0a\x0b"
+                         "\x10\x11\x12\x13",
+               .klen   = 12,
+               .input  = "\x6c\x94\x75\x41\xec\x52\x79\x9f",
+               .ilen   = 8,
+               .result = "\x65\x61\x6e\x73\x20\x46\x61\x74",
+               .rlen   = 8,
+       }, { /* Speck64/128 */
+               .key    = "\x00\x01\x02\x03\x08\x09\x0a\x0b"
+                         "\x10\x11\x12\x13\x18\x19\x1a\x1b",
+               .klen   = 16,
+               .input  = "\x8b\x02\x4e\x45\x48\xa5\x6f\x8c",
+               .ilen   = 8,
+               .result = "\x2d\x43\x75\x74\x74\x65\x72\x3b",
+               .rlen   = 8,
+       },
+};
+
+/*
+ * Speck64-XTS test vectors, taken from the AES-XTS test vectors with the result
+ * recomputed with Speck64 as the cipher, and key lengths adjusted
+ */
+
+static struct cipher_testvec speck64_xts_enc_tv_template[] = {
+       {
+               .key    = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .klen   = 24,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .ilen   = 32,
+               .result = "\x84\xaf\x54\x07\x19\xd4\x7c\xa6"
+                         "\xe4\xfe\xdf\xc4\x1f\x34\xc3\xc2"
+                         "\x80\xf5\x72\xe7\xcd\xf0\x99\x22"
+                         "\x35\xa7\x2f\x06\xef\xdc\x51\xaa",
+               .rlen   = 32,
+       }, {
+               .key    = "\x11\x11\x11\x11\x11\x11\x11\x11"
+                         "\x11\x11\x11\x11\x11\x11\x11\x11"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22",
+               .klen   = 24,
+               .iv     = "\x33\x33\x33\x33\x33\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44",
+               .ilen   = 32,
+               .result = "\x12\x56\x73\xcd\x15\x87\xa8\x59"
+                         "\xcf\x84\xae\xd9\x1c\x66\xd6\x9f"
+                         "\xb3\x12\x69\x7e\x36\xeb\x52\xff"
+                         "\x62\xdd\xba\x90\xb3\xe1\xee\x99",
+               .rlen   = 32,
+       }, {
+               .key    = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8"
+                         "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22",
+               .klen   = 24,
+               .iv     = "\x33\x33\x33\x33\x33\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44",
+               .ilen   = 32,
+               .result = "\x15\x1b\xe4\x2c\xa2\x5a\x2d\x2c"
+                         "\x27\x36\xc0\xbf\x5d\xea\x36\x37"
+                         "\x2d\x1a\x88\xbc\x66\xb5\xd0\x0b"
+                         "\xa1\xbc\x19\xb2\x0f\x3b\x75\x34",
+               .rlen   = 32,
+       }, {
+               .key    = "\x27\x18\x28\x18\x28\x45\x90\x45"
+                         "\x23\x53\x60\x28\x74\x71\x35\x26"
+                         "\x31\x41\x59\x26\x53\x58\x97\x93",
+               .klen   = 24,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+                         "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+               .ilen   = 512,
+               .result = "\xaf\xa1\x81\xa6\x32\xbb\x15\x8e"
+                         "\xf8\x95\x2e\xd3\xe6\xee\x7e\x09"
+                         "\x0c\x1a\xf5\x02\x97\x8b\xe3\xb3"
+                         "\x11\xc7\x39\x96\xd0\x95\xf4\x56"
+                         "\xf4\xdd\x03\x38\x01\x44\x2c\xcf"
+                         "\x88\xae\x8e\x3c\xcd\xe7\xaa\x66"
+                         "\xfe\x3d\xc6\xfb\x01\x23\x51\x43"
+                         "\xd5\xd2\x13\x86\x94\x34\xe9\x62"
+                         "\xf9\x89\xe3\xd1\x7b\xbe\xf8\xef"
+                         "\x76\x35\x04\x3f\xdb\x23\x9d\x0b"
+                         "\x85\x42\xb9\x02\xd6\xcc\xdb\x96"
+                         "\xa7\x6b\x27\xb6\xd4\x45\x8f\x7d"
+                         "\xae\xd2\x04\xd5\xda\xc1\x7e\x24"
+                         "\x8c\x73\xbe\x48\x7e\xcf\x65\x28"
+                         "\x29\xe5\xbe\x54\x30\xcb\x46\x95"
+                         "\x4f\x2e\x8a\x36\xc8\x27\xc5\xbe"
+                         "\xd0\x1a\xaf\xab\x26\xcd\x9e\x69"
+                         "\xa1\x09\x95\x71\x26\xe9\xc4\xdf"
+                         "\xe6\x31\xc3\x46\xda\xaf\x0b\x41"
+                         "\x1f\xab\xb1\x8e\xd6\xfc\x0b\xb3"
+                         "\x82\xc0\x37\x27\xfc\x91\xa7\x05"
+                         "\xfb\xc5\xdc\x2b\x74\x96\x48\x43"
+                         "\x5d\x9c\x19\x0f\x60\x63\x3a\x1f"
+                         "\x6f\xf0\x03\xbe\x4d\xfd\xc8\x4a"
+                         "\xc6\xa4\x81\x6d\xc3\x12\x2a\x5c"
+                         "\x07\xff\xf3\x72\x74\x48\xb5\x40"
+                         "\x50\xb5\xdd\x90\x43\x31\x18\x15"
+                         "\x7b\xf2\xa6\xdb\x83\xc8\x4b\x4a"
+                         "\x29\x93\x90\x8b\xda\x07\xf0\x35"
+                         "\x6d\x90\x88\x09\x4e\x83\xf5\x5b"
+                         "\x94\x12\xbb\x33\x27\x1d\x3f\x23"
+                         "\x51\xa8\x7c\x07\xa2\xae\x77\xa6"
+                         "\x50\xfd\xcc\xc0\x4f\x80\x7a\x9f"
+                         "\x66\xdd\xcd\x75\x24\x8b\x33\xf7"
+                         "\x20\xdb\x83\x9b\x4f\x11\x63\x6e"
+                         "\xcf\x37\xef\xc9\x11\x01\x5c\x45"
+                         "\x32\x99\x7c\x3c\x9e\x42\x89\xe3"
+                         "\x70\x6d\x15\x9f\xb1\xe6\xb6\x05"
+                         "\xfe\x0c\xb9\x49\x2d\x90\x6d\xcc"
+                         "\x5d\x3f\xc1\xfe\x89\x0a\x2e\x2d"
+                         "\xa0\xa8\x89\x3b\x73\x39\xa5\x94"
+                         "\x4c\xa4\xa6\xbb\xa7\x14\x46\x89"
+                         "\x10\xff\xaf\xef\xca\xdd\x4f\x80"
+                         "\xb3\xdf\x3b\xab\xd4\xe5\x5a\xc7"
+                         "\x33\xca\x00\x8b\x8b\x3f\xea\xec"
+                         "\x68\x8a\xc2\x6d\xfd\xd4\x67\x0f"
+                         "\x22\x31\xe1\x0e\xfe\x5a\x04\xd5"
+                         "\x64\xa3\xf1\x1a\x76\x28\xcc\x35"
+                         "\x36\xa7\x0a\x74\xf7\x1c\x44\x9b"
+                         "\xc7\x1b\x53\x17\x02\xea\xd1\xad"
+                         "\x13\x51\x73\xc0\xa0\xb2\x05\x32"
+                         "\xa8\xa2\x37\x2e\xe1\x7a\x3a\x19"
+                         "\x26\xb4\x6c\x62\x5d\xb3\x1a\x1d"
+                         "\x59\xda\xee\x1a\x22\x18\xda\x0d"
+                         "\x88\x0f\x55\x8b\x72\x62\xfd\xc1"
+                         "\x69\x13\xcd\x0d\x5f\xc1\x09\x52"
+                         "\xee\xd6\xe3\x84\x4d\xee\xf6\x88"
+                         "\xaf\x83\xdc\x76\xf4\xc0\x93\x3f"
+                         "\x4a\x75\x2f\xb0\x0b\x3e\xc4\x54"
+                         "\x7d\x69\x8d\x00\x62\x77\x0d\x14"
+                         "\xbe\x7c\xa6\x7d\xc5\x24\x4f\xf3"
+                         "\x50\xf7\x5f\xf4\xc2\xca\x41\x97"
+                         "\x37\xbe\x75\x74\xcd\xf0\x75\x6e"
+                         "\x25\x23\x94\xbd\xda\x8d\xb0\xd4",
+               .rlen   = 512,
+       }, {
+               .key    = "\x27\x18\x28\x18\x28\x45\x90\x45"
+                         "\x23\x53\x60\x28\x74\x71\x35\x26"
+                         "\x62\x49\x77\x57\x24\x70\x93\x69"
+                         "\x99\x59\x57\x49\x66\x96\x76\x27",
+               .klen   = 32,
+               .iv     = "\xff\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+                         "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+               .ilen   = 512,
+               .result = "\x55\xed\x71\xd3\x02\x8e\x15\x3b"
+                         "\xc6\x71\x29\x2d\x3e\x89\x9f\x59"
+                         "\x68\x6a\xcc\x8a\x56\x97\xf3\x95"
+                         "\x4e\x51\x08\xda\x2a\xf8\x6f\x3c"
+                         "\x78\x16\xea\x80\xdb\x33\x75\x94"
+                         "\xf9\x29\xc4\x2b\x76\x75\x97\xc7"
+                         "\xf2\x98\x2c\xf9\xff\xc8\xd5\x2b"
+                         "\x18\xf1\xaf\xcf\x7c\xc5\x0b\xee"
+                         "\xad\x3c\x76\x7c\xe6\x27\xa2\x2a"
+                         "\xe4\x66\xe1\xab\xa2\x39\xfc\x7c"
+                         "\xf5\xec\x32\x74\xa3\xb8\x03\x88"
+                         "\x52\xfc\x2e\x56\x3f\xa1\xf0\x9f"
+                         "\x84\x5e\x46\xed\x20\x89\xb6\x44"
+                         "\x8d\xd0\xed\x54\x47\x16\xbe\x95"
+                         "\x8a\xb3\x6b\x72\xc4\x32\x52\x13"
+                         "\x1b\xb0\x82\xbe\xac\xf9\x70\xa6"
+                         "\x44\x18\xdd\x8c\x6e\xca\x6e\x45"
+                         "\x8f\x1e\x10\x07\x57\x25\x98\x7b"
+                         "\x17\x8c\x78\xdd\x80\xa7\xd9\xd8"
+                         "\x63\xaf\xb9\x67\x57\xfd\xbc\xdb"
+                         "\x44\xe9\xc5\x65\xd1\xc7\x3b\xff"
+                         "\x20\xa0\x80\x1a\xc3\x9a\xad\x5e"
+                         "\x5d\x3b\xd3\x07\xd9\xf5\xfd\x3d"
+                         "\x4a\x8b\xa8\xd2\x6e\x7a\x51\x65"
+                         "\x6c\x8e\x95\xe0\x45\xc9\x5f\x4a"
+                         "\x09\x3c\x3d\x71\x7f\x0c\x84\x2a"
+                         "\xc8\x48\x52\x1a\xc2\xd5\xd6\x78"
+                         "\x92\x1e\xa0\x90\x2e\xea\xf0\xf3"
+                         "\xdc\x0f\xb1\xaf\x0d\x9b\x06\x2e"
+                         "\x35\x10\x30\x82\x0d\xe7\xc5\x9b"
+                         "\xde\x44\x18\xbd\x9f\xd1\x45\xa9"
+                         "\x7b\x7a\x4a\xad\x35\x65\x27\xca"
+                         "\xb2\xc3\xd4\x9b\x71\x86\x70\xee"
+                         "\xf1\x89\x3b\x85\x4b\x5b\xaa\xaf"
+                         "\xfc\x42\xc8\x31\x59\xbe\x16\x60"
+                         "\x4f\xf9\xfa\x12\xea\xd0\xa7\x14"
+                         "\xf0\x7a\xf3\xd5\x8d\xbd\x81\xef"
+                         "\x52\x7f\x29\x51\x94\x20\x67\x3c"
+                         "\xd1\xaf\x77\x9f\x22\x5a\x4e\x63"
+                         "\xe7\xff\x73\x25\xd1\xdd\x96\x8a"
+                         "\x98\x52\x6d\xf3\xac\x3e\xf2\x18"
+                         "\x6d\xf6\x0a\x29\xa6\x34\x3d\xed"
+                         "\xe3\x27\x0d\x9d\x0a\x02\x44\x7e"
+                         "\x5a\x7e\x67\x0f\x0a\x9e\xd6\xad"
+                         "\x91\xe6\x4d\x81\x8c\x5c\x59\xaa"
+                         "\xfb\xeb\x56\x53\xd2\x7d\x4c\x81"
+                         "\x65\x53\x0f\x41\x11\xbd\x98\x99"
+                         "\xf9\xc6\xfa\x51\x2e\xa3\xdd\x8d"
+                         "\x84\x98\xf9\x34\xed\x33\x2a\x1f"
+                         "\x82\xed\xc1\x73\x98\xd3\x02\xdc"
+                         "\xe6\xc2\x33\x1d\xa2\xb4\xca\x76"
+                         "\x63\x51\x34\x9d\x96\x12\xae\xce"
+                         "\x83\xc9\x76\x5e\xa4\x1b\x53\x37"
+                         "\x17\xd5\xc0\x80\x1d\x62\xf8\x3d"
+                         "\x54\x27\x74\xbb\x10\x86\x57\x46"
+                         "\x68\xe1\xed\x14\xe7\x9d\xfc\x84"
+                         "\x47\xbc\xc2\xf8\x19\x4b\x99\xcf"
+                         "\x7a\xe9\xc4\xb8\x8c\x82\x72\x4d"
+                         "\x7b\x4f\x38\x55\x36\x71\x64\xc1"
+                         "\xfc\x5c\x75\x52\x33\x02\x18\xf8"
+                         "\x17\xe1\x2b\xc2\x43\x39\xbd\x76"
+                         "\x9b\x63\x76\x32\x2f\x19\x72\x10"
+                         "\x9f\x21\x0c\xf1\x66\x50\x7f\xa5"
+                         "\x0d\x1f\x46\xe0\xba\xd3\x2f\x3c",
+               .rlen   = 512,
+               .also_non_np = 1,
+               .np     = 3,
+               .tap    = { 512 - 20, 4, 16 },
+       }
+};
+
+static struct cipher_testvec speck64_xts_dec_tv_template[] = {
+       {
+               .key    = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .klen   = 24,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x84\xaf\x54\x07\x19\xd4\x7c\xa6"
+                         "\xe4\xfe\xdf\xc4\x1f\x34\xc3\xc2"
+                         "\x80\xf5\x72\xe7\xcd\xf0\x99\x22"
+                         "\x35\xa7\x2f\x06\xef\xdc\x51\xaa",
+               .ilen   = 32,
+               .result = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .rlen   = 32,
+       }, {
+               .key    = "\x11\x11\x11\x11\x11\x11\x11\x11"
+                         "\x11\x11\x11\x11\x11\x11\x11\x11"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22",
+               .klen   = 24,
+               .iv     = "\x33\x33\x33\x33\x33\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x12\x56\x73\xcd\x15\x87\xa8\x59"
+                         "\xcf\x84\xae\xd9\x1c\x66\xd6\x9f"
+                         "\xb3\x12\x69\x7e\x36\xeb\x52\xff"
+                         "\x62\xdd\xba\x90\xb3\xe1\xee\x99",
+               .ilen   = 32,
+               .result = "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44",
+               .rlen   = 32,
+       }, {
+               .key    = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8"
+                         "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22",
+               .klen   = 24,
+               .iv     = "\x33\x33\x33\x33\x33\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x15\x1b\xe4\x2c\xa2\x5a\x2d\x2c"
+                         "\x27\x36\xc0\xbf\x5d\xea\x36\x37"
+                         "\x2d\x1a\x88\xbc\x66\xb5\xd0\x0b"
+                         "\xa1\xbc\x19\xb2\x0f\x3b\x75\x34",
+               .ilen   = 32,
+               .result = "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44",
+               .rlen   = 32,
+       }, {
+               .key    = "\x27\x18\x28\x18\x28\x45\x90\x45"
+                         "\x23\x53\x60\x28\x74\x71\x35\x26"
+                         "\x31\x41\x59\x26\x53\x58\x97\x93",
+               .klen   = 24,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\xaf\xa1\x81\xa6\x32\xbb\x15\x8e"
+                         "\xf8\x95\x2e\xd3\xe6\xee\x7e\x09"
+                         "\x0c\x1a\xf5\x02\x97\x8b\xe3\xb3"
+                         "\x11\xc7\x39\x96\xd0\x95\xf4\x56"
+                         "\xf4\xdd\x03\x38\x01\x44\x2c\xcf"
+                         "\x88\xae\x8e\x3c\xcd\xe7\xaa\x66"
+                         "\xfe\x3d\xc6\xfb\x01\x23\x51\x43"
+                         "\xd5\xd2\x13\x86\x94\x34\xe9\x62"
+                         "\xf9\x89\xe3\xd1\x7b\xbe\xf8\xef"
+                         "\x76\x35\x04\x3f\xdb\x23\x9d\x0b"
+                         "\x85\x42\xb9\x02\xd6\xcc\xdb\x96"
+                         "\xa7\x6b\x27\xb6\xd4\x45\x8f\x7d"
+                         "\xae\xd2\x04\xd5\xda\xc1\x7e\x24"
+                         "\x8c\x73\xbe\x48\x7e\xcf\x65\x28"
+                         "\x29\xe5\xbe\x54\x30\xcb\x46\x95"
+                         "\x4f\x2e\x8a\x36\xc8\x27\xc5\xbe"
+                         "\xd0\x1a\xaf\xab\x26\xcd\x9e\x69"
+                         "\xa1\x09\x95\x71\x26\xe9\xc4\xdf"
+                         "\xe6\x31\xc3\x46\xda\xaf\x0b\x41"
+                         "\x1f\xab\xb1\x8e\xd6\xfc\x0b\xb3"
+                         "\x82\xc0\x37\x27\xfc\x91\xa7\x05"
+                         "\xfb\xc5\xdc\x2b\x74\x96\x48\x43"
+                         "\x5d\x9c\x19\x0f\x60\x63\x3a\x1f"
+                         "\x6f\xf0\x03\xbe\x4d\xfd\xc8\x4a"
+                         "\xc6\xa4\x81\x6d\xc3\x12\x2a\x5c"
+                         "\x07\xff\xf3\x72\x74\x48\xb5\x40"
+                         "\x50\xb5\xdd\x90\x43\x31\x18\x15"
+                         "\x7b\xf2\xa6\xdb\x83\xc8\x4b\x4a"
+                         "\x29\x93\x90\x8b\xda\x07\xf0\x35"
+                         "\x6d\x90\x88\x09\x4e\x83\xf5\x5b"
+                         "\x94\x12\xbb\x33\x27\x1d\x3f\x23"
+                         "\x51\xa8\x7c\x07\xa2\xae\x77\xa6"
+                         "\x50\xfd\xcc\xc0\x4f\x80\x7a\x9f"
+                         "\x66\xdd\xcd\x75\x24\x8b\x33\xf7"
+                         "\x20\xdb\x83\x9b\x4f\x11\x63\x6e"
+                         "\xcf\x37\xef\xc9\x11\x01\x5c\x45"
+                         "\x32\x99\x7c\x3c\x9e\x42\x89\xe3"
+                         "\x70\x6d\x15\x9f\xb1\xe6\xb6\x05"
+                         "\xfe\x0c\xb9\x49\x2d\x90\x6d\xcc"
+                         "\x5d\x3f\xc1\xfe\x89\x0a\x2e\x2d"
+                         "\xa0\xa8\x89\x3b\x73\x39\xa5\x94"
+                         "\x4c\xa4\xa6\xbb\xa7\x14\x46\x89"
+                         "\x10\xff\xaf\xef\xca\xdd\x4f\x80"
+                         "\xb3\xdf\x3b\xab\xd4\xe5\x5a\xc7"
+                         "\x33\xca\x00\x8b\x8b\x3f\xea\xec"
+                         "\x68\x8a\xc2\x6d\xfd\xd4\x67\x0f"
+                         "\x22\x31\xe1\x0e\xfe\x5a\x04\xd5"
+                         "\x64\xa3\xf1\x1a\x76\x28\xcc\x35"
+                         "\x36\xa7\x0a\x74\xf7\x1c\x44\x9b"
+                         "\xc7\x1b\x53\x17\x02\xea\xd1\xad"
+                         "\x13\x51\x73\xc0\xa0\xb2\x05\x32"
+                         "\xa8\xa2\x37\x2e\xe1\x7a\x3a\x19"
+                         "\x26\xb4\x6c\x62\x5d\xb3\x1a\x1d"
+                         "\x59\xda\xee\x1a\x22\x18\xda\x0d"
+                         "\x88\x0f\x55\x8b\x72\x62\xfd\xc1"
+                         "\x69\x13\xcd\x0d\x5f\xc1\x09\x52"
+                         "\xee\xd6\xe3\x84\x4d\xee\xf6\x88"
+                         "\xaf\x83\xdc\x76\xf4\xc0\x93\x3f"
+                         "\x4a\x75\x2f\xb0\x0b\x3e\xc4\x54"
+                         "\x7d\x69\x8d\x00\x62\x77\x0d\x14"
+                         "\xbe\x7c\xa6\x7d\xc5\x24\x4f\xf3"
+                         "\x50\xf7\x5f\xf4\xc2\xca\x41\x97"
+                         "\x37\xbe\x75\x74\xcd\xf0\x75\x6e"
+                         "\x25\x23\x94\xbd\xda\x8d\xb0\xd4",
+               .ilen   = 512,
+               .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+                         "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+               .rlen   = 512,
+       }, {
+               .key    = "\x27\x18\x28\x18\x28\x45\x90\x45"
+                         "\x23\x53\x60\x28\x74\x71\x35\x26"
+                         "\x62\x49\x77\x57\x24\x70\x93\x69"
+                         "\x99\x59\x57\x49\x66\x96\x76\x27",
+               .klen   = 32,
+               .iv     = "\xff\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x55\xed\x71\xd3\x02\x8e\x15\x3b"
+                         "\xc6\x71\x29\x2d\x3e\x89\x9f\x59"
+                         "\x68\x6a\xcc\x8a\x56\x97\xf3\x95"
+                         "\x4e\x51\x08\xda\x2a\xf8\x6f\x3c"
+                         "\x78\x16\xea\x80\xdb\x33\x75\x94"
+                         "\xf9\x29\xc4\x2b\x76\x75\x97\xc7"
+                         "\xf2\x98\x2c\xf9\xff\xc8\xd5\x2b"
+                         "\x18\xf1\xaf\xcf\x7c\xc5\x0b\xee"
+                         "\xad\x3c\x76\x7c\xe6\x27\xa2\x2a"
+                         "\xe4\x66\xe1\xab\xa2\x39\xfc\x7c"
+                         "\xf5\xec\x32\x74\xa3\xb8\x03\x88"
+                         "\x52\xfc\x2e\x56\x3f\xa1\xf0\x9f"
+                         "\x84\x5e\x46\xed\x20\x89\xb6\x44"
+                         "\x8d\xd0\xed\x54\x47\x16\xbe\x95"
+                         "\x8a\xb3\x6b\x72\xc4\x32\x52\x13"
+                         "\x1b\xb0\x82\xbe\xac\xf9\x70\xa6"
+                         "\x44\x18\xdd\x8c\x6e\xca\x6e\x45"
+                         "\x8f\x1e\x10\x07\x57\x25\x98\x7b"
+                         "\x17\x8c\x78\xdd\x80\xa7\xd9\xd8"
+                         "\x63\xaf\xb9\x67\x57\xfd\xbc\xdb"
+                         "\x44\xe9\xc5\x65\xd1\xc7\x3b\xff"
+                         "\x20\xa0\x80\x1a\xc3\x9a\xad\x5e"
+                         "\x5d\x3b\xd3\x07\xd9\xf5\xfd\x3d"
+                         "\x4a\x8b\xa8\xd2\x6e\x7a\x51\x65"
+                         "\x6c\x8e\x95\xe0\x45\xc9\x5f\x4a"
+                         "\x09\x3c\x3d\x71\x7f\x0c\x84\x2a"
+                         "\xc8\x48\x52\x1a\xc2\xd5\xd6\x78"
+                         "\x92\x1e\xa0\x90\x2e\xea\xf0\xf3"
+                         "\xdc\x0f\xb1\xaf\x0d\x9b\x06\x2e"
+                         "\x35\x10\x30\x82\x0d\xe7\xc5\x9b"
+                         "\xde\x44\x18\xbd\x9f\xd1\x45\xa9"
+                         "\x7b\x7a\x4a\xad\x35\x65\x27\xca"
+                         "\xb2\xc3\xd4\x9b\x71\x86\x70\xee"
+                         "\xf1\x89\x3b\x85\x4b\x5b\xaa\xaf"
+                         "\xfc\x42\xc8\x31\x59\xbe\x16\x60"
+                         "\x4f\xf9\xfa\x12\xea\xd0\xa7\x14"
+                         "\xf0\x7a\xf3\xd5\x8d\xbd\x81\xef"
+                         "\x52\x7f\x29\x51\x94\x20\x67\x3c"
+                         "\xd1\xaf\x77\x9f\x22\x5a\x4e\x63"
+                         "\xe7\xff\x73\x25\xd1\xdd\x96\x8a"
+                         "\x98\x52\x6d\xf3\xac\x3e\xf2\x18"
+                         "\x6d\xf6\x0a\x29\xa6\x34\x3d\xed"
+                         "\xe3\x27\x0d\x9d\x0a\x02\x44\x7e"
+                         "\x5a\x7e\x67\x0f\x0a\x9e\xd6\xad"
+                         "\x91\xe6\x4d\x81\x8c\x5c\x59\xaa"
+                         "\xfb\xeb\x56\x53\xd2\x7d\x4c\x81"
+                         "\x65\x53\x0f\x41\x11\xbd\x98\x99"
+                         "\xf9\xc6\xfa\x51\x2e\xa3\xdd\x8d"
+                         "\x84\x98\xf9\x34\xed\x33\x2a\x1f"
+                         "\x82\xed\xc1\x73\x98\xd3\x02\xdc"
+                         "\xe6\xc2\x33\x1d\xa2\xb4\xca\x76"
+                         "\x63\x51\x34\x9d\x96\x12\xae\xce"
+                         "\x83\xc9\x76\x5e\xa4\x1b\x53\x37"
+                         "\x17\xd5\xc0\x80\x1d\x62\xf8\x3d"
+                         "\x54\x27\x74\xbb\x10\x86\x57\x46"
+                         "\x68\xe1\xed\x14\xe7\x9d\xfc\x84"
+                         "\x47\xbc\xc2\xf8\x19\x4b\x99\xcf"
+                         "\x7a\xe9\xc4\xb8\x8c\x82\x72\x4d"
+                         "\x7b\x4f\x38\x55\x36\x71\x64\xc1"
+                         "\xfc\x5c\x75\x52\x33\x02\x18\xf8"
+                         "\x17\xe1\x2b\xc2\x43\x39\xbd\x76"
+                         "\x9b\x63\x76\x32\x2f\x19\x72\x10"
+                         "\x9f\x21\x0c\xf1\x66\x50\x7f\xa5"
+                         "\x0d\x1f\x46\xe0\xba\xd3\x2f\x3c",
+               .ilen   = 512,
+               .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+                         "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+               .rlen   = 512,
+               .also_non_np = 1,
+               .np     = 3,
+               .tap    = { 512 - 20, 4, 16 },
+       }
+};
+
 /* Cast6 test vectors from RFC 2612 */
 #define CAST6_ENC_TEST_VECTORS         4
 #define CAST6_DEC_TEST_VECTORS         4
index d7c1d74..d563f5c 100644 (file)
@@ -97,6 +97,7 @@ obj-$(CONFIG_TC)              += tc/
 obj-$(CONFIG_UWB)              += uwb/
 obj-$(CONFIG_USB_PHY)          += usb/
 obj-$(CONFIG_USB)              += usb/
+obj-$(CONFIG_USB_SUPPORT)      += usb/
 obj-$(CONFIG_PCI)              += usb/
 obj-$(CONFIG_USB_GADGET)       += usb/
 obj-$(CONFIG_OF)               += usb/
index 2fa8304..7a34310 100644 (file)
@@ -275,8 +275,8 @@ static int acpi_smbus_hc_add(struct acpi_device *device)
        device->driver_data = hc;
 
        acpi_ec_add_query_handler(hc->ec, hc->query_bit, NULL, smbus_alarm, hc);
-       printk(KERN_INFO PREFIX "SBS HC: EC = 0x%p, offset = 0x%0x, query_bit = 0x%0x\n",
-               hc->ec, hc->offset, hc->query_bit);
+       dev_info(&device->dev, "SBS HC: offset = 0x%0x, query_bit = 0x%0x\n",
+                hc->offset, hc->query_bit);
 
        return 0;
 }
index 063e0df..9f62841 100644 (file)
@@ -4536,8 +4536,29 @@ static int binder_thread_release(struct binder_proc *proc,
                if (t)
                        spin_lock(&t->lock);
        }
+
+       /*
+        * If this thread used poll, make sure we remove the waitqueue
+        * from any epoll data structures holding it with POLLFREE.
+        * waitqueue_active() is safe to use here because we're holding
+        * the inner lock.
+        */
+       if ((thread->looper & BINDER_LOOPER_STATE_POLL) &&
+           waitqueue_active(&thread->wait)) {
+               wake_up_poll(&thread->wait, POLLHUP | POLLFREE);
+       }
+
        binder_inner_proc_unlock(thread->proc);
 
+       /*
+        * This is needed to avoid races between wake_up_poll() above and
+        * and ep_remove_waitqueue() called for other reasons (eg the epoll file
+        * descriptor being closed); ep_remove_waitqueue() holds an RCU read
+        * lock, so we can be sure it's done after calling synchronize_rcu().
+        */
+       if (thread->looper & BINDER_LOOPER_STATE_POLL)
+               synchronize_rcu();
+
        if (send_reply)
                binder_send_failed_reply(send_reply, BR_DEAD_REPLY);
        binder_release_work(proc, &thread->todo);
@@ -4553,6 +4574,8 @@ static unsigned int binder_poll(struct file *filp,
        bool wait_for_proc_work;
 
        thread = binder_get_thread(proc);
+       if (!thread)
+               return POLLERR;
 
        binder_inner_proc_lock(thread->proc);
        thread->looper |= BINDER_LOOPER_STATE_POLL;
index 60a1583..8ddf5d5 100644 (file)
@@ -260,9 +260,9 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, 0x3b23), board_ahci }, /* PCH AHCI */
        { PCI_VDEVICE(INTEL, 0x3b24), board_ahci }, /* PCH RAID */
        { PCI_VDEVICE(INTEL, 0x3b25), board_ahci }, /* PCH RAID */
-       { PCI_VDEVICE(INTEL, 0x3b29), board_ahci }, /* PCH AHCI */
+       { PCI_VDEVICE(INTEL, 0x3b29), board_ahci }, /* PCH AHCI */
        { PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
-       { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */
+       { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */
        { PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */
        { PCI_VDEVICE(INTEL, 0x19b0), board_ahci }, /* DNV AHCI */
        { PCI_VDEVICE(INTEL, 0x19b1), board_ahci }, /* DNV AHCI */
@@ -285,9 +285,9 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, 0x19cE), board_ahci }, /* DNV AHCI */
        { PCI_VDEVICE(INTEL, 0x19cF), board_ahci }, /* DNV AHCI */
        { PCI_VDEVICE(INTEL, 0x1c02), board_ahci }, /* CPT AHCI */
-       { PCI_VDEVICE(INTEL, 0x1c03), board_ahci }, /* CPT AHCI */
+       { PCI_VDEVICE(INTEL, 0x1c03), board_ahci }, /* CPT AHCI */
        { PCI_VDEVICE(INTEL, 0x1c04), board_ahci }, /* CPT RAID */
-       { PCI_VDEVICE(INTEL, 0x1c05), board_ahci }, /* CPT RAID */
+       { PCI_VDEVICE(INTEL, 0x1c05), board_ahci }, /* CPT RAID */
        { PCI_VDEVICE(INTEL, 0x1c06), board_ahci }, /* CPT RAID */
        { PCI_VDEVICE(INTEL, 0x1c07), board_ahci }, /* CPT RAID */
        { PCI_VDEVICE(INTEL, 0x1d02), board_ahci }, /* PBG AHCI */
@@ -296,20 +296,20 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* PBG RAID */
        { PCI_VDEVICE(INTEL, 0x2323), board_ahci }, /* DH89xxCC AHCI */
        { PCI_VDEVICE(INTEL, 0x1e02), board_ahci }, /* Panther Point AHCI */
-       { PCI_VDEVICE(INTEL, 0x1e03), board_ahci }, /* Panther Point AHCI */
+       { PCI_VDEVICE(INTEL, 0x1e03), board_ahci }, /* Panther Point AHCI */
        { PCI_VDEVICE(INTEL, 0x1e04), board_ahci }, /* Panther Point RAID */
        { PCI_VDEVICE(INTEL, 0x1e05), board_ahci }, /* Panther Point RAID */
        { PCI_VDEVICE(INTEL, 0x1e06), board_ahci }, /* Panther Point RAID */
-       { PCI_VDEVICE(INTEL, 0x1e07), board_ahci }, /* Panther Point RAID */
+       { PCI_VDEVICE(INTEL, 0x1e07), board_ahci }, /* Panther Point RAID */
        { PCI_VDEVICE(INTEL, 0x1e0e), board_ahci }, /* Panther Point RAID */
        { PCI_VDEVICE(INTEL, 0x8c02), board_ahci }, /* Lynx Point AHCI */
-       { PCI_VDEVICE(INTEL, 0x8c03), board_ahci }, /* Lynx Point AHCI */
+       { PCI_VDEVICE(INTEL, 0x8c03), board_ahci }, /* Lynx Point AHCI */
        { PCI_VDEVICE(INTEL, 0x8c04), board_ahci }, /* Lynx Point RAID */
-       { PCI_VDEVICE(INTEL, 0x8c05), board_ahci }, /* Lynx Point RAID */
+       { PCI_VDEVICE(INTEL, 0x8c05), board_ahci }, /* Lynx Point RAID */
        { PCI_VDEVICE(INTEL, 0x8c06), board_ahci }, /* Lynx Point RAID */
-       { PCI_VDEVICE(INTEL, 0x8c07), board_ahci }, /* Lynx Point RAID */
+       { PCI_VDEVICE(INTEL, 0x8c07), board_ahci }, /* Lynx Point RAID */
        { PCI_VDEVICE(INTEL, 0x8c0e), board_ahci }, /* Lynx Point RAID */
-       { PCI_VDEVICE(INTEL, 0x8c0f), board_ahci }, /* Lynx Point RAID */
+       { PCI_VDEVICE(INTEL, 0x8c0f), board_ahci }, /* Lynx Point RAID */
        { PCI_VDEVICE(INTEL, 0x9c02), board_ahci }, /* Lynx Point-LP AHCI */
        { PCI_VDEVICE(INTEL, 0x9c03), board_ahci }, /* Lynx Point-LP AHCI */
        { PCI_VDEVICE(INTEL, 0x9c04), board_ahci }, /* Lynx Point-LP RAID */
@@ -350,21 +350,21 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, 0x9c87), board_ahci }, /* Wildcat Point-LP RAID */
        { PCI_VDEVICE(INTEL, 0x9c8f), board_ahci }, /* Wildcat Point-LP RAID */
        { PCI_VDEVICE(INTEL, 0x8c82), board_ahci }, /* 9 Series AHCI */
-       { PCI_VDEVICE(INTEL, 0x8c83), board_ahci }, /* 9 Series AHCI */
+       { PCI_VDEVICE(INTEL, 0x8c83), board_ahci }, /* 9 Series AHCI */
        { PCI_VDEVICE(INTEL, 0x8c84), board_ahci }, /* 9 Series RAID */
-       { PCI_VDEVICE(INTEL, 0x8c85), board_ahci }, /* 9 Series RAID */
+       { PCI_VDEVICE(INTEL, 0x8c85), board_ahci }, /* 9 Series RAID */
        { PCI_VDEVICE(INTEL, 0x8c86), board_ahci }, /* 9 Series RAID */
-       { PCI_VDEVICE(INTEL, 0x8c87), board_ahci }, /* 9 Series RAID */
+       { PCI_VDEVICE(INTEL, 0x8c87), board_ahci }, /* 9 Series RAID */
        { PCI_VDEVICE(INTEL, 0x8c8e), board_ahci }, /* 9 Series RAID */
-       { PCI_VDEVICE(INTEL, 0x8c8f), board_ahci }, /* 9 Series RAID */
+       { PCI_VDEVICE(INTEL, 0x8c8f), board_ahci }, /* 9 Series RAID */
        { PCI_VDEVICE(INTEL, 0x9d03), board_ahci }, /* Sunrise Point-LP AHCI */
        { PCI_VDEVICE(INTEL, 0x9d05), board_ahci }, /* Sunrise Point-LP RAID */
        { PCI_VDEVICE(INTEL, 0x9d07), board_ahci }, /* Sunrise Point-LP RAID */
        { PCI_VDEVICE(INTEL, 0xa102), board_ahci }, /* Sunrise Point-H AHCI */
-       { PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H AHCI */
+       { PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H AHCI */
        { PCI_VDEVICE(INTEL, 0xa105), board_ahci }, /* Sunrise Point-H RAID */
        { PCI_VDEVICE(INTEL, 0xa106), board_ahci }, /* Sunrise Point-H RAID */
-       { PCI_VDEVICE(INTEL, 0xa107), board_ahci }, /* Sunrise Point-H RAID */
+       { PCI_VDEVICE(INTEL, 0xa107), board_ahci }, /* Sunrise Point-H RAID */
        { PCI_VDEVICE(INTEL, 0xa10f), board_ahci }, /* Sunrise Point-H RAID */
        { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* Lewisburg RAID*/
        { PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Lewisburg AHCI*/
@@ -382,6 +382,11 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, 0xa20e), board_ahci }, /* Lewisburg RAID*/
        { PCI_VDEVICE(INTEL, 0xa252), board_ahci }, /* Lewisburg RAID*/
        { PCI_VDEVICE(INTEL, 0xa256), board_ahci }, /* Lewisburg RAID*/
+       { PCI_VDEVICE(INTEL, 0xa356), board_ahci }, /* Cannon Lake PCH-H RAID */
+       { PCI_VDEVICE(INTEL, 0x0f22), board_ahci }, /* Bay Trail AHCI */
+       { PCI_VDEVICE(INTEL, 0x0f23), board_ahci }, /* Bay Trail AHCI */
+       { PCI_VDEVICE(INTEL, 0x22a3), board_ahci }, /* Cherry Trail AHCI */
+       { PCI_VDEVICE(INTEL, 0x5ae3), board_ahci }, /* Apollo Lake AHCI */
 
        /* JMicron 360/1/3/5/6, match class to avoid IDE function */
        { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
index f018318..440b52c 100644 (file)
@@ -2779,7 +2779,7 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
        pd->pkt_dev = MKDEV(pktdev_major, idx);
        ret = pkt_new_dev(pd, dev);
        if (ret)
-               goto out_new_dev;
+               goto out_mem2;
 
        /* inherit events of the host device */
        disk->events = pd->bdev->bd_disk->events;
@@ -2797,8 +2797,6 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
        mutex_unlock(&ctl_mutex);
        return 0;
 
-out_new_dev:
-       blk_cleanup_queue(disk->queue);
 out_mem2:
        put_disk(disk);
 out_mem:
index 7b62442..89ccb60 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/errno.h>
 #include <linux/skbuff.h>
 
+#include <linux/mmc/host.h>
 #include <linux/mmc/sdio_ids.h>
 #include <linux/mmc/sdio_func.h>
 
@@ -291,6 +292,14 @@ static int btsdio_probe(struct sdio_func *func,
                tuple = tuple->next;
        }
 
+       /* BCM43341 devices soldered onto the PCB (non-removable) use an
+        * uart connection for bluetooth, ignore the BT SDIO interface.
+        */
+       if (func->vendor == SDIO_VENDOR_ID_BROADCOM &&
+           func->device == SDIO_DEVICE_ID_BROADCOM_43341 &&
+           !mmc_card_is_removable(func->card->host))
+               return -ENODEV;
+
        data = devm_kzalloc(&func->dev, sizeof(*data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
index 1ccad79..54cef3d 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <linux/module.h>
 #include <linux/usb.h>
+#include <linux/usb/quirks.h>
 #include <linux/firmware.h>
 #include <asm/unaligned.h>
 
@@ -360,8 +361,8 @@ static const struct usb_device_id blacklist_table[] = {
 #define BTUSB_FIRMWARE_LOADED  7
 #define BTUSB_FIRMWARE_FAILED  8
 #define BTUSB_BOOTING          9
-#define BTUSB_RESET_RESUME     10
-#define BTUSB_DIAG_RUNNING     11
+#define BTUSB_DIAG_RUNNING     10
+#define BTUSB_OOB_WAKE_ENABLED 11
 
 struct btusb_data {
        struct hci_dev       *hdev;
@@ -2972,9 +2973,9 @@ static int btusb_probe(struct usb_interface *intf,
 
                /* QCA Rome devices lose their updated firmware over suspend,
                 * but the USB hub doesn't notice any status change.
-                * Explicitly request a device reset on resume.
+                * explicitly request a device reset on resume.
                 */
-               set_bit(BTUSB_RESET_RESUME, &data->flags);
+               interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME;
        }
 
 #ifdef CONFIG_BT_HCIBTUSB_RTL
@@ -2985,7 +2986,7 @@ static int btusb_probe(struct usb_interface *intf,
                 * but the USB hub doesn't notice any status change.
                 * Explicitly request a device reset on resume.
                 */
-               set_bit(BTUSB_RESET_RESUME, &data->flags);
+               interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME;
        }
 #endif
 
@@ -3142,14 +3143,6 @@ static int btusb_suspend(struct usb_interface *intf, pm_message_t message)
        btusb_stop_traffic(data);
        usb_kill_anchored_urbs(&data->tx_anchor);
 
-       /* Optionally request a device reset on resume, but only when
-        * wakeups are disabled. If wakeups are enabled we assume the
-        * device will stay powered up throughout suspend.
-        */
-       if (test_bit(BTUSB_RESET_RESUME, &data->flags) &&
-           !device_may_wakeup(&data->udev->dev))
-               data->udev->reset_resume = 1;
-
        return 0;
 }
 
index 7845a38..7ba0ae0 100644 (file)
@@ -155,8 +155,7 @@ static int exynos_rng_probe(struct platform_device *pdev)
        return ret;
 }
 
-#ifdef CONFIG_PM
-static int exynos_rng_runtime_suspend(struct device *dev)
+static int __maybe_unused exynos_rng_runtime_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct exynos_rng *exynos_rng = platform_get_drvdata(pdev);
@@ -166,7 +165,7 @@ static int exynos_rng_runtime_suspend(struct device *dev)
        return 0;
 }
 
-static int exynos_rng_runtime_resume(struct device *dev)
+static int __maybe_unused exynos_rng_runtime_resume(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct exynos_rng *exynos_rng = platform_get_drvdata(pdev);
@@ -174,12 +173,12 @@ static int exynos_rng_runtime_resume(struct device *dev)
        return clk_prepare_enable(exynos_rng->clk);
 }
 
-static int exynos_rng_suspend(struct device *dev)
+static int __maybe_unused exynos_rng_suspend(struct device *dev)
 {
        return pm_runtime_force_suspend(dev);
 }
 
-static int exynos_rng_resume(struct device *dev)
+static int __maybe_unused exynos_rng_resume(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct exynos_rng *exynos_rng = platform_get_drvdata(pdev);
@@ -191,7 +190,6 @@ static int exynos_rng_resume(struct device *dev)
 
        return exynos_rng_configure(exynos_rng);
 }
-#endif
 
 static const struct dev_pm_ops exynos_rng_pm_ops = {
        SET_SYSTEM_SLEEP_PM_OPS(exynos_rng_suspend, exynos_rng_resume)
index e874fcc..e3a0181 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011,2013-2014 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011,2013-2014,2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
 #include <linux/platform_device.h>
 #include <linux/of.h>
 #include <soc/qcom/msm-clock-controller.h>
+#include <linux/reset-controller.h>
+
+#define DUMMY_RESET_NR 20
+
+static int dummy_reset_assert(struct reset_controller_dev *rcdev,
+                               unsigned long id)
+{
+       return 0;
+}
+
+static int dummy_reset_deassert(struct reset_controller_dev *rcdev,
+                               unsigned long id)
+{
+       return 0;
+}
+
+static int dummy_reset(struct reset_controller_dev *rcdev, unsigned long id)
+{
+       return 0;
+}
+
+static struct reset_control_ops dummy_reset_ops = {
+       .reset = dummy_reset,
+       .assert = dummy_reset_assert,
+       .deassert = dummy_reset_deassert,
+};
+
+static int dummy_reset_controller_register(struct platform_device *pdev)
+{
+       struct reset_controller_dev *prcdev;
+       int ret = 0;
+
+       prcdev = devm_kzalloc(&pdev->dev, sizeof(*prcdev), GFP_KERNEL);
+       if (!prcdev)
+               return -ENOMEM;
+
+       prcdev->of_node = pdev->dev.of_node;
+       prcdev->ops = &dummy_reset_ops;
+       prcdev->owner = pdev->dev.driver->owner;
+       prcdev->nr_resets = DUMMY_RESET_NR;
+
+       ret = reset_controller_register(prcdev);
+       if (ret)
+               dev_err(&pdev->dev, "Failed to register reset controller\n");
+
+       return ret;
+}
 
 static int dummy_clk_reset(struct clk *clk, enum clk_reset_action action)
 {
@@ -99,7 +146,11 @@ static int msm_clock_dummy_probe(struct platform_device *pdev)
 
        ret = of_clk_add_provider(pdev->dev.of_node, of_dummy_get, NULL);
        if (ret)
-               return -ENOMEM;
+               return ret;
+
+       ret = dummy_reset_controller_register(pdev);
+       if (ret)
+               return ret;
 
        dev_info(&pdev->dev, "Registered DUMMY provider.\n");
        return ret;
index 5f779ec..e37face 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2016, 2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -403,8 +403,8 @@ static void mdss_dsi_pll_8996_input_init(struct mdss_pll_resources *pll,
        pdb->in.pll_ip_trim = 4;        /* 4, reg: 0x0404 */
        pdb->in.pll_cpcset_cur = 1;     /* 1, reg: 0x04f0, bit 0 - 2 */
        pdb->in.pll_cpmset_cur = 1;     /* 1, reg: 0x04f0, bit 3 - 5 */
-       pdb->in.pll_icpmset = 4;        /* 4, reg: 0x04fc, bit 3 - 5 */
-       pdb->in.pll_icpcset = 4;        /* 4, reg: 0x04fc, bit 0 - 2 */
+       pdb->in.pll_icpmset = 7;        /* 7, reg: 0x04fc, bit 3 - 5 */
+       pdb->in.pll_icpcset = 7;        /* 7, reg: 0x04fc, bit 0 - 2 */
        pdb->in.pll_icpmset_p = 0;      /* 0, reg: 0x04f4, bit 0 - 2 */
        pdb->in.pll_icpmset_m = 0;      /* 0, reg: 0x04f4, bit 3 - 5 */
        pdb->in.pll_icpcset_p = 0;      /* 0, reg: 0x04f8, bit 0 - 2 */
index 542737e..05606f1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -2419,7 +2419,7 @@ static struct clk_regmap_div mmss_mdss_byte0_intf_div_clk = {
                        },
                        .num_parents = 1,
                        .ops = &clk_regmap_div_ops,
-                       .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
+                       .flags = CLK_GET_RATE_NOCACHE,
                },
        },
 };
@@ -2476,7 +2476,7 @@ static struct clk_regmap_div mmss_mdss_byte1_intf_div_clk = {
                        },
                        .num_parents = 1,
                        .ops = &clk_regmap_div_ops,
-                       .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
+                       .flags = CLK_GET_RATE_NOCACHE,
                },
        },
 };
index 53e6145..ee87eb7 100644 (file)
@@ -224,12 +224,16 @@ static int instantiate_rng(struct device *ctrldev, int state_handle_mask,
                 * without any error (HW optimizations for later
                 * CAAM eras), then try again.
                 */
+               if (ret)
+                       break;
+
                rdsta_val = rd_reg32(&ctrl->r4tst[0].rdsta) & RDSTA_IFMASK;
                if ((status && status != JRSTA_SSRC_JUMP_HALT_CC) ||
-                   !(rdsta_val & (1 << sh_idx)))
+                   !(rdsta_val & (1 << sh_idx))) {
                        ret = -EAGAIN;
-               if (ret)
                        break;
+               }
+
                dev_info(ctrldev, "Instantiated RNG4 SH%d\n", sh_idx);
                /* Clear the contents before recreating the descriptor */
                memset(desc, 0x00, CAAM_CMD_SZ * 7);
index fd39893..45ea895 100644 (file)
@@ -401,16 +401,21 @@ static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode)
        uint32_t                    aes_control;
        int                         err;
        unsigned long               flags;
+       u8 *iv;
 
        aes_control = SSS_AES_KEY_CHANGE_MODE;
        if (mode & FLAGS_AES_DECRYPT)
                aes_control |= SSS_AES_MODE_DECRYPT;
 
-       if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CBC)
+       if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CBC) {
                aes_control |= SSS_AES_CHAIN_MODE_CBC;
-       else if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CTR)
+               iv = req->info;
+       } else if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CTR) {
                aes_control |= SSS_AES_CHAIN_MODE_CTR;
-
+               iv = req->info;
+       } else {
+               iv = NULL; /* AES_ECB */
+       }
        if (dev->ctx->keylen == AES_KEYSIZE_192)
                aes_control |= SSS_AES_KEY_SIZE_192;
        else if (dev->ctx->keylen == AES_KEYSIZE_256)
@@ -440,7 +445,7 @@ static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode)
                goto outdata_error;
 
        SSS_AES_WRITE(dev, AES_CONTROL, aes_control);
-       s5p_set_aes(dev, dev->ctx->aes_key, req->info, dev->ctx->keylen);
+       s5p_set_aes(dev, dev->ctx->aes_key, iv, dev->ctx->keylen);
 
        s5p_set_dma_indata(dev,  req->src);
        s5p_set_dma_outdata(dev, req->dst);
index 844a8ad..64e86ad 100644 (file)
@@ -607,7 +607,7 @@ struct devfreq *devm_devfreq_add_device(struct device *dev,
        devfreq = devfreq_add_device(dev, profile, governor_name, data);
        if (IS_ERR(devfreq)) {
                devres_free(ptr);
-               return ERR_PTR(-ENOMEM);
+               return devfreq;
        }
 
        *ptr = devfreq;
index 53d22eb..be26f62 100644 (file)
@@ -716,7 +716,7 @@ atc_prep_dma_interleaved(struct dma_chan *chan,
                         unsigned long flags)
 {
        struct at_dma_chan      *atchan = to_at_dma_chan(chan);
-       struct data_chunk       *first = xt->sgl;
+       struct data_chunk       *first;
        struct at_desc          *desc = NULL;
        size_t                  xfer_count;
        unsigned int            dwidth;
@@ -728,6 +728,8 @@ atc_prep_dma_interleaved(struct dma_chan *chan,
        if (unlikely(!xt || xt->numf != 1 || !xt->frame_size))
                return NULL;
 
+       first = xt->sgl;
+
        dev_info(chan2dev(chan),
                 "%s: src=%pad, dest=%pad, numf=%d, frame_size=%d, flags=0x%lx\n",
                __func__, &xt->src_start, &xt->dst_start, xt->numf,
index 7638b24..35fc58f 100644 (file)
@@ -557,7 +557,7 @@ static int jz4740_dma_probe(struct platform_device *pdev)
 
        ret = dma_async_device_register(dd);
        if (ret)
-               return ret;
+               goto err_clk;
 
        irq = platform_get_irq(pdev, 0);
        ret = request_irq(irq, jz4740_dma_irq, 0, dev_name(&pdev->dev), dmadev);
@@ -570,6 +570,8 @@ static int jz4740_dma_probe(struct platform_device *pdev)
 
 err_unregister:
        dma_async_device_unregister(dd);
+err_clk:
+       clk_disable_unprepare(dmadev->clk);
        return ret;
 }
 
index 7254c20..6796eb1 100644 (file)
@@ -329,7 +329,7 @@ static void dmatest_callback(void *arg)
 {
        struct dmatest_done *done = arg;
        struct dmatest_thread *thread =
-               container_of(arg, struct dmatest_thread, done_wait);
+               container_of(done, struct dmatest_thread, test_done);
        if (!thread->done) {
                done->done = true;
                wake_up_all(done->wait);
index abb75eb..ac8c289 100644 (file)
@@ -395,7 +395,7 @@ static int ioat_dma_self_test(struct ioatdma_device *ioat_dma)
        if (memcmp(src, dest, IOAT_TEST_SIZE)) {
                dev_err(dev, "Self-test copy failed compare, disabling\n");
                err = -ENODEV;
-               goto free_resources;
+               goto unmap_dma;
        }
 
 unmap_dma:
index 6059d81..8e55403 100644 (file)
@@ -26,7 +26,7 @@
 
 #define DRIVER_NAME            "zx-dma"
 #define DMA_ALIGN              4
-#define DMA_MAX_SIZE           (0x10000 - PAGE_SIZE)
+#define DMA_MAX_SIZE           (0x10000 - 512)
 #define LLI_BLOCK_SIZE         (4 * PAGE_SIZE)
 
 #define REG_ZX_SRC_ADDR                        0x00
index cda6dab..6b65a10 100644 (file)
@@ -79,6 +79,7 @@ static void octeon_lmc_edac_poll_o2(struct mem_ctl_info *mci)
        if (!pvt->inject)
                int_reg.u64 = cvmx_read_csr(CVMX_LMCX_INT(mci->mc_idx));
        else {
+               int_reg.u64 = 0;
                if (pvt->error_type == 1)
                        int_reg.s.sec_err = 1;
                if (pvt->error_type == 2)
index c50e930..297121a 100644 (file)
@@ -326,7 +326,7 @@ static void intel_mid_irq_init_hw(struct intel_mid_gpio *priv)
        }
 }
 
-static int intel_gpio_runtime_idle(struct device *dev)
+static int __maybe_unused intel_gpio_runtime_idle(struct device *dev)
 {
        int err = pm_schedule_suspend(dev, 500);
        return err ?: -EBUSY;
index 18a8182..7f1f323 100644 (file)
@@ -42,9 +42,7 @@ struct xgene_gpio {
        struct gpio_chip        chip;
        void __iomem            *base;
        spinlock_t              lock;
-#ifdef CONFIG_PM
        u32                     set_dr_val[XGENE_MAX_GPIO_BANKS];
-#endif
 };
 
 static inline struct xgene_gpio *to_xgene_gpio(struct gpio_chip *chip)
@@ -132,8 +130,7 @@ static int xgene_gpio_dir_out(struct gpio_chip *gc,
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int xgene_gpio_suspend(struct device *dev)
+static __maybe_unused int xgene_gpio_suspend(struct device *dev)
 {
        struct xgene_gpio *gpio = dev_get_drvdata(dev);
        unsigned long bank_offset;
@@ -146,7 +143,7 @@ static int xgene_gpio_suspend(struct device *dev)
        return 0;
 }
 
-static int xgene_gpio_resume(struct device *dev)
+static __maybe_unused int xgene_gpio_resume(struct device *dev)
 {
        struct xgene_gpio *gpio = dev_get_drvdata(dev);
        unsigned long bank_offset;
@@ -160,10 +157,6 @@ static int xgene_gpio_resume(struct device *dev)
 }
 
 static SIMPLE_DEV_PM_OPS(xgene_gpio_pm, xgene_gpio_suspend, xgene_gpio_resume);
-#define XGENE_GPIO_PM_OPS      (&xgene_gpio_pm)
-#else
-#define XGENE_GPIO_PM_OPS      NULL
-#endif
 
 static int xgene_gpio_probe(struct platform_device *pdev)
 {
@@ -230,7 +223,7 @@ static struct platform_driver xgene_gpio_driver = {
        .driver = {
                .name = "xgene-gpio",
                .of_match_table = xgene_gpio_of_match,
-               .pm     = XGENE_GPIO_PM_OPS,
+               .pm     = &xgene_gpio_pm,
        },
        .probe = xgene_gpio_probe,
        .remove = xgene_gpio_remove,
index cebcab5..5d68189 100644 (file)
@@ -1182,17 +1182,13 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,
 
        ret = devm_request_irq(dev, irq, armada_drm_irq, 0, "armada_drm_crtc",
                               dcrtc);
-       if (ret < 0) {
-               kfree(dcrtc);
-               return ret;
-       }
+       if (ret < 0)
+               goto err_crtc;
 
        if (dcrtc->variant->init) {
                ret = dcrtc->variant->init(dcrtc, dev);
-               if (ret) {
-                       kfree(dcrtc);
-                       return ret;
-               }
+               if (ret)
+                       goto err_crtc;
        }
 
        /* Ensure AXI pipeline is enabled */
@@ -1203,13 +1199,15 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,
        dcrtc->crtc.port = port;
 
        primary = kzalloc(sizeof(*primary), GFP_KERNEL);
-       if (!primary)
-               return -ENOMEM;
+       if (!primary) {
+               ret = -ENOMEM;
+               goto err_crtc;
+       }
 
        ret = armada_drm_plane_init(primary);
        if (ret) {
                kfree(primary);
-               return ret;
+               goto err_crtc;
        }
 
        ret = drm_universal_plane_init(drm, &primary->base, 0,
@@ -1219,7 +1217,7 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,
                                       DRM_PLANE_TYPE_PRIMARY);
        if (ret) {
                kfree(primary);
-               return ret;
+               goto err_crtc;
        }
 
        ret = drm_crtc_init_with_planes(drm, &dcrtc->crtc, &primary->base, NULL,
@@ -1238,6 +1236,9 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,
 
 err_crtc_init:
        primary->base.funcs->destroy(&primary->base);
+err_crtc:
+       kfree(dcrtc);
+
        return ret;
 }
 
index 6675b14..c257de3 100644 (file)
@@ -69,7 +69,7 @@ void drm_modeset_lock_all(struct drm_device *dev)
        struct drm_modeset_acquire_ctx *ctx;
        int ret;
 
-       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL | __GFP_NOFAIL);
        if (WARN_ON(!ctx))
                return;
 
index d4813e0..00275c3 100644 (file)
@@ -821,14 +821,18 @@ void mdfld_dsi_dpi_mode_set(struct drm_encoder *encoder,
        struct drm_device *dev = dsi_config->dev;
        struct drm_psb_private *dev_priv = dev->dev_private;
        int pipe = mdfld_dsi_encoder_get_pipe(dsi_encoder);
-
        u32 pipeconf_reg = PIPEACONF;
        u32 dspcntr_reg = DSPACNTR;
+       u32 pipeconf, dspcntr;
 
-       u32 pipeconf = dev_priv->pipeconf[pipe];
-       u32 dspcntr = dev_priv->dspcntr[pipe];
        u32 mipi = MIPI_PORT_EN | PASS_FROM_SPHY_TO_AFE | SEL_FLOPPED_HSTX;
 
+       if (WARN_ON(pipe < 0))
+               return;
+
+       pipeconf = dev_priv->pipeconf[pipe];
+       dspcntr = dev_priv->dspcntr[pipe];
+
        if (pipe) {
                pipeconf_reg = PIPECCONF;
                dspcntr_reg = DSPCCNTR;
index 89f705c..910a2f2 100644 (file)
@@ -382,16 +382,6 @@ static int mdfld_dsi_connector_mode_valid(struct drm_connector *connector,
        return MODE_OK;
 }
 
-static void mdfld_dsi_connector_dpms(struct drm_connector *connector, int mode)
-{
-       if (mode == connector->dpms)
-               return;
-
-       /*first, execute dpms*/
-
-       drm_helper_connector_dpms(connector, mode);
-}
-
 static struct drm_encoder *mdfld_dsi_connector_best_encoder(
                                struct drm_connector *connector)
 {
@@ -404,7 +394,7 @@ static struct drm_encoder *mdfld_dsi_connector_best_encoder(
 
 /*DSI connector funcs*/
 static const struct drm_connector_funcs mdfld_dsi_connector_funcs = {
-       .dpms = /*drm_helper_connector_dpms*/mdfld_dsi_connector_dpms,
+       .dpms = drm_helper_connector_dpms,
        .save = mdfld_dsi_connector_save,
        .restore = mdfld_dsi_connector_restore,
        .detect = mdfld_dsi_connector_detect,
index baf7ee2..133b122 100644 (file)
@@ -355,11 +355,35 @@ static int msm_ioctl_query_client_id(struct drm_device *dev, void *data,
        return ret;
 }
 
+static long msm_drm_ioctl(struct file *filp,
+       unsigned int cmd, unsigned long arg)
+{
+       switch (cmd) {
+       case DRM_IOCTL_PRIME_FD_TO_HANDLE:
+       {
+               struct drm_prime_handle cmd_data;
+
+               if (copy_from_user(&cmd_data, (void __user *)arg,
+                               sizeof(struct drm_prime_handle)) != 0)
+                       return -EFAULT;
+               cmd_data.handle = cmd_data.fd;
+               if (copy_to_user((void __user *)arg, &cmd_data,
+                               sizeof(struct drm_prime_handle)) != 0)
+                       return -EFAULT;
+               return 0;
+       }
+       case DRM_IOCTL_GEM_CLOSE:
+               return 0;
+       default:
+               return drm_ioctl(filp, cmd, arg);
+       }
+}
+
 static const struct file_operations fops = {
        .owner              = THIS_MODULE,
        .open               = drm_open,
        .release            = drm_release,
-       .unlocked_ioctl     = drm_ioctl,
+       .unlocked_ioctl     = msm_drm_ioctl,
        .poll               = drm_poll,
        .read               = drm_read,
        .write              = msm_drm_write,
index fb9617c..6015cf3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1089,7 +1089,7 @@ error:
 static int dsi_enable_ulps(struct dsi_ctrl *dsi_ctrl)
 {
        int rc = 0;
-       u32 lanes;
+       u32 lanes = 0;
        u32 ulps_lanes;
 
        if (dsi_ctrl->host_config.panel_mode == DSI_OP_CMD_MODE)
index 2f0f6c2..caba508 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -565,7 +565,7 @@ u32 dsi_ctrl_hw_14_get_cmd_read_data(struct dsi_ctrl_hw *ctrl,
        u32 read_cnt;
        u32 rx_byte = 0;
        u32 repeated_bytes = 0;
-       u8 reg[16];
+       u8 reg[16] = {0};
        u32 pkt_size = 0;
        int buf_offset = read_offset;
 
index f2412da..09ab14c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1481,8 +1481,8 @@ static int dsi_display_dfps_update(struct dsi_display *display,
        m_ctrl = &display->ctrl[display->clk_master_idx];
        rc = dsi_ctrl_async_timing_update(m_ctrl->ctrl, timing);
        if (rc) {
-               pr_err("[%s] failed to dfps update host_%d, rc=%d\n",
-                               display->name, i, rc);
+               pr_err("[%s] failed to dfps update clock master, rc=%d\n",
+                               display->name, rc);
                goto error;
        }
 
index 3c149f1..4b6eeb6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark <robdclark@gmail.com>
  *
@@ -1215,6 +1215,9 @@ static int _sde_hdmi_gpio_config(struct hdmi *hdmi, bool on)
 
                gpio_free(config->hpd_gpio);
 
+               if (config->hpd5v_gpio != -1)
+                       gpio_free(config->hpd5v_gpio);
+
                if (config->mux_en_gpio != -1) {
                        gpio_set_value_cansleep(config->mux_en_gpio, 0);
                        gpio_free(config->mux_en_gpio);
@@ -1336,6 +1339,8 @@ static int _sde_hdmi_hpd_enable(struct sde_hdmi *sde_hdmi)
                        HDMI_HPD_CTRL_ENABLE | hpd_ctrl);
        spin_unlock_irqrestore(&hdmi->reg_lock, flags);
 
+       hdmi->hpd_off = false;
+       SDE_DEBUG("enabled hdmi hpd\n");
        return 0;
 
 fail:
@@ -1395,7 +1400,7 @@ int sde_hdmi_core_enable(struct sde_hdmi *sde_hdmi)
        return ret;
 }
 
-static void _sde_hdmi_hdp_disable(struct sde_hdmi *sde_hdmi)
+static void _sde_hdmi_hpd_disable(struct sde_hdmi *sde_hdmi)
 {
        struct hdmi *hdmi = sde_hdmi->ctrl.ctrl;
        const struct hdmi_platform_config *config = hdmi->config;
@@ -1403,6 +1408,11 @@ static void _sde_hdmi_hdp_disable(struct sde_hdmi *sde_hdmi)
        int i, ret = 0;
        unsigned long flags;
 
+       if (hdmi->hpd_off) {
+               pr_warn("hdmi display hpd was already disabled\n");
+               return;
+       }
+
        spin_lock_irqsave(&hdmi->reg_lock, flags);
        /* Disable HPD interrupt */
        hdmi_write(hdmi, REG_HDMI_HPD_CTRL, 0);
@@ -1429,12 +1439,42 @@ static void _sde_hdmi_hdp_disable(struct sde_hdmi *sde_hdmi)
                        pr_warn("failed to disable hpd regulator: %s (%d)\n",
                                        config->hpd_reg_names[i], ret);
        }
+       hdmi->hpd_off = true;
+       SDE_DEBUG("disabled hdmi hpd\n");
+}
+
+/**
+ * _sde_hdmi_update_hpd_state() - Update the HDMI HPD clock state
+ *
+ * @state: non-zero to disbale HPD clock, 0 to enable.
+ * return: 0 on success, non-zero in case of failure.
+ *
+ */
+static int
+_sde_hdmi_update_hpd_state(struct sde_hdmi *hdmi_display, u64 state)
+{
+       struct hdmi *hdmi = hdmi_display->ctrl.ctrl;
+       int rc = 0;
+
+       if (hdmi_display->non_pluggable)
+               return 0;
+
+       SDE_DEBUG("changing hdmi hpd state to %llu\n", state);
+
+       if (state == SDE_MODE_HPD_ON) {
+               if (!hdmi->hpd_off)
+                       pr_warn("hdmi display hpd was already enabled\n");
+               rc = _sde_hdmi_hpd_enable(hdmi_display);
+       } else
+               _sde_hdmi_hpd_disable(hdmi_display);
+
+       return rc;
 }
 
 void sde_hdmi_core_disable(struct sde_hdmi *sde_hdmi)
 {
        /* HPD contains all the core clock and pwr */
-       _sde_hdmi_hdp_disable(sde_hdmi);
+       _sde_hdmi_hpd_disable(sde_hdmi);
 }
 
 static void _sde_hdmi_cec_update_phys_addr(struct sde_hdmi *display)
@@ -1664,7 +1704,7 @@ static int _sde_hdmi_ext_disp_init(struct sde_hdmi *display)
        const char *phandle = "qcom,msm_ext_disp";
 
        if (!display) {
-               SDE_ERROR("[%s]Invalid params\n", display->name);
+               SDE_ERROR("Invalid params\n");
                return -EINVAL;
        }
 
@@ -2204,6 +2244,8 @@ int sde_hdmi_set_property(struct drm_connector *connector,
                rc = _sde_hdmi_enable_pll_update(display, value);
        else if (property_index == CONNECTOR_PROP_PLL_DELTA)
                rc = _sde_hdmi_update_pll_delta(display, value);
+       else if (property_index == CONNECTOR_PROP_HPD_OFF)
+               rc = _sde_hdmi_update_hpd_state(display, value);
 
        return rc;
 }
@@ -2281,7 +2323,7 @@ int sde_hdmi_connector_pre_deinit(struct drm_connector *connector,
                return -EINVAL;
        }
 
-       _sde_hdmi_hdp_disable(sde_hdmi);
+       _sde_hdmi_hpd_disable(sde_hdmi);
 
        return 0;
 }
index 8ca7b36..9a0733b 100644 (file)
@@ -50,6 +50,9 @@ struct hdmi {
 
        const struct hdmi_platform_config *config;
 
+       /* hpd state: */
+       bool hpd_off;
+
        /* audio state: */
        struct hdmi_audio audio;
 
index 25dc5f9..fb24b83 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark <robdclark@gmail.com>
  *
@@ -164,6 +164,7 @@ enum msm_mdp_conn_property {
        CONNECTOR_PROP_TOPOLOGY_NAME,
        CONNECTOR_PROP_TOPOLOGY_CONTROL,
        CONNECTOR_PROP_LP,
+       CONNECTOR_PROP_HPD_OFF,
 
        /* total # of properties */
        CONNECTOR_PROP_COUNT
index 6a741a7..e8dfd1f 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -46,6 +46,11 @@ static const struct drm_prop_enum_list e_power_mode[] = {
        {SDE_MODE_DPMS_OFF,     "OFF"},
 };
 
+static const struct drm_prop_enum_list hpd_clock_state[] = {
+       {SDE_MODE_HPD_ON,      "ON"},
+       {SDE_MODE_HPD_OFF,     "OFF"},
+};
+
 int sde_connector_get_info(struct drm_connector *connector,
                struct msm_display_info *info)
 {
@@ -475,6 +480,9 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector,
                _sde_connector_update_power_locked(c_conn);
                mutex_unlock(&c_conn->lock);
                break;
+       case CONNECTOR_PROP_HPD_OFF:
+               c_conn->hpd_mode = val;
+               break;
        default:
                break;
        }
@@ -819,6 +827,7 @@ struct drm_connector *sde_connector_init(struct drm_device *dev,
        c_conn->display = display;
 
        c_conn->dpms_mode = DRM_MODE_DPMS_ON;
+       c_conn->hpd_mode = SDE_MODE_HPD_ON;
        c_conn->lp_mode = 0;
        c_conn->last_panel_power_mode = SDE_MODE_DPMS_ON;
 
@@ -946,6 +955,11 @@ struct drm_connector *sde_connector_init(struct drm_device *dev,
                        ARRAY_SIZE(e_power_mode),
                        CONNECTOR_PROP_LP, 0);
 
+       msm_property_install_enum(&c_conn->property_info, "HPD_OFF",
+                       DRM_MODE_PROP_ATOMIC, 0, hpd_clock_state,
+                       ARRAY_SIZE(hpd_clock_state),
+                       CONNECTOR_PROP_HPD_OFF, 0);
+
        rc = msm_property_install_get_status(&c_conn->property_info);
        if (rc) {
                SDE_ERROR("failed to create one or more properties\n");
index 0f563ac..7db98af 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -22,6 +22,9 @@
 #include "sde_kms.h"
 #include "sde_fence.h"
 
+#define SDE_MODE_HPD_ON        0
+#define SDE_MODE_HPD_OFF       1
+
 #define SDE_CONNECTOR_NAME_SIZE        16
 
 struct sde_connector;
@@ -207,6 +210,7 @@ struct sde_connector {
        struct sde_fence retire_fence;
        struct sde_connector_ops ops;
        int dpms_mode;
+       u64 hpd_mode;
        int lp_mode;
        int last_panel_power_mode;
 
index 3f5aa4d..96ef909 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2018 The Linux Foundation. All rights reserved.
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark <robdclark@gmail.com>
  *
@@ -240,6 +240,10 @@ static void _sde_crtc_blend_setup_mixer(struct drm_crtc *crtc,
                                plane->state->fb->base.id : -1);
 
                format = to_sde_format(msm_framebuffer_format(pstate->base.fb));
+               if (!format) {
+                       SDE_ERROR("%s: get sde format failed\n", __func__);
+                       return;
+               }
 
                /* blend config update */
                if (pstate->stage != SDE_STAGE_BASE) {
@@ -915,6 +919,11 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc)
        dev = crtc->dev;
        sde_crtc = to_sde_crtc(crtc);
        sde_kms = _sde_crtc_get_kms(crtc);
+       if (!sde_kms) {
+               SDE_ERROR("invalid sde_kms\n");
+               return;
+       }
+
        priv = sde_kms->dev->dev_private;
 
        /*
@@ -1543,6 +1552,10 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc,
        sde_crtc = to_sde_crtc(crtc);
        dev = crtc->dev;
        sde_kms = _sde_crtc_get_kms(crtc);
+       if (!sde_kms) {
+               SDE_ERROR("invalid sde_kms\n");
+               return;
+       }
 
        info = kzalloc(sizeof(struct sde_kms_info), GFP_KERNEL);
        if (!info) {
@@ -1683,7 +1696,6 @@ static int sde_crtc_atomic_get_property(struct drm_crtc *crtc,
        struct sde_crtc *sde_crtc;
        struct sde_crtc_state *cstate;
        int i, ret = -EINVAL;
-       bool conn_offset = 0;
 
        if (!crtc || !state) {
                SDE_ERROR("invalid argument(s)\n");
@@ -1691,20 +1703,13 @@ static int sde_crtc_atomic_get_property(struct drm_crtc *crtc,
                sde_crtc = to_sde_crtc(crtc);
                cstate = to_sde_crtc_state(state);
 
-               for (i = 0; i < cstate->num_connectors; ++i) {
-                       conn_offset = sde_connector_needs_offset(
-                                               cstate->connectors[i]);
-                       if (conn_offset)
-                               break;
-               }
-
                i = msm_property_index(&sde_crtc->property_info, property);
                if (i == CRTC_PROP_OUTPUT_FENCE) {
                        int offset = sde_crtc_get_property(cstate,
                                        CRTC_PROP_OUTPUT_FENCE_OFFSET);
 
                        ret = sde_fence_create(&sde_crtc->output_fence, val,
-                                                       offset + conn_offset);
+                                                       offset);
                        if (ret)
                                SDE_ERROR("fence create failed\n");
                } else {
index cb8b349..6e4de62 100644 (file)
@@ -43,6 +43,8 @@
 /* timeout in frames waiting for frame done */
 #define SDE_ENCODER_FRAME_DONE_TIMEOUT 60
 
+#define MISR_BUFF_SIZE 256
+
 /*
  * Two to anticipate panels that can do cmd/vid dynamic switching
  * plan is to create all possible physical encoder types, and switch between
@@ -1046,16 +1048,18 @@ static ssize_t _sde_encoder_misr_set(struct file *file,
        struct sde_encoder_virt *sde_enc;
        struct drm_encoder *drm_enc;
        int i = 0;
-       char buf[10];
+       char buf[MISR_BUFF_SIZE + 1];
+       size_t buff_copy;
        u32 enable, frame_count;
 
        drm_enc = file->private_data;
        sde_enc = to_sde_encoder_virt(drm_enc);
 
-       if (copy_from_user(buf, user_buf, count))
-               return -EFAULT;
+       buff_copy = min_t(size_t, MISR_BUFF_SIZE, count);
+       if (copy_from_user(buf, user_buf, buff_copy))
+               return -EINVAL;
 
-       buf[count] = 0; /* end of string */
+       buf[buff_copy] = 0; /* end of string */
 
        if (sscanf(buf, "%u %u", &enable, &frame_count) != 2)
                return -EFAULT;
index d58c06d..2f89c57 100644 (file)
@@ -333,10 +333,24 @@ static void sde_encoder_phys_vid_underrun_irq(void *arg, int irq_idx)
                        phys_enc);
 }
 
+static bool _sde_encoder_phys_is_ppsplit(struct sde_encoder_phys *phys_enc)
+{
+       enum sde_rm_topology_name topology;
+
+       if (!phys_enc)
+               return false;
+
+       topology = sde_connector_get_topology_name(phys_enc->connector);
+       if (topology == SDE_RM_TOPOLOGY_PPSPLIT)
+               return true;
+
+       return false;
+}
+
 static bool sde_encoder_phys_vid_needs_single_flush(
                struct sde_encoder_phys *phys_enc)
 {
-       return phys_enc && phys_enc->split_role != ENC_ROLE_SOLO;
+       return phys_enc && _sde_encoder_phys_is_ppsplit(phys_enc);
 }
 
 static int sde_encoder_phys_vid_register_irq(struct sde_encoder_phys *phys_enc,
@@ -674,7 +688,7 @@ static int sde_encoder_phys_vid_wait_for_vblank(
                        KICKOFF_TIMEOUT_MS);
        if (ret <= 0) {
                irq_status = sde_core_irq_read(phys_enc->sde_kms,
-                               INTR_IDX_VSYNC, true);
+                               vid_enc->irq_idx[INTR_IDX_VSYNC], true);
                if (irq_status) {
                        SDE_EVT32(DRMID(phys_enc->parent),
                                        vid_enc->hw_intf->idx - INTF_0);
index 34a32d7..93b8a69 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark <robdclark@gmail.com>
  *
@@ -385,7 +385,7 @@ static void sde_kms_wait_for_commit_done(struct msm_kms *kms,
                struct drm_crtc *crtc)
 {
        struct drm_encoder *encoder;
-       struct drm_device *dev = crtc->dev;
+       struct drm_device *dev;
        int ret;
 
        if (!kms || !crtc || !crtc->state) {
@@ -393,6 +393,8 @@ static void sde_kms_wait_for_commit_done(struct msm_kms *kms,
                return;
        }
 
+       dev = crtc->dev;
+
        if (!crtc->state->enable) {
                SDE_DEBUG("[crtc:%d] not enable\n", crtc->base.id);
                return;
index f5f125c..43ff508 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014-2017 The Linux Foundation. All rights reserved.
+ * Copyright (C) 2014-2018 The Linux Foundation. All rights reserved.
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark <robdclark@gmail.com>
  *
@@ -303,6 +303,11 @@ static void _sde_plane_set_qos_lut(struct sde_phy_plane *pp,
                                fb->pixel_format,
                                fb->modifier,
                                drm_format_num_planes(fb->pixel_format));
+               if (!fmt) {
+                       SDE_ERROR("%s: faile to get fmt\n", __func__);
+                       return;
+               }
+
                total_fl = _sde_plane_calc_fill_level(pp, fmt,
                                pp->pipe_cfg.src_rect.w);
 
@@ -362,6 +367,10 @@ static void _sde_plane_set_danger_lut(struct sde_phy_plane *pp,
                                fb->pixel_format,
                                fb->modifier,
                                drm_format_num_planes(fb->pixel_format));
+               if (!fmt) {
+                       SDE_ERROR("%s: fail to get fmt\n", __func__);
+                       return;
+               }
 
                if (SDE_FORMAT_IS_LINEAR(fmt)) {
                        danger_lut = pp->pipe_sblk->danger_lut_linear;
@@ -694,11 +703,11 @@ static inline void _sde_plane_set_scanout(struct sde_phy_plane *pp,
 static int _sde_plane_setup_scaler3_lut(struct sde_phy_plane *pp,
                struct sde_plane_state *pstate)
 {
-       struct sde_plane *psde = pp->sde_plane;
+       struct sde_plane *psde;
        struct sde_hw_scaler3_cfg *cfg;
        int ret = 0;
 
-       if (!pp || !pp->scaler3_cfg) {
+       if (!pp || !pp->sde_plane || !pp->scaler3_cfg) {
                SDE_ERROR("invalid args\n");
                return -EINVAL;
        } else if (!pstate) {
@@ -707,6 +716,7 @@ static int _sde_plane_setup_scaler3_lut(struct sde_phy_plane *pp,
                return -EINVAL;
        }
 
+       psde = pp->sde_plane;
        cfg = pp->scaler3_cfg;
 
        cfg->dir_lut = msm_property_get_blob(
@@ -1450,7 +1460,7 @@ static int _sde_plane_mode_set(struct drm_plane *plane,
 static int sde_plane_prepare_fb(struct drm_plane *plane,
                const struct drm_plane_state *new_state)
 {
-       struct drm_framebuffer *fb = new_state->fb;
+       struct drm_framebuffer *fb;
        struct sde_plane *psde = to_sde_plane(plane);
        struct sde_plane_state *pstate;
        int rc;
@@ -1461,6 +1471,7 @@ static int sde_plane_prepare_fb(struct drm_plane *plane,
        if (!new_state->fb)
                return 0;
 
+       fb = new_state->fb;
        pstate = to_sde_plane_state(new_state);
        rc = _sde_plane_get_aspace(psde, pstate, &psde->aspace);
 
@@ -1800,7 +1811,7 @@ static void _sde_plane_install_properties(struct drm_plane *plane,
                {SDE_DRM_FB_NON_SEC_DIR_TRANS, "non_sec_direct_translation"},
                {SDE_DRM_FB_SEC_DIR_TRANS, "sec_direct_translation"},
        };
-       const struct sde_format_extended *format_list;
+       const struct sde_format_extended *format_list = NULL;
        struct sde_kms_info *info;
        struct sde_plane *psde = to_sde_plane(plane);
        int zpos_max = 255;
index a0865c4..495c279 100644 (file)
@@ -370,7 +370,7 @@ validate_init(struct nouveau_channel *chan, struct drm_file *file_priv,
        struct nouveau_cli *cli = nouveau_cli(file_priv);
        struct drm_device *dev = chan->drm->dev;
        int trycnt = 0;
-       int ret, i;
+       int ret = -EINVAL, i;
        struct nouveau_bo *res_bo = NULL;
        LIST_HEAD(gart_list);
        LIST_HEAD(vram_list);
index 6edcb54..b35ebab 100644 (file)
@@ -946,7 +946,7 @@ int radeon_uvd_calc_upll_dividers(struct radeon_device *rdev,
                /* calc dclk divider with current vco freq */
                dclk_div = radeon_uvd_calc_upll_post_div(vco_freq, dclk,
                                                         pd_min, pd_even);
-               if (vclk_div > pd_max)
+               if (dclk_div > pd_max)
                        break; /* vco is too big, it has to stop */
 
                /* calc score with current vco freq */
index 9befd62..6fab079 100644 (file)
@@ -371,6 +371,31 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
        rcrtc->started = true;
 }
 
+static void rcar_du_crtc_disable_planes(struct rcar_du_crtc *rcrtc)
+{
+       struct rcar_du_device *rcdu = rcrtc->group->dev;
+       struct drm_crtc *crtc = &rcrtc->crtc;
+       u32 status;
+       /* Make sure vblank interrupts are enabled. */
+       drm_crtc_vblank_get(crtc);
+       /*
+        * Disable planes and calculate how many vertical blanking interrupts we
+        * have to wait for. If a vertical blanking interrupt has been triggered
+        * but not processed yet, we don't know whether it occurred before or
+        * after the planes got disabled. We thus have to wait for two vblank
+        * interrupts in that case.
+        */
+       spin_lock_irq(&rcrtc->vblank_lock);
+       rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0);
+       status = rcar_du_crtc_read(rcrtc, DSSR);
+       rcrtc->vblank_count = status & DSSR_VBK ? 2 : 1;
+       spin_unlock_irq(&rcrtc->vblank_lock);
+       if (!wait_event_timeout(rcrtc->vblank_wait, rcrtc->vblank_count == 0,
+                               msecs_to_jiffies(100)))
+               dev_warn(rcdu->dev, "vertical blanking timeout\n");
+       drm_crtc_vblank_put(crtc);
+}
+
 static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
 {
        struct drm_crtc *crtc = &rcrtc->crtc;
@@ -379,17 +404,16 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
                return;
 
        /* Disable all planes and wait for the change to take effect. This is
-        * required as the DSnPR registers are updated on vblank, and no vblank
-        * will occur once the CRTC is stopped. Disabling planes when starting
-        * the CRTC thus wouldn't be enough as it would start scanning out
-        * immediately from old frame buffers until the next vblank.
+        * required as the plane enable registers are updated on vblank, and no
+        * vblank will occur once the CRTC is stopped. Disabling planes when
+        * starting the CRTC thus wouldn't be enough as it would start scanning
+        * out immediately from old frame buffers until the next vblank.
         *
         * This increases the CRTC stop delay, especially when multiple CRTCs
         * are stopped in one operation as we now wait for one vblank per CRTC.
         * Whether this can be improved needs to be researched.
         */
-       rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0);
-       drm_crtc_wait_one_vblank(crtc);
+       rcar_du_crtc_disable_planes(rcrtc);
 
        /* Disable vertical blanking interrupt reporting. We first need to wait
         * for page flip completion before stopping the CRTC as userspace
@@ -528,10 +552,26 @@ static irqreturn_t rcar_du_crtc_irq(int irq, void *arg)
        irqreturn_t ret = IRQ_NONE;
        u32 status;
 
+       spin_lock(&rcrtc->vblank_lock);
+
        status = rcar_du_crtc_read(rcrtc, DSSR);
        rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK);
 
-       if (status & DSSR_FRM) {
+       if (status & DSSR_VBK) {
+               /*
+                * Wake up the vblank wait if the counter reaches 0. This must
+                * be protected by the vblank_lock to avoid races in
+                * rcar_du_crtc_disable_planes().
+                */
+               if (rcrtc->vblank_count) {
+                       if (--rcrtc->vblank_count == 0)
+                               wake_up(&rcrtc->vblank_wait);
+               }
+       }
+
+       spin_unlock(&rcrtc->vblank_lock);
+
+       if (status & DSSR_VBK) {
                drm_handle_vblank(rcrtc->crtc.dev, rcrtc->index);
                rcar_du_crtc_finish_page_flip(rcrtc);
                ret = IRQ_HANDLED;
@@ -585,6 +625,8 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index)
        }
 
        init_waitqueue_head(&rcrtc->flip_wait);
+       init_waitqueue_head(&rcrtc->vblank_wait);
+       spin_lock_init(&rcrtc->vblank_lock);
 
        rcrtc->group = rgrp;
        rcrtc->mmio_offset = mmio_offsets[index];
index 2bbe3f5..be22ce3 100644 (file)
@@ -15,6 +15,7 @@
 #define __RCAR_DU_CRTC_H__
 
 #include <linux/mutex.h>
+#include <linux/spinlock.h>
 #include <linux/wait.h>
 
 #include <drm/drmP.h>
@@ -32,6 +33,9 @@ struct rcar_du_group;
  * @started: whether the CRTC has been started and is running
  * @event: event to post when the pending page flip completes
  * @flip_wait: wait queue used to signal page flip completion
+ * @vblank_lock: protects vblank_wait and vblank_count
+ * @vblank_wait: wait queue used to signal vertical blanking
+ * @vblank_count: number of vertical blanking interrupts to wait for
  * @outputs: bitmask of the outputs (enum rcar_du_output) driven by this CRTC
  * @enabled: whether the CRTC is enabled, used to control system resume
  * @group: CRTC group this CRTC belongs to
@@ -48,6 +52,10 @@ struct rcar_du_crtc {
        struct drm_pending_vblank_event *event;
        wait_queue_head_t flip_wait;
 
+       spinlock_t vblank_lock;
+       wait_queue_head_t vblank_wait;
+       unsigned int vblank_count;
+
        unsigned int outputs;
        bool enabled;
 
index 67cebb2..aa04fb0 100644 (file)
@@ -293,13 +293,10 @@ static int vmw_cmdbuf_header_submit(struct vmw_cmdbuf_header *header)
        struct vmw_cmdbuf_man *man = header->man;
        u32 val;
 
-       if (sizeof(header->handle) > 4)
-               val = (header->handle >> 32);
-       else
-               val = 0;
+       val = upper_32_bits(header->handle);
        vmw_write(man->dev_priv, SVGA_REG_COMMAND_HIGH, val);
 
-       val = (header->handle & 0xFFFFFFFFULL);
+       val = lower_32_bits(header->handle);
        val |= header->cb_context & SVGA_CB_CONTEXT_MASK;
        vmw_write(man->dev_priv, SVGA_REG_COMMAND_LOW, val);
 
index 97a2d8f..bb8ab4c 100644 (file)
@@ -530,6 +530,16 @@ int kgsl_context_init(struct kgsl_device_private *dev_priv,
        struct kgsl_device *device = dev_priv->device;
        char name[64];
        int ret = 0, id;
+       struct kgsl_process_private  *proc_priv = dev_priv->process_priv;
+
+       if (atomic_read(&proc_priv->ctxt_count) > KGSL_MAX_CONTEXTS_PER_PROC) {
+               KGSL_DRV_ERR(device,
+                       "Per process context limit reached for pid %u",
+                       dev_priv->process_priv->pid);
+               return -ENOSPC;
+       }
+
+       atomic_inc(&proc_priv->ctxt_count);
 
        id = _kgsl_get_context_id(device);
        if (id == -ENOSPC) {
@@ -548,7 +558,7 @@ int kgsl_context_init(struct kgsl_device_private *dev_priv,
                        KGSL_DRV_INFO(device,
                                "cannot have more than %zu contexts due to memstore limitation\n",
                                KGSL_MEMSTORE_MAX);
-
+               atomic_dec(&proc_priv->ctxt_count);
                return id;
        }
 
@@ -579,6 +589,7 @@ int kgsl_context_init(struct kgsl_device_private *dev_priv,
 
 out:
        if (ret) {
+               atomic_dec(&proc_priv->ctxt_count);
                write_lock(&device->context_lock);
                idr_remove(&dev_priv->device->context_idr, id);
                write_unlock(&device->context_lock);
@@ -662,6 +673,7 @@ kgsl_context_destroy(struct kref *kref)
                        device->pwrctrl.constraint.type = KGSL_CONSTRAINT_NONE;
                }
 
+               atomic_dec(&context->proc_priv->ctxt_count);
                idr_remove(&device->context_idr, context->id);
                context->id = KGSL_CONTEXT_INVALID;
        }
index faf38d1..a486d9a 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2016, 2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
 /* The number of memstore arrays limits the number of contexts allowed.
  * If more contexts are needed, update multiple for MEMSTORE_SIZE
  */
-#define KGSL_MEMSTORE_SIZE     ((int)(PAGE_SIZE * 2))
+#define KGSL_MEMSTORE_SIZE     ((int)(PAGE_SIZE * 8))
 #define KGSL_MEMSTORE_GLOBAL   (0)
 #define KGSL_PRIORITY_MAX_RB_LEVELS 4
 #define KGSL_MEMSTORE_MAX      (KGSL_MEMSTORE_SIZE / \
        sizeof(struct kgsl_devmemstore) - 1 - KGSL_PRIORITY_MAX_RB_LEVELS)
+#define KGSL_MAX_CONTEXTS_PER_PROC 200
 
 #define MEMSTORE_RB_OFFSET(rb, field)  \
        KGSL_MEMSTORE_OFFSET(((rb)->id + KGSL_MEMSTORE_MAX), field)
index 64dd45a..b6c787e 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -417,6 +417,7 @@ struct kgsl_context {
  * @syncsource_idr: sync sources created by this process
  * @syncsource_lock: Spinlock to protect the syncsource idr
  * @fd_count: Counter for the number of FDs for this process
+ * @ctxt_count: Count for the number of contexts for this process
  */
 struct kgsl_process_private {
        unsigned long priv;
@@ -436,6 +437,7 @@ struct kgsl_process_private {
        struct idr syncsource_idr;
        spinlock_t syncsource_lock;
        int fd_count;
+       atomic_t ctxt_count;
 };
 
 /**
index 659ca36..27f80e9 100644 (file)
@@ -2309,7 +2309,6 @@ static const struct hid_device_id hid_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, 0x0004) },
        { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, 0x000a) },
        { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0400) },
-       { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0401) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC5UH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC4UM) },
@@ -2579,6 +2578,17 @@ bool hid_ignore(struct hid_device *hdev)
                        strncmp(hdev->name, "www.masterkit.ru MA901", 22) == 0)
                        return true;
                break;
+       case USB_VENDOR_ID_ELAN:
+               /*
+                * Many Elan devices have a product id of 0x0401 and are handled
+                * by the elan_i2c input driver. But the ACPI HID ELAN0800 dev
+                * is not (and cannot be) handled by that driver ->
+                * Ignore all 0x0401 devs except for the ELAN0800 dev.
+                */
+               if (hdev->product == 0x0401 &&
+                   strncmp(hdev->name, "ELAN0800", 8) != 0)
+                       return true;
+               break;
        }
 
        if (hdev->type == HID_TYPE_USBMOUSE &&
index d415a80..9a8976a 100644 (file)
@@ -195,9 +195,7 @@ int hv_init(void)
 {
        int max_leaf;
        union hv_x64_msr_hypercall_contents hypercall_msr;
-       union hv_x64_msr_hypercall_contents tsc_msr;
        void *virtaddr = NULL;
-       void *va_tsc = NULL;
 
        memset(hv_context.synic_event_page, 0, sizeof(void *) * NR_CPUS);
        memset(hv_context.synic_message_page, 0,
@@ -243,6 +241,9 @@ int hv_init(void)
 
 #ifdef CONFIG_X86_64
        if (ms_hyperv.features & HV_X64_MSR_REFERENCE_TSC_AVAILABLE) {
+               union hv_x64_msr_hypercall_contents tsc_msr;
+               void *va_tsc;
+
                va_tsc = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL);
                if (!va_tsc)
                        goto cleanup;
index 4a9536d..c0d9622 100644 (file)
@@ -32,6 +32,8 @@
 #include <linux/dma-mapping.h>
 #include <linux/i2c.h>
 #include <linux/of.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
 #include <linux/msm-sps.h>
 #include <linux/msm-bus.h>
 #include <linux/msm-bus-board.h>
@@ -50,6 +52,9 @@ static int i2c_msm_xfer_wait_for_completion(struct i2c_msm_ctrl *ctrl,
 static int  i2c_msm_pm_resume(struct device *dev);
 static void i2c_msm_pm_suspend(struct device *dev);
 static void i2c_msm_clk_path_init(struct i2c_msm_ctrl *ctrl);
+static struct pinctrl_state *
+       i2c_msm_rsrcs_gpio_get_state(struct i2c_msm_ctrl *ctrl,
+                                       const char *name);
 static void i2c_msm_pm_pinctrl_state(struct i2c_msm_ctrl *ctrl,
                                                bool runtime_active);
 
@@ -1917,63 +1922,74 @@ static void i2c_msm_qup_init(struct i2c_msm_ctrl *ctrl)
                        "error on verifying HW support (I2C_MAST_GEN=0)\n");
 }
 
-/*
- * qup_i2c_try_recover_bus_busy: issue QUP bus clear command
- */
-static int qup_i2c_try_recover_bus_busy(struct i2c_msm_ctrl *ctrl)
+static void qup_i2c_recover_bit_bang(struct i2c_msm_ctrl *ctrl)
 {
-       int ret;
-       ulong min_sleep_usec;
+       int i, ret;
+       int gpio_clk;
+       int gpio_dat;
+       bool gpio_clk_status = false;
+       uint32_t status = readl_relaxed(ctrl->rsrcs.base + QUP_I2C_STATUS);
+       struct pinctrl_state *bitbang;
 
-       /* call i2c_msm_qup_init() to set core in idle state */
-       i2c_msm_qup_init(ctrl);
-
-       /* must be in run state for bus clear */
-       ret = i2c_msm_qup_state_set(ctrl, QUP_STATE_RUN);
-       if (ret < 0) {
-               dev_err(ctrl->dev, "error: bus clear fail to set run state\n");
-               return ret;
+       dev_info(ctrl->dev, "Executing bus recovery procedure (9 clk pulse)\n");
+       disable_irq(ctrl->rsrcs.irq);
+       if (!(status & (I2C_STATUS_BUS_ACTIVE)) ||
+               (status & (I2C_STATUS_BUS_MASTER))) {
+               dev_warn(ctrl->dev, "unexpected i2c recovery call:0x%x\n",
+                                   status);
+               goto recovery_exit;
        }
 
-       /*
-        * call i2c_msm_qup_xfer_init_run_state() to set clock dividers.
-        * the dividers are necessary for bus clear.
-        */
-       i2c_msm_qup_xfer_init_run_state(ctrl);
+       gpio_clk = of_get_named_gpio(ctrl->adapter.dev.of_node, "qcom,i2c-clk",
+                                    0);
+       gpio_dat = of_get_named_gpio(ctrl->adapter.dev.of_node, "qcom,i2c-dat",
+                                    0);
 
-       writel_relaxed(0x1, ctrl->rsrcs.base + QUP_I2C_MASTER_BUS_CLR);
+       if (gpio_clk < 0 || gpio_dat < 0) {
+               dev_warn(ctrl->dev, "SW bigbang err: i2c gpios not known\n");
+               goto recovery_exit;
+       }
 
-       /*
-        * wait for recovery (9 clock pulse cycles) to complete.
-        * min_time = 9 clock *10  (1000% margin)
-        * max_time = 10* min_time
-        */
-       min_sleep_usec =
-         max_t(ulong, (9 * 10 * USEC_PER_SEC) / ctrl->rsrcs.clk_freq_out, 100);
+       bitbang = i2c_msm_rsrcs_gpio_get_state(ctrl, "i2c_bitbang");
+       if (bitbang)
+               ret = pinctrl_select_state(ctrl->rsrcs.pinctrl, bitbang);
+       if (!bitbang || ret) {
+               dev_err(ctrl->dev, "GPIO pins have no bitbang setting\n");
+               goto recovery_exit;
+       }
+       for (i = 0; i < 10; i++) {
+               if (gpio_get_value(gpio_dat) && gpio_clk_status)
+                       break;
+               gpio_direction_output(gpio_clk, 0);
+               udelay(5);
+               gpio_direction_output(gpio_dat, 0);
+               udelay(5);
+               gpio_direction_input(gpio_clk);
+               udelay(5);
+               if (!gpio_get_value(gpio_clk))
+                       udelay(20);
+               if (!gpio_get_value(gpio_clk))
+                       usleep_range(10000, 10001);
+               gpio_clk_status = gpio_get_value(gpio_clk);
+               gpio_direction_input(gpio_dat);
+               udelay(5);
+       }
 
-       usleep_range(min_sleep_usec, min_sleep_usec * 10);
-       return ret;
-}
+       i2c_msm_pm_pinctrl_state(ctrl, true);
+       udelay(10);
 
-static int qup_i2c_recover_bus_busy(struct i2c_msm_ctrl *ctrl)
-{
-       u32 bus_clr, bus_active, status;
-       int retry = 0;
-       dev_info(ctrl->dev, "Executing bus recovery procedure (9 clk pulse)\n");
+       status = readl_relaxed(ctrl->rsrcs.base + QUP_I2C_STATUS);
+       if (!(status & I2C_STATUS_BUS_ACTIVE)) {
+               dev_info(ctrl->dev,
+                       "Bus busy cleared after %d clock cycles, status %x\n",
+                        i, status);
+               goto recovery_exit;
+       }
 
-       do {
-               qup_i2c_try_recover_bus_busy(ctrl);
-               bus_clr    = readl_relaxed(ctrl->rsrcs.base +
-                                                       QUP_I2C_MASTER_BUS_CLR);
-               status     = readl_relaxed(ctrl->rsrcs.base + QUP_I2C_STATUS);
-               bus_active = status & I2C_STATUS_BUS_ACTIVE;
-               if (++retry >= I2C_QUP_MAX_BUS_RECOVERY_RETRY)
-                       break;
-       } while (bus_clr || bus_active);
+       dev_warn(ctrl->dev, "Bus still busy, status %x\n", status);
 
-       dev_info(ctrl->dev, "Bus recovery %s after %d retries\n",
-               (bus_clr || bus_active) ? "fail" : "success", retry);
-       return 0;
+recovery_exit:
+       enable_irq(ctrl->rsrcs.irq);
 }
 
 static int i2c_msm_qup_post_xfer(struct i2c_msm_ctrl *ctrl, int err)
@@ -1984,7 +2000,7 @@ static int i2c_msm_qup_post_xfer(struct i2c_msm_ctrl *ctrl, int err)
                    (ctrl->xfer.err == I2C_MSM_ERR_BUS_ERR)  ||
                    (ctrl->xfer.err == I2C_MSM_ERR_TIMEOUT)) {
                        if (i2c_msm_qup_slv_holds_bus(ctrl))
-                               qup_i2c_recover_bus_busy(ctrl);
+                               qup_i2c_recover_bit_bang(ctrl);
 
                        /* do not generalize error to EIO if its already set */
                        if (!err)
index 90e3229..42c25ae 100644 (file)
@@ -56,9 +56,7 @@ EXPORT_SYMBOL_GPL(__i2c_first_dynamic_bus_num);
  * The board info passed can safely be __initdata, but be careful of embedded
  * pointers (for platform_data, functions, etc) since that won't be copied.
  */
-int __init
-i2c_register_board_info(int busnum,
-       struct i2c_board_info const *info, unsigned len)
+int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len)
 {
        int status;
 
index 4732dfc..331adc5 100644 (file)
@@ -17,6 +17,7 @@ config I7300_IDLE_IOAT_CHANNEL
 
 config I7300_IDLE
        tristate "Intel chipset idle memory power saving driver"
+       depends on PCI
        select I7300_IDLE_IOAT_CHANNEL
        help
          Enable memory power savings when idle with certain Intel server
index f684fe3..64799ad 100644 (file)
@@ -44,7 +44,7 @@ struct axp288_adc_info {
        struct regmap *regmap;
 };
 
-static const struct iio_chan_spec const axp288_adc_channels[] = {
+static const struct iio_chan_spec axp288_adc_channels[] = {
        {
                .indexed = 1,
                .type = IIO_TEMP,
index e354358..b6c9a37 100644 (file)
@@ -626,6 +626,7 @@ struct rdma_cm_id *rdma_create_id(struct net *net,
        INIT_LIST_HEAD(&id_priv->mc_list);
        get_random_bytes(&id_priv->seq_num, sizeof id_priv->seq_num);
        id_priv->id.route.addr.dev_addr.net = get_net(net);
+       id_priv->seq_num &= 0x00ffffff;
 
        return &id_priv->id;
 }
index 58fce17..337b1a5 100644 (file)
@@ -809,10 +809,9 @@ static int c4iw_rdev_open(struct c4iw_rdev *rdev)
             rdev->lldi.vr->qp.size,
             rdev->lldi.vr->cq.start,
             rdev->lldi.vr->cq.size);
-       PDBG("udb len 0x%x udb base %p db_reg %p gts_reg %p "
+       PDBG("udb %pR db_reg %p gts_reg %p "
             "qpmask 0x%x cqmask 0x%x\n",
-            (unsigned)pci_resource_len(rdev->lldi.pdev, 2),
-            (void *)pci_resource_start(rdev->lldi.pdev, 2),
+               &rdev->lldi.pdev->resource[2],
             rdev->lldi.db_reg, rdev->lldi.gts_reg,
             rdev->qpmask, rdev->cqmask);
 
index 8763fb8..5a2a0b5 100644 (file)
@@ -2483,9 +2483,8 @@ err_steer_free_bitmap:
        kfree(ibdev->ib_uc_qpns_bitmap);
 
 err_steer_qp_release:
-       if (ibdev->steering_support == MLX4_STEERING_MODE_DEVICE_MANAGED)
-               mlx4_qp_release_range(dev, ibdev->steer_qpn_base,
-                                     ibdev->steer_qpn_count);
+       mlx4_qp_release_range(dev, ibdev->steer_qpn_base,
+                             ibdev->steer_qpn_count);
 err_counter:
        for (i = 0; i < ibdev->num_ports; ++i)
                mlx4_ib_delete_counters_table(ibdev, &ibdev->counters_table[i]);
@@ -2586,11 +2585,9 @@ static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr)
                ibdev->iboe.nb.notifier_call = NULL;
        }
 
-       if (ibdev->steering_support == MLX4_STEERING_MODE_DEVICE_MANAGED) {
-               mlx4_qp_release_range(dev, ibdev->steer_qpn_base,
-                                     ibdev->steer_qpn_count);
-               kfree(ibdev->ib_uc_qpns_bitmap);
-       }
+       mlx4_qp_release_range(dev, ibdev->steer_qpn_base,
+                             ibdev->steer_qpn_count);
+       kfree(ibdev->ib_uc_qpns_bitmap);
 
        iounmap(ibdev->uar_map);
        for (p = 0; p < ibdev->num_ports; ++p)
index 9002298..3048ef3 100644 (file)
@@ -164,11 +164,18 @@ static void tca8418_read_keypad(struct tca8418_keypad *keypad_data)
        int error, col, row;
        u8 reg, state, code;
 
-       /* Initial read of the key event FIFO */
-       error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, &reg);
+       do {
+               error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, &reg);
+               if (error < 0) {
+                       dev_err(&keypad_data->client->dev,
+                               "unable to read REG_KEY_EVENT_A\n");
+                       break;
+               }
+
+               /* Assume that key code 0 signifies empty FIFO */
+               if (reg <= 0)
+                       break;
 
-       /* Assume that key code 0 signifies empty FIFO */
-       while (error >= 0 && reg > 0) {
                state = reg & KEY_EVENT_VALUE;
                code  = reg & KEY_EVENT_CODE;
 
@@ -184,11 +191,7 @@ static void tca8418_read_keypad(struct tca8418_keypad *keypad_data)
 
                /* Read for next loop */
                error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, &reg);
-       }
-
-       if (error < 0)
-               dev_err(&keypad_data->client->dev,
-                       "unable to read REG_KEY_EVENT_A\n");
+       } while (1);
 
        input_sync(input);
 }
index 93c9c3c..6f6cb35 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
  * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
- * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -472,7 +472,7 @@ static int synaptics_i2c_change_pipe_owner(
        struct synaptics_rmi4_data *rmi4_data, enum subsystem subsystem)
 {
        /*scm call descriptor */
-       struct scm_desc desc;
+       struct scm_desc desc = {0};
        struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
        int ret = 0;
 
@@ -3808,6 +3808,13 @@ static int synaptics_rmi4_probe(struct platform_device *pdev)
        }
 
        exp_data.workqueue = create_singlethread_workqueue("dsx_exp_workqueue");
+       if (exp_data.workqueue == NULL) {
+               dev_err(&pdev->dev,
+                       "%s: Failed to create workqueue\n", __func__);
+               retval = -ENOMEM;
+               goto err_create_wq;
+       }
+
        INIT_DELAYED_WORK(&exp_data.work, synaptics_rmi4_exp_fn_work);
        exp_data.rmi4_data = rmi4_data;
        exp_data.queue_work = true;
@@ -3859,10 +3866,9 @@ err_create_debugfs_file:
        debugfs_remove_recursive(rmi4_data->dir);
 err_create_debugfs_dir:
        cancel_delayed_work_sync(&exp_data.work);
-       if (exp_data.workqueue != NULL) {
-               flush_workqueue(exp_data.workqueue);
-               destroy_workqueue(exp_data.workqueue);
-       }
+       flush_workqueue(exp_data.workqueue);
+       destroy_workqueue(exp_data.workqueue);
+err_create_wq:
        synaptics_rmi4_irq_enable(rmi4_data, false);
        free_irq(rmi4_data->irq, rmi4_data);
 
index bb99258..5706327 100644 (file)
@@ -227,3 +227,11 @@ config IRQ_MXS
 config MSM_IRQ
        bool
        select IRQ_DOMAIN
+
+config GOLDFISH_PIC
+       bool "Goldfish programmable interrupt controller"
+       depends on MIPS && (GOLDFISH || COMPILE_TEST)
+       select IRQ_DOMAIN
+       help
+         Say yes here to enable Goldfish interrupt controller driver used
+         for Goldfish based virtual platforms.
index a9ac2b2..67aedf0 100644 (file)
@@ -56,3 +56,4 @@ obj-$(CONFIG_ARCH_SA1100)             += irq-sa11x0.o
 obj-$(CONFIG_INGENIC_IRQ)              += irq-ingenic.o
 obj-$(CONFIG_IMX_GPCV2)                        += irq-imx-gpcv2.o
 obj-$(CONFIG_QCOM_SHOW_RESUME_IRQ)       += msm_show_resume_irq.o
+obj-$(CONFIG_GOLDFISH_PIC)             += irq-goldfish-pic.o
diff --git a/drivers/irqchip/irq-goldfish-pic.c b/drivers/irqchip/irq-goldfish-pic.c
new file mode 100644 (file)
index 0000000..ac18926
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Driver for MIPS Goldfish Programmable Interrupt Controller.
+ *
+ * Author: Miodrag Dinic <miodrag.dinic@mips.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#define GFPIC_NR_IRQS                  32
+
+/* 8..39 Cascaded Goldfish PIC interrupts */
+#define GFPIC_IRQ_BASE                 8
+
+#define GFPIC_REG_IRQ_PENDING          0x04
+#define GFPIC_REG_IRQ_DISABLE_ALL      0x08
+#define GFPIC_REG_IRQ_DISABLE          0x0c
+#define GFPIC_REG_IRQ_ENABLE           0x10
+
+struct goldfish_pic_data {
+       void __iomem *base;
+       struct irq_domain *irq_domain;
+};
+
+static void goldfish_pic_cascade(struct irq_desc *desc)
+{
+       struct goldfish_pic_data *gfpic = irq_desc_get_handler_data(desc);
+       struct irq_chip *host_chip = irq_desc_get_chip(desc);
+       u32 pending, hwirq, virq;
+
+       chained_irq_enter(host_chip, desc);
+
+       pending = readl(gfpic->base + GFPIC_REG_IRQ_PENDING);
+       while (pending) {
+               hwirq = __fls(pending);
+               virq = irq_linear_revmap(gfpic->irq_domain, hwirq);
+               generic_handle_irq(virq);
+               pending &= ~(1 << hwirq);
+       }
+
+       chained_irq_exit(host_chip, desc);
+}
+
+static const struct irq_domain_ops goldfish_irq_domain_ops = {
+       .xlate = irq_domain_xlate_onecell,
+};
+
+static int __init goldfish_pic_of_init(struct device_node *of_node,
+                                      struct device_node *parent)
+{
+       struct goldfish_pic_data *gfpic;
+       struct irq_chip_generic *gc;
+       struct irq_chip_type *ct;
+       unsigned int parent_irq;
+       int ret = 0;
+
+       gfpic = kzalloc(sizeof(*gfpic), GFP_KERNEL);
+       if (!gfpic) {
+               ret = -ENOMEM;
+               goto out_err;
+       }
+
+       parent_irq = irq_of_parse_and_map(of_node, 0);
+       if (!parent_irq) {
+               pr_err("Failed to map parent IRQ!\n");
+               ret = -EINVAL;
+               goto out_free;
+       }
+
+       gfpic->base = of_iomap(of_node, 0);
+       if (!gfpic->base) {
+               pr_err("Failed to map base address!\n");
+               ret = -ENOMEM;
+               goto out_unmap_irq;
+       }
+
+       /* Mask interrupts. */
+       writel(1, gfpic->base + GFPIC_REG_IRQ_DISABLE_ALL);
+
+       gc = irq_alloc_generic_chip("GFPIC", 1, GFPIC_IRQ_BASE, gfpic->base,
+                                   handle_level_irq);
+       if (!gc) {
+               pr_err("Failed to allocate chip structures!\n");
+               ret = -ENOMEM;
+               goto out_iounmap;
+       }
+
+       ct = gc->chip_types;
+       ct->regs.enable = GFPIC_REG_IRQ_ENABLE;
+       ct->regs.disable = GFPIC_REG_IRQ_DISABLE;
+       ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
+       ct->chip.irq_mask = irq_gc_mask_disable_reg;
+
+       irq_setup_generic_chip(gc, IRQ_MSK(GFPIC_NR_IRQS), 0,
+                              IRQ_NOPROBE | IRQ_LEVEL, 0);
+
+       gfpic->irq_domain = irq_domain_add_legacy(of_node, GFPIC_NR_IRQS,
+                                                 GFPIC_IRQ_BASE, 0,
+                                                 &goldfish_irq_domain_ops,
+                                                 NULL);
+       if (!gfpic->irq_domain) {
+               pr_err("Failed to add irqdomain!\n");
+               ret = -ENOMEM;
+               goto out_iounmap;
+       }
+
+       irq_set_chained_handler_and_data(parent_irq,
+                                        goldfish_pic_cascade, gfpic);
+
+       pr_info("Successfully registered.\n");
+       return 0;
+
+out_iounmap:
+       iounmap(gfpic->base);
+out_unmap_irq:
+       irq_dispose_mapping(parent_irq);
+out_free:
+       kfree(gfpic);
+out_err:
+       pr_err("Failed to initialize! (errno = %d)\n", ret);
+       return ret;
+}
+
+IRQCHIP_DECLARE(google_gf_pic, "google,goldfish-pic", goldfish_pic_of_init);
index 6f1dbd5..3f79b3a 100644 (file)
@@ -181,7 +181,7 @@ void gic_write_cpu_compare(cycle_t cnt, int cpu)
 
        local_irq_save(flags);
 
-       gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), cpu);
+       gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), mips_cm_vp_id(cpu));
 
        if (mips_cm_is64) {
                gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE), cnt);
@@ -230,6 +230,14 @@ void gic_stop_count(void)
 
 #endif
 
+unsigned gic_read_local_vp_id(void)
+{
+       unsigned long ident;
+
+       ident = gic_read(GIC_REG(VPE_LOCAL, GIC_VP_IDENT));
+       return ident & GIC_VP_IDENT_VCNUM_MSK;
+}
+
 static bool gic_local_irq_is_routable(int intr)
 {
        u32 vpe_ctl;
@@ -534,7 +542,8 @@ static void gic_mask_local_irq_all_vpes(struct irq_data *d)
 
        spin_lock_irqsave(&gic_lock, flags);
        for (i = 0; i < gic_vpes; i++) {
-               gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i);
+               gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR),
+                         mips_cm_vp_id(i));
                gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << intr);
        }
        spin_unlock_irqrestore(&gic_lock, flags);
@@ -548,7 +557,8 @@ static void gic_unmask_local_irq_all_vpes(struct irq_data *d)
 
        spin_lock_irqsave(&gic_lock, flags);
        for (i = 0; i < gic_vpes; i++) {
-               gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i);
+               gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR),
+                         mips_cm_vp_id(i));
                gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_SMASK), 1 << intr);
        }
        spin_unlock_irqrestore(&gic_lock, flags);
@@ -665,7 +675,8 @@ static void __init gic_basic_init(void)
        for (i = 0; i < gic_vpes; i++) {
                unsigned int j;
 
-               gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i);
+               gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR),
+                         mips_cm_vp_id(i));
                for (j = 0; j < GIC_NUM_LOCAL_INTRS; j++) {
                        if (!gic_local_irq_is_routable(j))
                                continue;
@@ -710,7 +721,8 @@ static int gic_local_irq_domain_map(struct irq_domain *d, unsigned int virq,
        for (i = 0; i < gic_vpes; i++) {
                u32 val = GIC_MAP_TO_PIN_MSK | gic_cpu_pin;
 
-               gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i);
+               gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR),
+                         mips_cm_vp_id(i));
 
                switch (intr) {
                case GIC_LOCAL_INT_WD:
index 7b4ddf0..2d28530 100644 (file)
@@ -147,7 +147,7 @@ static word plci_remove_check(PLCI *);
 static void listen_check(DIVA_CAPI_ADAPTER *);
 static byte AddInfo(byte **, byte **, byte *, byte *);
 static byte getChannel(API_PARSE *);
-static void IndParse(PLCI *, word *, byte **, byte);
+static void IndParse(PLCI *, const word *, byte **, byte);
 static byte ie_compare(byte *, byte *);
 static word find_cip(DIVA_CAPI_ADAPTER *, byte *, byte *);
 static word CPN_filter_ok(byte *cpn, DIVA_CAPI_ADAPTER *, word);
@@ -4860,7 +4860,7 @@ static void sig_ind(PLCI *plci)
        /* included before the ESC_MSGTYPE and MAXPARMSIDS has to be incremented */
        /* SMSG is situated at the end because its 0 (for compatibility reasons */
        /* (see Info_Mask Bit 4, first IE. then the message type)           */
-       word parms_id[] =
+       static const word parms_id[] =
                {MAXPARMSIDS, CPN, 0xff, DSA, OSA, BC, LLC, HLC, ESC_CAUSE, DSP, DT, CHA,
                 UUI, CONG_RR, CONG_RNR, ESC_CHI, KEY, CHI, CAU, ESC_LAW,
                 RDN, RDX, CONN_NR, RIN, NI, CAI, ESC_CR,
@@ -4868,12 +4868,12 @@ static void sig_ind(PLCI *plci)
        /* 14 FTY repl by ESC_CHI */
        /* 18 PI  repl by ESC_LAW */
        /* removed OAD changed to 0xff for future use, OAD is multiIE now */
-       word multi_fac_id[] = {1, FTY};
-       word multi_pi_id[]  = {1, PI};
-       word multi_CiPN_id[]  = {1, OAD};
-       word multi_ssext_id[]  = {1, ESC_SSEXT};
+       static const word multi_fac_id[] = {1, FTY};
+       static const word multi_pi_id[]  = {1, PI};
+       static const word multi_CiPN_id[]  = {1, OAD};
+       static const word multi_ssext_id[]  = {1, ESC_SSEXT};
 
-       word multi_vswitch_id[]  = {1, ESC_VSWITCH};
+       static const word multi_vswitch_id[]  = {1, ESC_VSWITCH};
 
        byte *cau;
        word ncci;
@@ -8926,7 +8926,7 @@ static void listen_check(DIVA_CAPI_ADAPTER *a)
 /* functions for all parameters sent in INDs                        */
 /*------------------------------------------------------------------*/
 
-static void IndParse(PLCI *plci, word *parms_id, byte **parms, byte multiIEsize)
+static void IndParse(PLCI *plci, const word *parms_id, byte **parms, byte multiIEsize)
 {
        word ploc;            /* points to current location within packet */
        byte w;
index 358a574..46d957c 100644 (file)
@@ -718,7 +718,7 @@ icn_sendbuf(int channel, int ack, struct sk_buff *skb, icn_card *card)
                        return 0;
                if (card->sndcount[channel] > ICN_MAX_SQUEUE)
                        return 0;
-#warning TODO test headroom or use skb->nb to flag ACK
+               /* TODO test headroom or use skb->nb to flag ACK */
                nskb = skb_clone(skb, GFP_ATOMIC);
                if (nskb) {
                        /* Push ACK flag as one
index 3597ef4..09fc129 100644 (file)
@@ -441,6 +441,7 @@ static int identify_board(unsigned long rambase, unsigned int iobase)
        RspMessage rcvmsg;
        ReqMessage sndmsg;
        HWConfig_pl hwci;
+       void __iomem *rambase_sig = (void __iomem *)rambase + SIG_OFFSET;
        int x;
 
        pr_debug("Attempting to identify adapter @ 0x%lx io 0x%x\n",
@@ -481,7 +482,7 @@ static int identify_board(unsigned long rambase, unsigned int iobase)
         */
        outb(PRI_BASEPG_VAL, pgport);
        msleep_interruptible(1000);
-       sig = readl(rambase + SIG_OFFSET);
+       sig = readl(rambase_sig);
        pr_debug("Looking for a signature, got 0x%lx\n", sig);
        if (sig == SIGNATURE)
                return PRI_BOARD;
@@ -491,7 +492,7 @@ static int identify_board(unsigned long rambase, unsigned int iobase)
         */
        outb(BRI_BASEPG_VAL, pgport);
        msleep_interruptible(1000);
-       sig = readl(rambase + SIG_OFFSET);
+       sig = readl(rambase_sig);
        pr_debug("Looking for a signature, got 0x%lx\n", sig);
        if (sig == SIGNATURE)
                return BRI_BOARD;
@@ -501,7 +502,7 @@ static int identify_board(unsigned long rambase, unsigned int iobase)
        /*
         * Try to spot a card
         */
-       sig = readl(rambase + SIG_OFFSET);
+       sig = readl(rambase_sig);
        pr_debug("Looking for a signature, got 0x%lx\n", sig);
        if (sig != SIGNATURE)
                return -1;
index f7f560f..f002d2c 100644 (file)
@@ -974,7 +974,8 @@ static void dec_pending(struct dm_io *io, int error)
                } else {
                        /* done with normal IO or empty flush */
                        trace_block_bio_complete(md->queue, bio, io_error);
-                       bio->bi_error = io_error;
+                       if (io_error)
+                               bio->bi_error = io_error;
                        bio_endio(bio);
                }
        }
index 1cd8192..3a9685f 100644 (file)
@@ -1028,8 +1028,9 @@ static int super_90_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor
         * (not needed for Linear and RAID0 as metadata doesn't
         * record this size)
         */
-       if (rdev->sectors >= (2ULL << 32) && sb->level >= 1)
-               rdev->sectors = (2ULL << 32) - 2;
+       if (IS_ENABLED(CONFIG_LBDAF) && (u64)rdev->sectors >= (2ULL << 32) &&
+           sb->level >= 1)
+               rdev->sectors = (sector_t)(2ULL << 32) - 2;
 
        if (rdev->sectors < ((sector_t)sb->size) * 2 && sb->level >= 1)
                /* "this cannot possibly happen" ... */
@@ -1322,8 +1323,9 @@ super_90_rdev_size_change(struct md_rdev *rdev, sector_t num_sectors)
        /* Limit to 4TB as metadata cannot record more than that.
         * 4TB == 2^32 KB, or 2*2^32 sectors.
         */
-       if (num_sectors >= (2ULL << 32) && rdev->mddev->level >= 1)
-               num_sectors = (2ULL << 32) - 2;
+       if (IS_ENABLED(CONFIG_LBDAF) && (u64)num_sectors >= (2ULL << 32) &&
+           rdev->mddev->level >= 1)
+               num_sectors = (sector_t)(2ULL << 32) - 2;
        md_super_write(rdev->mddev, rdev, rdev->sb_start, rdev->sb_size,
                       rdev->sb_page);
        md_super_wait(rdev->mddev);
index 9c59f43..f595640 100644 (file)
@@ -38,7 +38,7 @@ static int flexcop_fe_request_firmware(struct dvb_frontend *fe,
 #endif
 
 /* lnb control */
-#if FE_SUPPORTED(MT312) || FE_SUPPORTED(STV0299)
+#if (FE_SUPPORTED(MT312) || FE_SUPPORTED(STV0299)) && FE_SUPPORTED(PLL)
 static int flexcop_set_voltage(struct dvb_frontend *fe,
                               enum fe_sec_voltage voltage)
 {
@@ -68,7 +68,7 @@ static int flexcop_set_voltage(struct dvb_frontend *fe,
 #endif
 
 #if FE_SUPPORTED(S5H1420) || FE_SUPPORTED(STV0299) || FE_SUPPORTED(MT312)
-static int flexcop_sleep(struct dvb_frontend* fe)
+static int __maybe_unused flexcop_sleep(struct dvb_frontend* fe)
 {
        struct flexcop_device *fc = fe->dvb->priv;
        if (fc->fe_sleep)
index 7979e5d..7ca3593 100644 (file)
@@ -369,7 +369,7 @@ static int ts2020_read_tuner_gain(struct dvb_frontend *fe, unsigned v_agc,
                gain2 = clamp_t(long, gain2, 0, 13);
                v_agc = clamp_t(long, v_agc, 400, 1100);
 
-               *_gain = -(gain1 * 2330 +
+               *_gain = -((__s64)gain1 * 2330 +
                           gain2 * 3500 +
                           v_agc * 24 / 10 * 10 +
                           10000);
@@ -387,7 +387,7 @@ static int ts2020_read_tuner_gain(struct dvb_frontend *fe, unsigned v_agc,
                gain3 = clamp_t(long, gain3, 0, 6);
                v_agc = clamp_t(long, v_agc, 600, 1600);
 
-               *_gain = -(gain1 * 2650 +
+               *_gain = -((__s64)gain1 * 2650 +
                           gain2 * 3380 +
                           gain3 * 2850 +
                           v_agc * 176 / 100 * 10 -
index d0ad6a2..5ac2bab 100644 (file)
@@ -421,6 +421,7 @@ static int s5k6aa_set_ahb_address(struct i2c_client *client)
 
 /**
  * s5k6aa_configure_pixel_clock - apply ISP main clock/PLL configuration
+ * @s5k6aa: pointer to &struct s5k6aa describing the device
  *
  * Configure the internal ISP PLL for the required output frequency.
  * Locking: called with s5k6aa.lock mutex held.
@@ -669,6 +670,7 @@ static int s5k6aa_set_input_params(struct s5k6aa *s5k6aa)
 
 /**
  * s5k6aa_configure_video_bus - configure the video output interface
+ * @s5k6aa: pointer to &struct s5k6aa describing the device
  * @bus_type: video bus type: parallel or MIPI-CSI
  * @nlanes: number of MIPI lanes to be used (MIPI-CSI only)
  *
@@ -724,6 +726,8 @@ static int s5k6aa_new_config_sync(struct i2c_client *client, int timeout,
 
 /**
  * s5k6aa_set_prev_config - write user preview register set
+ * @s5k6aa: pointer to &struct s5k6aa describing the device
+ * @preset: s5kaa preset to be applied
  *
  * Configure output resolution and color fromat, pixel clock
  * frequency range, device frame rate type and frame period range.
@@ -777,6 +781,7 @@ static int s5k6aa_set_prev_config(struct s5k6aa *s5k6aa,
 
 /**
  * s5k6aa_initialize_isp - basic ISP MCU initialization
+ * @sd: pointer to V4L2 sub-device descriptor
  *
  * Configure AHB addresses for registers read/write; configure PLLs for
  * required output pixel clock. The ISP power supply needs to be already
index 9ef5baa..ea2777e 100644 (file)
@@ -197,57 +197,61 @@ static void i2c_wr(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n)
        }
 }
 
-static u8 i2c_rd8(struct v4l2_subdev *sd, u16 reg)
+static noinline u32 i2c_rdreg(struct v4l2_subdev *sd, u16 reg, u32 n)
 {
-       u8 val;
+       __le32 val = 0;
 
-       i2c_rd(sd, reg, &val, 1);
+       i2c_rd(sd, reg, (u8 __force *)&val, n);
 
-       return val;
+       return le32_to_cpu(val);
+}
+
+static noinline void i2c_wrreg(struct v4l2_subdev *sd, u16 reg, u32 val, u32 n)
+{
+       __le32 raw = cpu_to_le32(val);
+
+       i2c_wr(sd, reg, (u8 __force *)&raw, n);
+}
+
+static u8 i2c_rd8(struct v4l2_subdev *sd, u16 reg)
+{
+       return i2c_rdreg(sd, reg, 1);
 }
 
 static void i2c_wr8(struct v4l2_subdev *sd, u16 reg, u8 val)
 {
-       i2c_wr(sd, reg, &val, 1);
+       i2c_wrreg(sd, reg, val, 1);
 }
 
 static void i2c_wr8_and_or(struct v4l2_subdev *sd, u16 reg,
                u8 mask, u8 val)
 {
-       i2c_wr8(sd, reg, (i2c_rd8(sd, reg) & mask) | val);
+       i2c_wrreg(sd, reg, (i2c_rdreg(sd, reg, 2) & mask) | val, 2);
 }
 
 static u16 i2c_rd16(struct v4l2_subdev *sd, u16 reg)
 {
-       u16 val;
-
-       i2c_rd(sd, reg, (u8 *)&val, 2);
-
-       return val;
+       return i2c_rdreg(sd, reg, 2);
 }
 
 static void i2c_wr16(struct v4l2_subdev *sd, u16 reg, u16 val)
 {
-       i2c_wr(sd, reg, (u8 *)&val, 2);
+       i2c_wrreg(sd, reg, val, 2);
 }
 
 static void i2c_wr16_and_or(struct v4l2_subdev *sd, u16 reg, u16 mask, u16 val)
 {
-       i2c_wr16(sd, reg, (i2c_rd16(sd, reg) & mask) | val);
+       i2c_wrreg(sd, reg, (i2c_rdreg(sd, reg, 2) & mask) | val, 2);
 }
 
 static u32 i2c_rd32(struct v4l2_subdev *sd, u16 reg)
 {
-       u32 val;
-
-       i2c_rd(sd, reg, (u8 *)&val, 4);
-
-       return val;
+       return i2c_rdreg(sd, reg, 4);
 }
 
 static void i2c_wr32(struct v4l2_subdev *sd, u16 reg, u32 val)
 {
-       i2c_wr(sd, reg, (u8 *)&val, 4);
+       i2c_wrreg(sd, reg, val, 4);
 }
 
 /* --------------- STATUS --------------- */
@@ -1240,7 +1244,7 @@ static int tc358743_g_register(struct v4l2_subdev *sd,
 
        reg->size = tc358743_get_reg_size(reg->reg);
 
-       i2c_rd(sd, reg->reg, (u8 *)&reg->val, reg->size);
+       reg->val = i2c_rdreg(sd, reg->reg, reg->size);
 
        return 0;
 }
@@ -1266,7 +1270,7 @@ static int tc358743_s_register(struct v4l2_subdev *sd,
            reg->reg == BCAPS)
                return 0;
 
-       i2c_wr(sd, (u16)reg->reg, (u8 *)&reg->val,
+       i2c_wrreg(sd, (u16)reg->reg, reg->val,
                        tc358743_get_reg_size(reg->reg));
 
        return 0;
index afba738..353b747 100644 (file)
@@ -550,7 +550,7 @@ static int camera_v4l2_fh_open(struct file *filep)
 {
        struct msm_video_device *pvdev = video_drvdata(filep);
        struct camera_v4l2_private *sp;
-       unsigned int stream_id;
+       unsigned long stream_id;
 
        sp = kzalloc(sizeof(*sp), GFP_KERNEL);
        if (!sp)
@@ -627,7 +627,7 @@ static int camera_v4l2_open(struct file *filep)
        int rc = 0;
        struct v4l2_event event;
        struct msm_video_device *pvdev = video_drvdata(filep);
-       unsigned int opn_idx, idx;
+       unsigned long opn_idx, idx;
 
        if (WARN_ON(!pvdev))
                return -EIO;
index 422c7a5..2dbf02e 100644 (file)
@@ -540,7 +540,7 @@ static int _sde_rotator_secure_session_ctrl(bool enable)
 {
        struct sde_rot_data_type *mdata = sde_rot_get_mdata();
        uint32_t sid_info;
-       struct scm_desc desc;
+       struct scm_desc desc = {0};
        unsigned int resp = 0;
        int ret = 0;
 
index f92687f..7ae3a1e 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1135,8 +1135,7 @@ static void handle_event_change(enum hal_command_response cmd, void *data)
        case HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES:
                rc = msm_comm_g_ctrl_for_id(inst,
                        V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER);
-               if (!is_thumbnail_session(inst) &&
-                       (IS_ERR_VALUE(rc) || rc == false))
+               if ((IS_ERR_VALUE(rc) || rc == false))
                        event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
                else
                        event = V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
index bda29bc..2f74a5a 100644 (file)
@@ -405,3 +405,7 @@ void soc_camera_calc_client_output(struct soc_camera_device *icd,
        mf->height = soc_camera_shift_scale(rect->height, shift, scale_v);
 }
 EXPORT_SYMBOL(soc_camera_calc_client_output);
+
+MODULE_DESCRIPTION("soc-camera scaling-cropping functions");
+MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
+MODULE_LICENSE("GPL");
index a7a8452..c1ce8d3 100644 (file)
@@ -410,9 +410,11 @@ static int r820t_write(struct r820t_priv *priv, u8 reg, const u8 *val,
        return 0;
 }
 
-static int r820t_write_reg(struct r820t_priv *priv, u8 reg, u8 val)
+static inline int r820t_write_reg(struct r820t_priv *priv, u8 reg, u8 val)
 {
-       return r820t_write(priv, reg, &val, 1);
+       u8 tmp = val; /* work around GCC PR81715 with asan-stack=1 */
+
+       return r820t_write(priv, reg, &tmp, 1);
 }
 
 static int r820t_read_cache_reg(struct r820t_priv *priv, int reg)
@@ -425,17 +427,18 @@ static int r820t_read_cache_reg(struct r820t_priv *priv, int reg)
                return -EINVAL;
 }
 
-static int r820t_write_reg_mask(struct r820t_priv *priv, u8 reg, u8 val,
+static inline int r820t_write_reg_mask(struct r820t_priv *priv, u8 reg, u8 val,
                                u8 bit_mask)
 {
+       u8 tmp = val;
        int rc = r820t_read_cache_reg(priv, reg);
 
        if (rc < 0)
                return rc;
 
-       val = (rc & ~bit_mask) | (val & bit_mask);
+       tmp = (rc & ~bit_mask) | (tmp & bit_mask);
 
-       return r820t_write(priv, reg, &val, 1);
+       return r820t_write(priv, reg, &tmp, 1);
 }
 
 static int r820t_read(struct r820t_priv *priv, u8 reg, u8 *val, int len)
index 3721ee6..09c9784 100644 (file)
@@ -503,18 +503,23 @@ static int lme2510_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
 
 static int lme2510_return_status(struct dvb_usb_device *d)
 {
-       int ret = 0;
+       int ret;
        u8 *data;
 
-       data = kzalloc(10, GFP_KERNEL);
+       data = kzalloc(6, GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
-       ret |= usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
-                       0x06, 0x80, 0x0302, 0x00, data, 0x0006, 200);
-       info("Firmware Status: %x (%x)", ret , data[2]);
+       ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
+                             0x06, 0x80, 0x0302, 0x00,
+                             data, 0x6, 200);
+       if (ret != 6)
+               ret = -EINVAL;
+       else
+               ret = data[2];
+
+       info("Firmware Status: %6ph", data);
 
-       ret = (ret < 0) ? -ENODEV : data[2];
        kfree(data);
        return ret;
 }
@@ -1078,8 +1083,6 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
 
                if (adap->fe[0]) {
                        info("FE Found M88RS2000");
-                       dvb_attach(ts2020_attach, adap->fe[0], &ts2020_config,
-                                       &d->i2c_adap);
                        st->i2c_tuner_gate_w = 5;
                        st->i2c_tuner_gate_r = 5;
                        st->i2c_tuner_addr = 0x60;
@@ -1145,17 +1148,18 @@ static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap)
                        ret = st->tuner_config;
                break;
        case TUNER_RS2000:
-               ret = st->tuner_config;
+               if (dvb_attach(ts2020_attach, adap->fe[0],
+                              &ts2020_config, &d->i2c_adap))
+                       ret = st->tuner_config;
                break;
        default:
                break;
        }
 
-       if (ret)
+       if (ret) {
                info("TUN Found %s tuner", tun_msg[ret]);
-       else {
-               info("TUN No tuner found --- resetting device");
-               lme_coldreset(d);
+       } else {
+               info("TUN No tuner found");
                return -ENODEV;
        }
 
@@ -1199,6 +1203,7 @@ static int lme2510_get_adapter_count(struct dvb_usb_device *d)
 static int lme2510_identify_state(struct dvb_usb_device *d, const char **name)
 {
        struct lme2510_state *st = d->priv;
+       int status;
 
        usb_reset_configuration(d->udev);
 
@@ -1207,12 +1212,16 @@ static int lme2510_identify_state(struct dvb_usb_device *d, const char **name)
 
        st->dvb_usb_lme2510_firmware = dvb_usb_lme2510_firmware;
 
-       if (lme2510_return_status(d) == 0x44) {
+       status = lme2510_return_status(d);
+       if (status == 0x44) {
                *name = lme_firmware_switch(d, 0);
                return COLD;
        }
 
-       return 0;
+       if (status != 0x47)
+               return -EINVAL;
+
+       return WARM;
 }
 
 static int lme2510_get_stream_config(struct dvb_frontend *fe, u8 *ts_type,
index ab71511..d00b27e 100644 (file)
@@ -818,6 +818,8 @@ static int dvico_bluebird_xc2028_callback(void *ptr, int component,
        case XC2028_RESET_CLK:
                deb_info("%s: XC2028_RESET_CLK %d\n", __func__, arg);
                break;
+       case XC2028_I2C_FLUSH:
+               break;
        default:
                deb_info("%s: unknown command %d, arg %d\n", __func__,
                         command, arg);
index 7df0707..38c0328 100644 (file)
@@ -431,6 +431,7 @@ static int stk7700ph_xc3028_callback(void *ptr, int component,
                state->dib7000p_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
                break;
        case XC2028_RESET_CLK:
+       case XC2028_I2C_FLUSH:
                break;
        default:
                err("%s: unknown command %d, arg %d\n", __func__,
index e382210..75323f5 100644 (file)
@@ -11,7 +11,7 @@ config VIDEO_EM28XX_V4L2
        select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT
        select VIDEO_TVP5150 if MEDIA_SUBDRV_AUTOSELECT
        select VIDEO_MSP3400 if MEDIA_SUBDRV_AUTOSELECT
-       select VIDEO_MT9V011 if MEDIA_SUBDRV_AUTOSELECT
+       select VIDEO_MT9V011 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_CAMERA_SUPPORT
 
        ---help---
          This is a video4linux driver for Empia 28xx based TV cards.
index 95a3af6..af1d024 100644 (file)
@@ -11,7 +11,7 @@ config VIDEO_GO7007
        select VIDEO_TW2804 if MEDIA_SUBDRV_AUTOSELECT
        select VIDEO_TW9903 if MEDIA_SUBDRV_AUTOSELECT
        select VIDEO_TW9906 if MEDIA_SUBDRV_AUTOSELECT
-       select VIDEO_OV7640 if MEDIA_SUBDRV_AUTOSELECT
+       select VIDEO_OV7640 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_CAMERA_SUPPORT
        select VIDEO_UDA1342 if MEDIA_SUBDRV_AUTOSELECT
        ---help---
          This is a video4linux driver for the WIS GO7007 MPEG
index 3fc6419..08f0ca7 100644 (file)
@@ -273,7 +273,9 @@ static int hdpvr_probe(struct usb_interface *interface,
        struct hdpvr_device *dev;
        struct usb_host_interface *iface_desc;
        struct usb_endpoint_descriptor *endpoint;
+#if IS_ENABLED(CONFIG_I2C)
        struct i2c_client *client;
+#endif
        size_t buffer_size;
        int i;
        int retval = -ENOMEM;
index 58f23bc..299750e 100644 (file)
@@ -1119,8 +1119,10 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
 
        return 0;
 
+#ifdef CONFIG_USB_PWC_INPUT_EVDEV
 err_video_unreg:
        video_unregister_device(&pdev->vdev);
+#endif
 err_unregister_v4l2_dev:
        v4l2_device_unregister(&pdev->v4l2_dev);
 err_free_controls:
index 9beece0..29b3436 100644 (file)
@@ -37,7 +37,6 @@ config VIDEO_PCI_SKELETON
 # Used by drivers that need tuner.ko
 config VIDEO_TUNER
        tristate
-       depends on MEDIA_TUNER
 
 # Used by drivers that need v4l2-mem2mem.ko
 config V4L2_MEM2MEM_DEV
index 18045a7..dc3dd13 100644 (file)
 #include <linux/videodev2.h>
 #include <linux/v4l2-subdev.h>
 #include <media/v4l2-dev.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
 #include <media/v4l2-ioctl.h>
 
+/* Use the same argument order as copy_in_user */
+#define assign_in_user(to, from)                                       \
+({                                                                     \
+       typeof(*from) __assign_tmp;                                     \
+                                                                       \
+       get_user(__assign_tmp, from) || put_user(__assign_tmp, to);     \
+})
+
 static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        long ret = -ENOIOCTLCMD;
@@ -33,131 +43,88 @@ static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
 struct v4l2_clip32 {
        struct v4l2_rect        c;
-       compat_caddr_t          next;
+       compat_caddr_t          next;
 };
 
 struct v4l2_window32 {
        struct v4l2_rect        w;
-       __u32                   field;  /* enum v4l2_field */
+       __u32                   field;  /* enum v4l2_field */
        __u32                   chromakey;
        compat_caddr_t          clips; /* actually struct v4l2_clip32 * */
        __u32                   clipcount;
        compat_caddr_t          bitmap;
+       __u8                    global_alpha;
 };
 
-static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
-{
-       if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) ||
-               copy_from_user(&kp->w, &up->w, sizeof(up->w)) ||
-               get_user(kp->field, &up->field) ||
-               get_user(kp->chromakey, &up->chromakey) ||
-               get_user(kp->clipcount, &up->clipcount))
-                       return -EFAULT;
-       if (kp->clipcount > 2048)
-               return -EINVAL;
-       if (kp->clipcount) {
-               struct v4l2_clip32 __user *uclips;
-               struct v4l2_clip __user *kclips;
-               int n = kp->clipcount;
-               compat_caddr_t p;
-
-               if (get_user(p, &up->clips))
-                       return -EFAULT;
-               uclips = compat_ptr(p);
-               kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip));
-               kp->clips = kclips;
-               while (--n >= 0) {
-                       if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
-                               return -EFAULT;
-                       if (put_user(n ? kclips + 1 : NULL, &kclips->next))
-                               return -EFAULT;
-                       uclips += 1;
-                       kclips += 1;
-               }
-       } else
-               kp->clips = NULL;
-       return 0;
-}
-
-static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
+static int get_v4l2_window32(struct v4l2_window __user *kp,
+                            struct v4l2_window32 __user *up,
+                            void __user *aux_buf, u32 aux_space)
 {
-       if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) ||
-               put_user(kp->field, &up->field) ||
-               put_user(kp->chromakey, &up->chromakey) ||
-               put_user(kp->clipcount, &up->clipcount))
-                       return -EFAULT;
-       return 0;
-}
-
-static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
-{
-       if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format)))
-               return -EFAULT;
-       return 0;
-}
-
-static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp,
-                               struct v4l2_pix_format_mplane __user *up)
-{
-       if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane)))
-               return -EFAULT;
-       return 0;
-}
-
-static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
-{
-       if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format)))
+       struct v4l2_clip32 __user *uclips;
+       struct v4l2_clip __user *kclips;
+       compat_caddr_t p;
+       u32 clipcount;
+
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+           copy_in_user(&kp->w, &up->w, sizeof(up->w)) ||
+           assign_in_user(&kp->field, &up->field) ||
+           assign_in_user(&kp->chromakey, &up->chromakey) ||
+           assign_in_user(&kp->global_alpha, &up->global_alpha) ||
+           get_user(clipcount, &up->clipcount) ||
+           put_user(clipcount, &kp->clipcount))
                return -EFAULT;
-       return 0;
-}
+       if (clipcount > 2048)
+               return -EINVAL;
+       if (!clipcount)
+               return put_user(NULL, &kp->clips);
 
-static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp,
-                               struct v4l2_pix_format_mplane __user *up)
-{
-       if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane)))
+       if (get_user(p, &up->clips))
                return -EFAULT;
-       return 0;
-}
-
-static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
-{
-       if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format)))
+       uclips = compat_ptr(p);
+       if (aux_space < clipcount * sizeof(*kclips))
                return -EFAULT;
-       return 0;
-}
-
-static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
-{
-       if (copy_to_user(up, kp, sizeof(struct v4l2_vbi_format)))
-               return -EFAULT;
-       return 0;
-}
-
-static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
-{
-       if (copy_from_user(kp, up, sizeof(struct v4l2_sliced_vbi_format)))
+       kclips = aux_buf;
+       if (put_user(kclips, &kp->clips))
                return -EFAULT;
-       return 0;
-}
 
-static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
-{
-       if (copy_to_user(up, kp, sizeof(struct v4l2_sliced_vbi_format)))
-               return -EFAULT;
+       while (clipcount--) {
+               if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
+                       return -EFAULT;
+               if (put_user(clipcount ? kclips + 1 : NULL, &kclips->next))
+                       return -EFAULT;
+               uclips++;
+               kclips++;
+       }
        return 0;
 }
 
-static inline int get_v4l2_sdr_format(struct v4l2_sdr_format *kp, struct v4l2_sdr_format __user *up)
+static int put_v4l2_window32(struct v4l2_window __user *kp,
+                            struct v4l2_window32 __user *up)
 {
-       if (copy_from_user(kp, up, sizeof(struct v4l2_sdr_format)))
+       struct v4l2_clip __user *kclips = kp->clips;
+       struct v4l2_clip32 __user *uclips;
+       compat_caddr_t p;
+       u32 clipcount;
+
+       if (copy_in_user(&up->w, &kp->w, sizeof(kp->w)) ||
+           assign_in_user(&up->field, &kp->field) ||
+           assign_in_user(&up->chromakey, &kp->chromakey) ||
+           assign_in_user(&up->global_alpha, &kp->global_alpha) ||
+           get_user(clipcount, &kp->clipcount) ||
+           put_user(clipcount, &up->clipcount))
                return -EFAULT;
-       return 0;
-}
+       if (!clipcount)
+               return 0;
 
-static inline int put_v4l2_sdr_format(struct v4l2_sdr_format *kp, struct v4l2_sdr_format __user *up)
-{
-       if (copy_to_user(up, kp, sizeof(struct v4l2_sdr_format)))
+       if (get_user(p, &up->clips))
                return -EFAULT;
+       uclips = compat_ptr(p);
+       while (clipcount--) {
+               if (copy_in_user(&uclips->c, &kclips->c, sizeof(uclips->c)))
+                       return -EFAULT;
+               uclips++;
+               kclips++;
+       }
        return 0;
 }
 
@@ -191,97 +158,158 @@ struct v4l2_create_buffers32 {
        __u32                   reserved[8];
 };
 
-static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+static int __bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size)
+{
+       u32 type;
+
+       if (get_user(type, &up->type))
+               return -EFAULT;
+
+       switch (type) {
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: {
+               u32 clipcount;
+
+               if (get_user(clipcount, &up->fmt.win.clipcount))
+                       return -EFAULT;
+               if (clipcount > 2048)
+                       return -EINVAL;
+               *size = clipcount * sizeof(struct v4l2_clip);
+               return 0;
+       }
+       default:
+               *size = 0;
+               return 0;
+       }
+}
+
+static int bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size)
 {
-       if (get_user(kp->type, &up->type))
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)))
                return -EFAULT;
+       return __bufsize_v4l2_format(up, size);
+}
+
+static int __get_v4l2_format32(struct v4l2_format __user *kp,
+                              struct v4l2_format32 __user *up,
+                              void __user *aux_buf, u32 aux_space)
+{
+       u32 type;
 
-       switch (kp->type) {
+       if (get_user(type, &up->type) || put_user(type, &kp->type))
+               return -EFAULT;
+
+       switch (type) {
        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
        case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-               return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
+               return copy_in_user(&kp->fmt.pix, &up->fmt.pix,
+                                   sizeof(kp->fmt.pix)) ? -EFAULT : 0;
        case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
        case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
-               return get_v4l2_pix_format_mplane(&kp->fmt.pix_mp,
-                                                 &up->fmt.pix_mp);
+               return copy_in_user(&kp->fmt.pix_mp, &up->fmt.pix_mp,
+                                   sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0;
        case V4L2_BUF_TYPE_VIDEO_OVERLAY:
        case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
-               return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
+               return get_v4l2_window32(&kp->fmt.win, &up->fmt.win,
+                                        aux_buf, aux_space);
        case V4L2_BUF_TYPE_VBI_CAPTURE:
        case V4L2_BUF_TYPE_VBI_OUTPUT:
-               return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
+               return copy_in_user(&kp->fmt.vbi, &up->fmt.vbi,
+                                   sizeof(kp->fmt.vbi)) ? -EFAULT : 0;
        case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
        case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
-               return get_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
+               return copy_in_user(&kp->fmt.sliced, &up->fmt.sliced,
+                                   sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
        case V4L2_BUF_TYPE_SDR_CAPTURE:
        case V4L2_BUF_TYPE_SDR_OUTPUT:
-               return get_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr);
+               return copy_in_user(&kp->fmt.sdr, &up->fmt.sdr,
+                                   sizeof(kp->fmt.sdr)) ? -EFAULT : 0;
        default:
-               pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
-                                                               kp->type);
                return -EINVAL;
        }
 }
 
-static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+static int get_v4l2_format32(struct v4l2_format __user *kp,
+                            struct v4l2_format32 __user *up,
+                            void __user *aux_buf, u32 aux_space)
 {
-       if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)))
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)))
                return -EFAULT;
-       return __get_v4l2_format32(kp, up);
+       return __get_v4l2_format32(kp, up, aux_buf, aux_space);
 }
 
-static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
+static int bufsize_v4l2_create(struct v4l2_create_buffers32 __user *up,
+                              u32 *size)
 {
-       if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_create_buffers32)) ||
-           copy_from_user(kp, up, offsetof(struct v4l2_create_buffers32, format)))
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)))
                return -EFAULT;
-       return __get_v4l2_format32(&kp->format, &up->format);
+       return __bufsize_v4l2_format(&up->format, size);
 }
 
-static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+static int get_v4l2_create32(struct v4l2_create_buffers __user *kp,
+                            struct v4l2_create_buffers32 __user *up,
+                            void __user *aux_buf, u32 aux_space)
 {
-       if (put_user(kp->type, &up->type))
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+           copy_in_user(kp, up,
+                        offsetof(struct v4l2_create_buffers32, format)))
+               return -EFAULT;
+       return __get_v4l2_format32(&kp->format, &up->format,
+                                  aux_buf, aux_space);
+}
+
+static int __put_v4l2_format32(struct v4l2_format __user *kp,
+                              struct v4l2_format32 __user *up)
+{
+       u32 type;
+
+       if (get_user(type, &kp->type))
                return -EFAULT;
 
-       switch (kp->type) {
+       switch (type) {
        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
        case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-               return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
+               return copy_in_user(&up->fmt.pix, &kp->fmt.pix,
+                                   sizeof(kp->fmt.pix)) ? -EFAULT : 0;
        case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
        case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
-               return put_v4l2_pix_format_mplane(&kp->fmt.pix_mp,
-                                                 &up->fmt.pix_mp);
+               return copy_in_user(&up->fmt.pix_mp, &kp->fmt.pix_mp,
+                                   sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0;
        case V4L2_BUF_TYPE_VIDEO_OVERLAY:
        case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
                return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
        case V4L2_BUF_TYPE_VBI_CAPTURE:
        case V4L2_BUF_TYPE_VBI_OUTPUT:
-               return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
+               return copy_in_user(&up->fmt.vbi, &kp->fmt.vbi,
+                                   sizeof(kp->fmt.vbi)) ? -EFAULT : 0;
        case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
        case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
-               return put_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
+               return copy_in_user(&up->fmt.sliced, &kp->fmt.sliced,
+                                   sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
        case V4L2_BUF_TYPE_SDR_CAPTURE:
        case V4L2_BUF_TYPE_SDR_OUTPUT:
-               return put_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr);
+               return copy_in_user(&up->fmt.sdr, &kp->fmt.sdr,
+                                   sizeof(kp->fmt.sdr)) ? -EFAULT : 0;
        default:
-               pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
-                                                               kp->type);
                return -EINVAL;
        }
 }
 
-static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+static int put_v4l2_format32(struct v4l2_format __user *kp,
+                            struct v4l2_format32 __user *up)
 {
-       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)))
+       if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
                return -EFAULT;
        return __put_v4l2_format32(kp, up);
 }
 
-static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
+static int put_v4l2_create32(struct v4l2_create_buffers __user *kp,
+                            struct v4l2_create_buffers32 __user *up)
 {
-       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) ||
-           copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format)) ||
-           copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved)))
+       if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+           copy_in_user(up, kp,
+                        offsetof(struct v4l2_create_buffers32, format)) ||
+           copy_in_user(up->reserved, kp->reserved, sizeof(kp->reserved)))
                return -EFAULT;
        return __put_v4l2_format32(&kp->format, &up->format);
 }
@@ -295,25 +323,28 @@ struct v4l2_standard32 {
        __u32                reserved[4];
 };
 
-static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
+static int get_v4l2_standard32(struct v4l2_standard __user *kp,
+                              struct v4l2_standard32 __user *up)
 {
        /* other fields are not set by the user, nor used by the driver */
-       if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) ||
-               get_user(kp->index, &up->index))
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+           assign_in_user(&kp->index, &up->index))
                return -EFAULT;
        return 0;
 }
 
-static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
+static int put_v4l2_standard32(struct v4l2_standard __user *kp,
+                              struct v4l2_standard32 __user *up)
 {
-       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) ||
-               put_user(kp->index, &up->index) ||
-               put_user(kp->id, &up->id) ||
-               copy_to_user(up->name, kp->name, 24) ||
-               copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) ||
-               put_user(kp->framelines, &up->framelines) ||
-               copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32)))
-                       return -EFAULT;
+       if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+           assign_in_user(&up->index, &kp->index) ||
+           assign_in_user(&up->id, &kp->id) ||
+           copy_in_user(up->name, kp->name, sizeof(up->name)) ||
+           copy_in_user(&up->frameperiod, &kp->frameperiod,
+                        sizeof(up->frameperiod)) ||
+           assign_in_user(&up->framelines, &kp->framelines) ||
+           copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+               return -EFAULT;
        return 0;
 }
 
@@ -352,144 +383,192 @@ struct v4l2_buffer32 {
        __u32                   reserved;
 };
 
-static int get_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32,
-                               enum v4l2_memory memory)
+static int get_v4l2_plane32(struct v4l2_plane __user *up,
+                           struct v4l2_plane32 __user *up32,
+                           enum v4l2_memory memory)
 {
-       void __user *up_pln;
-       compat_long_t p;
+       compat_ulong_t p;
 
        if (copy_in_user(up, up32, 2 * sizeof(__u32)) ||
-               copy_in_user(&up->data_offset, &up32->data_offset,
-                               sizeof(__u32)) ||
-               copy_in_user(up->reserved, up32->reserved,
-                               sizeof(up->reserved)) ||
-               copy_in_user(&up->length, &up32->length,
-                               sizeof(__u32)))
+           copy_in_user(&up->data_offset, &up32->data_offset,
+                        sizeof(up->data_offset)) ||
+           copy_in_user(up->reserved, up32->reserved,
+                        sizeof(up->reserved)) ||
+           copy_in_user(&up->length, &up32->length,
+                        sizeof(up->length)))
                return -EFAULT;
 
-       if (memory == V4L2_MEMORY_USERPTR) {
-               if (get_user(p, &up32->m.userptr))
-                       return -EFAULT;
-               up_pln = compat_ptr(p);
-               if (put_user((unsigned long)up_pln, &up->m.userptr))
+       switch (memory) {
+       case V4L2_MEMORY_MMAP:
+       case V4L2_MEMORY_OVERLAY:
+               if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset,
+                                sizeof(up32->m.mem_offset)))
                        return -EFAULT;
-       } else if (memory == V4L2_MEMORY_DMABUF) {
-               if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(int)))
+               break;
+       case V4L2_MEMORY_USERPTR:
+               if (get_user(p, &up32->m.userptr) ||
+                   put_user((unsigned long)compat_ptr(p), &up->m.userptr))
                        return -EFAULT;
-       } else {
-               if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset,
-                                       sizeof(__u32)))
+               break;
+       case V4L2_MEMORY_DMABUF:
+               if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(up32->m.fd)))
                        return -EFAULT;
+               break;
        }
 
        return 0;
 }
 
-static int put_v4l2_plane32(struct v4l2_plane __user *up, struct v4l2_plane32 __user *up32,
-                               enum v4l2_memory memory)
+static int put_v4l2_plane32(struct v4l2_plane __user *up,
+                           struct v4l2_plane32 __user *up32,
+                           enum v4l2_memory memory)
 {
+       unsigned long p;
+
        if (copy_in_user(up32, up, 2 * sizeof(__u32)) ||
-               copy_in_user(up32->reserved, up->reserved,
-                               sizeof(up32->reserved)) ||
-               copy_in_user(&up32->data_offset, &up->data_offset,
-                               sizeof(__u32)))
+           copy_in_user(up32->reserved, up->reserved,
+                        sizeof(up32->reserved)) ||
+           copy_in_user(&up32->data_offset, &up->data_offset,
+                        sizeof(up->data_offset)))
                return -EFAULT;
 
-       /* For MMAP, driver might've set up the offset, so copy it back.
-        * USERPTR stays the same (was userspace-provided), so no copying. */
-       if (memory == V4L2_MEMORY_MMAP)
+       switch (memory) {
+       case V4L2_MEMORY_MMAP:
+       case V4L2_MEMORY_OVERLAY:
                if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset,
-                                       sizeof(__u32)))
+                                sizeof(up->m.mem_offset)))
                        return -EFAULT;
-       /* For DMABUF, driver might've set up the fd, so copy it back. */
-       if (memory == V4L2_MEMORY_DMABUF)
-               if (copy_in_user(&up32->m.fd, &up->m.fd,
-                                       sizeof(int)))
+               break;
+       case V4L2_MEMORY_USERPTR:
+               if (get_user(p, &up->m.userptr) ||
+                   put_user((compat_ulong_t)ptr_to_compat((__force void *)p),
+                            &up32->m.userptr))
                        return -EFAULT;
-       if (memory == V4L2_MEMORY_USERPTR)
-               if (copy_in_user(&up32->m.userptr, &up->m.userptr,
-                                       sizeof(compat_long_t)))
+               break;
+       case V4L2_MEMORY_DMABUF:
+               if (copy_in_user(&up32->m.fd, &up->m.fd, sizeof(up->m.fd)))
                        return -EFAULT;
+               break;
+       }
+
+       return 0;
+}
+
+static int bufsize_v4l2_buffer(struct v4l2_buffer32 __user *up, u32 *size)
+{
+       u32 type;
+       u32 length;
+
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+           get_user(type, &up->type) ||
+           get_user(length, &up->length))
+               return -EFAULT;
+
+       if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
+               if (length > VIDEO_MAX_PLANES)
+                       return -EINVAL;
 
+               /*
+                * We don't really care if userspace decides to kill itself
+                * by passing a very big length value
+                */
+               *size = length * sizeof(struct v4l2_plane);
+       } else {
+               *size = 0;
+       }
        return 0;
 }
 
-static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
+static int get_v4l2_buffer32(struct v4l2_buffer __user *kp,
+                            struct v4l2_buffer32 __user *up,
+                            void __user *aux_buf, u32 aux_space)
 {
+       u32 type;
+       u32 length;
+       enum v4l2_memory memory;
        struct v4l2_plane32 __user *uplane32;
        struct v4l2_plane __user *uplane;
        compat_caddr_t p;
-       int num_planes;
        int ret;
 
-       if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) ||
-               get_user(kp->index, &up->index) ||
-               get_user(kp->type, &up->type) ||
-               get_user(kp->flags, &up->flags) ||
-               get_user(kp->memory, &up->memory) ||
-               get_user(kp->length, &up->length))
-                       return -EFAULT;
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+           assign_in_user(&kp->index, &up->index) ||
+           get_user(type, &up->type) ||
+           put_user(type, &kp->type) ||
+           assign_in_user(&kp->flags, &up->flags) ||
+           get_user(memory, &up->memory) ||
+           put_user(memory, &kp->memory) ||
+           get_user(length, &up->length) ||
+           put_user(length, &kp->length))
+               return -EFAULT;
 
-       if (V4L2_TYPE_IS_OUTPUT(kp->type))
-               if (get_user(kp->bytesused, &up->bytesused) ||
-                       get_user(kp->field, &up->field) ||
-                       get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
-                       get_user(kp->timestamp.tv_usec,
-                                       &up->timestamp.tv_usec))
+       if (V4L2_TYPE_IS_OUTPUT(type))
+               if (assign_in_user(&kp->bytesused, &up->bytesused) ||
+                   assign_in_user(&kp->field, &up->field) ||
+                   assign_in_user(&kp->timestamp.tv_sec,
+                                  &up->timestamp.tv_sec) ||
+                   assign_in_user(&kp->timestamp.tv_usec,
+                                  &up->timestamp.tv_usec))
                        return -EFAULT;
 
-       if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
-               num_planes = kp->length;
+       if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
+               u32 num_planes = length;
+
                if (num_planes == 0) {
-                       kp->m.planes = NULL;
-                       /* num_planes == 0 is legal, e.g. when userspace doesn't
-                        * need planes array on DQBUF*/
-                       return 0;
+                       /*
+                        * num_planes == 0 is legal, e.g. when userspace doesn't
+                        * need planes array on DQBUF
+                        */
+                       return put_user(NULL, &kp->m.planes);
                }
+               if (num_planes > VIDEO_MAX_PLANES)
+                       return -EINVAL;
 
                if (get_user(p, &up->m.planes))
                        return -EFAULT;
 
                uplane32 = compat_ptr(p);
                if (!access_ok(VERIFY_READ, uplane32,
-                               num_planes * sizeof(struct v4l2_plane32)))
+                              num_planes * sizeof(*uplane32)))
                        return -EFAULT;
 
-               /* We don't really care if userspace decides to kill itself
-                * by passing a very big num_planes value */
-               uplane = compat_alloc_user_space(num_planes *
-                                               sizeof(struct v4l2_plane));
-               kp->m.planes = (__force struct v4l2_plane *)uplane;
+               /*
+                * We don't really care if userspace decides to kill itself
+                * by passing a very big num_planes value
+                */
+               if (aux_space < num_planes * sizeof(*uplane))
+                       return -EFAULT;
+
+               uplane = aux_buf;
+               if (put_user((__force struct v4l2_plane *)uplane,
+                            &kp->m.planes))
+                       return -EFAULT;
 
-               while (--num_planes >= 0) {
-                       ret = get_v4l2_plane32(uplane, uplane32, kp->memory);
+               while (num_planes--) {
+                       ret = get_v4l2_plane32(uplane, uplane32, memory);
                        if (ret)
                                return ret;
-                       ++uplane;
-                       ++uplane32;
+                       uplane++;
+                       uplane32++;
                }
        } else {
-               switch (kp->memory) {
+               switch (memory) {
                case V4L2_MEMORY_MMAP:
-                       if (get_user(kp->m.offset, &up->m.offset))
+               case V4L2_MEMORY_OVERLAY:
+                       if (assign_in_user(&kp->m.offset, &up->m.offset))
                                return -EFAULT;
                        break;
-               case V4L2_MEMORY_USERPTR:
-                       {
-                       compat_long_t tmp;
+               case V4L2_MEMORY_USERPTR: {
+                       compat_ulong_t userptr;
 
-                       if (get_user(tmp, &up->m.userptr))
-                               return -EFAULT;
-
-                       kp->m.userptr = (unsigned long)compat_ptr(tmp);
-                       }
-                       break;
-               case V4L2_MEMORY_OVERLAY:
-                       if (get_user(kp->m.offset, &up->m.offset))
+                       if (get_user(userptr, &up->m.userptr) ||
+                           put_user((unsigned long)compat_ptr(userptr),
+                                    &kp->m.userptr))
                                return -EFAULT;
                        break;
+               }
                case V4L2_MEMORY_DMABUF:
-                       if (get_user(kp->m.fd, &up->m.fd))
+                       if (assign_in_user(&kp->m.fd, &up->m.fd))
                                return -EFAULT;
                        break;
                }
@@ -498,65 +577,70 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
        return 0;
 }
 
-static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
+static int put_v4l2_buffer32(struct v4l2_buffer __user *kp,
+                            struct v4l2_buffer32 __user *up)
 {
+       u32 type;
+       u32 length;
+       enum v4l2_memory memory;
        struct v4l2_plane32 __user *uplane32;
        struct v4l2_plane __user *uplane;
        compat_caddr_t p;
-       int num_planes;
        int ret;
 
-       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) ||
-               put_user(kp->index, &up->index) ||
-               put_user(kp->type, &up->type) ||
-               put_user(kp->flags, &up->flags) ||
-               put_user(kp->memory, &up->memory))
-                       return -EFAULT;
+       if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+           assign_in_user(&up->index, &kp->index) ||
+           get_user(type, &kp->type) ||
+           put_user(type, &up->type) ||
+           assign_in_user(&up->flags, &kp->flags) ||
+           get_user(memory, &kp->memory) ||
+           put_user(memory, &up->memory))
+               return -EFAULT;
 
-       if (put_user(kp->bytesused, &up->bytesused) ||
-               put_user(kp->field, &up->field) ||
-               put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
-               put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) ||
-               copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) ||
-               put_user(kp->sequence, &up->sequence) ||
-               put_user(kp->reserved2, &up->reserved2) ||
-               put_user(kp->reserved, &up->reserved) ||
-               put_user(kp->length, &up->length))
-                       return -EFAULT;
+       if (assign_in_user(&up->bytesused, &kp->bytesused) ||
+           assign_in_user(&up->field, &kp->field) ||
+           assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) ||
+           assign_in_user(&up->timestamp.tv_usec, &kp->timestamp.tv_usec) ||
+           copy_in_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) ||
+           assign_in_user(&up->sequence, &kp->sequence) ||
+           assign_in_user(&up->reserved2, &kp->reserved2) ||
+           assign_in_user(&up->reserved, &kp->reserved) ||
+           get_user(length, &kp->length) ||
+           put_user(length, &up->length))
+               return -EFAULT;
+
+       if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
+               u32 num_planes = length;
 
-       if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
-               num_planes = kp->length;
                if (num_planes == 0)
                        return 0;
 
-               uplane = (__force struct v4l2_plane __user *)kp->m.planes;
+               if (get_user(uplane, ((__force struct v4l2_plane __user **)&kp->m.planes)))
+                       return -EFAULT;
                if (get_user(p, &up->m.planes))
                        return -EFAULT;
                uplane32 = compat_ptr(p);
 
-               while (--num_planes >= 0) {
-                       ret = put_v4l2_plane32(uplane, uplane32, kp->memory);
+               while (num_planes--) {
+                       ret = put_v4l2_plane32(uplane, uplane32, memory);
                        if (ret)
                                return ret;
                        ++uplane;
                        ++uplane32;
                }
        } else {
-               switch (kp->memory) {
+               switch (memory) {
                case V4L2_MEMORY_MMAP:
-                       if (put_user(kp->m.offset, &up->m.offset))
+               case V4L2_MEMORY_OVERLAY:
+                       if (assign_in_user(&up->m.offset, &kp->m.offset))
                                return -EFAULT;
                        break;
                case V4L2_MEMORY_USERPTR:
-                       if (put_user(kp->m.userptr, &up->m.userptr))
-                               return -EFAULT;
-                       break;
-               case V4L2_MEMORY_OVERLAY:
-                       if (put_user(kp->m.offset, &up->m.offset))
+                       if (assign_in_user(&up->m.userptr, &kp->m.userptr))
                                return -EFAULT;
                        break;
                case V4L2_MEMORY_DMABUF:
-                       if (put_user(kp->m.fd, &up->m.fd))
+                       if (assign_in_user(&up->m.fd, &kp->m.fd))
                                return -EFAULT;
                        break;
                }
@@ -568,7 +652,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
 struct v4l2_framebuffer32 {
        __u32                   capability;
        __u32                   flags;
-       compat_caddr_t          base;
+       compat_caddr_t          base;
        struct {
                __u32           width;
                __u32           height;
@@ -581,30 +665,33 @@ struct v4l2_framebuffer32 {
        } fmt;
 };
 
-static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
+static int get_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp,
+                                 struct v4l2_framebuffer32 __user *up)
 {
-       u32 tmp;
-
-       if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) ||
-               get_user(tmp, &up->base) ||
-               get_user(kp->capability, &up->capability) ||
-               get_user(kp->flags, &up->flags) ||
-               copy_from_user(&kp->fmt, &up->fmt, sizeof(up->fmt)))
-                       return -EFAULT;
-       kp->base = (__force void *)compat_ptr(tmp);
+       compat_caddr_t tmp;
+
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+           get_user(tmp, &up->base) ||
+           put_user((__force void *)compat_ptr(tmp), &kp->base) ||
+           assign_in_user(&kp->capability, &up->capability) ||
+           assign_in_user(&kp->flags, &up->flags) ||
+           copy_in_user(&kp->fmt, &up->fmt, sizeof(kp->fmt)))
+               return -EFAULT;
        return 0;
 }
 
-static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
+static int put_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp,
+                                 struct v4l2_framebuffer32 __user *up)
 {
-       u32 tmp = (u32)((unsigned long)kp->base);
-
-       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) ||
-               put_user(tmp, &up->base) ||
-               put_user(kp->capability, &up->capability) ||
-               put_user(kp->flags, &up->flags) ||
-               copy_to_user(&up->fmt, &kp->fmt, sizeof(up->fmt)))
-                       return -EFAULT;
+       void *base;
+
+       if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+           get_user(base, &kp->base) ||
+           put_user(ptr_to_compat(base), &up->base) ||
+           assign_in_user(&up->capability, &kp->capability) ||
+           assign_in_user(&up->flags, &kp->flags) ||
+           copy_in_user(&up->fmt, &kp->fmt, sizeof(kp->fmt)))
+               return -EFAULT;
        return 0;
 }
 
@@ -616,21 +703,26 @@ struct v4l2_input32 {
        __u32        tuner;             /*  Associated tuner */
        compat_u64   std;
        __u32        status;
-       __u32        reserved[4];
+       __u32        capabilities;
+       __u32        reserved[3];
 };
 
-/* The 64-bit v4l2_input struct has extra padding at the end of the struct.
-   Otherwise it is identical to the 32-bit version. */
-static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
+/*
+ * The 64-bit v4l2_input struct has extra padding at the end of the struct.
+ * Otherwise it is identical to the 32-bit version.
+ */
+static inline int get_v4l2_input32(struct v4l2_input __user *kp,
+                                  struct v4l2_input32 __user *up)
 {
-       if (copy_from_user(kp, up, sizeof(struct v4l2_input32)))
+       if (copy_in_user(kp, up, sizeof(*up)))
                return -EFAULT;
        return 0;
 }
 
-static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
+static inline int put_v4l2_input32(struct v4l2_input __user *kp,
+                                  struct v4l2_input32 __user *up)
 {
-       if (copy_to_user(up, kp, sizeof(struct v4l2_input32)))
+       if (copy_in_user(up, kp, sizeof(*up)))
                return -EFAULT;
        return 0;
 }
@@ -654,58 +746,95 @@ struct v4l2_ext_control32 {
        };
 } __attribute__ ((packed));
 
-/* The following function really belong in v4l2-common, but that causes
-   a circular dependency between modules. We need to think about this, but
-   for now this will do. */
-
-/* Return non-zero if this control is a pointer type. Currently only
-   type STRING is a pointer type. */
-static inline int ctrl_is_pointer(u32 id)
+/* Return true if this control is a pointer type. */
+static inline bool ctrl_is_pointer(struct file *file, u32 id)
 {
-       switch (id) {
-       case V4L2_CID_RDS_TX_PS_NAME:
-       case V4L2_CID_RDS_TX_RADIO_TEXT:
-               return 1;
-       default:
-               return 0;
+       struct video_device *vdev = video_devdata(file);
+       struct v4l2_fh *fh = NULL;
+       struct v4l2_ctrl_handler *hdl = NULL;
+       struct v4l2_query_ext_ctrl qec = { id };
+       const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops;
+
+       if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags))
+               fh = file->private_data;
+
+       if (fh && fh->ctrl_handler)
+               hdl = fh->ctrl_handler;
+       else if (vdev->ctrl_handler)
+               hdl = vdev->ctrl_handler;
+
+       if (hdl) {
+               struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, id);
+
+               return ctrl && ctrl->is_ptr;
        }
+
+       if (!ops || !ops->vidioc_query_ext_ctrl)
+               return false;
+
+       return !ops->vidioc_query_ext_ctrl(file, fh, &qec) &&
+               (qec.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD);
+}
+
+static int bufsize_v4l2_ext_controls(struct v4l2_ext_controls32 __user *up,
+                                    u32 *size)
+{
+       u32 count;
+
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+           get_user(count, &up->count))
+               return -EFAULT;
+       if (count > V4L2_CID_MAX_CTRLS)
+               return -EINVAL;
+       *size = count * sizeof(struct v4l2_ext_control);
+       return 0;
 }
 
-static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
+static int get_v4l2_ext_controls32(struct file *file,
+                                  struct v4l2_ext_controls __user *kp,
+                                  struct v4l2_ext_controls32 __user *up,
+                                  void __user *aux_buf, u32 aux_space)
 {
        struct v4l2_ext_control32 __user *ucontrols;
        struct v4l2_ext_control __user *kcontrols;
-       int n;
+       u32 count;
+       u32 n;
        compat_caddr_t p;
 
-       if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) ||
-               get_user(kp->ctrl_class, &up->ctrl_class) ||
-               get_user(kp->count, &up->count) ||
-               get_user(kp->error_idx, &up->error_idx) ||
-               copy_from_user(kp->reserved, up->reserved,
-                              sizeof(kp->reserved)))
-                       return -EFAULT;
-       n = kp->count;
-       if (n == 0) {
-               kp->controls = NULL;
-               return 0;
-       }
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+           assign_in_user(&kp->ctrl_class, &up->ctrl_class) ||
+           get_user(count, &up->count) ||
+           put_user(count, &kp->count) ||
+           assign_in_user(&kp->error_idx, &up->error_idx) ||
+           copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
+               return -EFAULT;
+
+       if (count == 0)
+               return put_user(NULL, &kp->controls);
+       if (count > V4L2_CID_MAX_CTRLS)
+               return -EINVAL;
        if (get_user(p, &up->controls))
                return -EFAULT;
        ucontrols = compat_ptr(p);
-       if (!access_ok(VERIFY_READ, ucontrols,
-                       n * sizeof(struct v4l2_ext_control32)))
+       if (!access_ok(VERIFY_READ, ucontrols, count * sizeof(*ucontrols)))
+               return -EFAULT;
+       if (aux_space < count * sizeof(*kcontrols))
                return -EFAULT;
-       kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
-       kp->controls = (__force struct v4l2_ext_control *)kcontrols;
-       while (--n >= 0) {
+       kcontrols = aux_buf;
+       if (put_user((__force struct v4l2_ext_control *)kcontrols,
+                    &kp->controls))
+               return -EFAULT;
+
+       for (n = 0; n < count; n++) {
                u32 id;
 
                if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols)))
                        return -EFAULT;
+
                if (get_user(id, &kcontrols->id))
                        return -EFAULT;
-               if (ctrl_is_pointer(id)) {
+
+               if (ctrl_is_pointer(file, id)) {
                        void __user *s;
 
                        if (get_user(p, &ucontrols->string))
@@ -720,43 +849,55 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
        return 0;
 }
 
-static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
+static int put_v4l2_ext_controls32(struct file *file,
+                                  struct v4l2_ext_controls __user *kp,
+                                  struct v4l2_ext_controls32 __user *up)
 {
        struct v4l2_ext_control32 __user *ucontrols;
-       struct v4l2_ext_control __user *kcontrols =
-               (__force struct v4l2_ext_control __user *)kp->controls;
-       int n = kp->count;
+       struct v4l2_ext_control __user *kcontrols;
+       u32 count;
+       u32 n;
        compat_caddr_t p;
 
-       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) ||
-               put_user(kp->ctrl_class, &up->ctrl_class) ||
-               put_user(kp->count, &up->count) ||
-               put_user(kp->error_idx, &up->error_idx) ||
-               copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
-                       return -EFAULT;
-       if (!kp->count)
-               return 0;
+       if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+           assign_in_user(&up->ctrl_class, &kp->ctrl_class) ||
+           get_user(count, &kp->count) ||
+           put_user(count, &up->count) ||
+           assign_in_user(&up->error_idx, &kp->error_idx) ||
+           copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)) ||
+           get_user(kcontrols, &kp->controls))
+               return -EFAULT;
 
+       if (!count)
+               return 0;
        if (get_user(p, &up->controls))
                return -EFAULT;
        ucontrols = compat_ptr(p);
-       if (!access_ok(VERIFY_WRITE, ucontrols,
-                       n * sizeof(struct v4l2_ext_control32)))
+       if (!access_ok(VERIFY_WRITE, ucontrols, count * sizeof(*ucontrols)))
                return -EFAULT;
 
-       while (--n >= 0) {
-               unsigned size = sizeof(*ucontrols);
+       for (n = 0; n < count; n++) {
+               unsigned int size = sizeof(*ucontrols);
                u32 id;
 
-               if (get_user(id, &kcontrols->id))
+               if (get_user(id, &kcontrols->id) ||
+                   put_user(id, &ucontrols->id) ||
+                   assign_in_user(&ucontrols->size, &kcontrols->size) ||
+                   copy_in_user(&ucontrols->reserved2, &kcontrols->reserved2,
+                                sizeof(ucontrols->reserved2)))
                        return -EFAULT;
-               /* Do not modify the pointer when copying a pointer control.
-                  The contents of the pointer was changed, not the pointer
-                  itself. */
-               if (ctrl_is_pointer(id))
+
+               /*
+                * Do not modify the pointer when copying a pointer control.
+                * The contents of the pointer was changed, not the pointer
+                * itself.
+                */
+               if (ctrl_is_pointer(file, id))
                        size -= sizeof(ucontrols->value64);
+
                if (copy_in_user(ucontrols, kcontrols, size))
                        return -EFAULT;
+
                ucontrols++;
                kcontrols++;
        }
@@ -781,18 +922,19 @@ struct v4l2_event32 {
        __u32                           reserved[8];
 };
 
-static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *up)
+static int put_v4l2_event32(struct v4l2_event __user *kp,
+                           struct v4l2_event32 __user *up)
 {
-       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_event32)) ||
-               put_user(kp->type, &up->type) ||
-               copy_to_user(&up->u, &kp->u, sizeof(kp->u)) ||
-               put_user(kp->pending, &up->pending) ||
-               put_user(kp->sequence, &up->sequence) ||
-               put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
-               put_user(kp->timestamp.tv_nsec, &up->timestamp.tv_nsec) ||
-               put_user(kp->id, &up->id) ||
-               copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32)))
-                       return -EFAULT;
+       if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+           assign_in_user(&up->type, &kp->type) ||
+           copy_in_user(&up->u, &kp->u, sizeof(kp->u)) ||
+           assign_in_user(&up->pending, &kp->pending) ||
+           assign_in_user(&up->sequence, &kp->sequence) ||
+           assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) ||
+           assign_in_user(&up->timestamp.tv_nsec, &kp->timestamp.tv_nsec) ||
+           assign_in_user(&up->id, &kp->id) ||
+           copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+               return -EFAULT;
        return 0;
 }
 
@@ -804,32 +946,35 @@ struct v4l2_edid32 {
        compat_caddr_t edid;
 };
 
-static int get_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up)
+static int get_v4l2_edid32(struct v4l2_edid __user *kp,
+                          struct v4l2_edid32 __user *up)
 {
-       u32 tmp;
-
-       if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_edid32)) ||
-               get_user(kp->pad, &up->pad) ||
-               get_user(kp->start_block, &up->start_block) ||
-               get_user(kp->blocks, &up->blocks) ||
-               get_user(tmp, &up->edid) ||
-               copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
-                       return -EFAULT;
-       kp->edid = (__force u8 *)compat_ptr(tmp);
+       compat_uptr_t tmp;
+
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+           assign_in_user(&kp->pad, &up->pad) ||
+           assign_in_user(&kp->start_block, &up->start_block) ||
+           assign_in_user(&kp->blocks, &up->blocks) ||
+           get_user(tmp, &up->edid) ||
+           put_user(compat_ptr(tmp), &kp->edid) ||
+           copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
+               return -EFAULT;
        return 0;
 }
 
-static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up)
+static int put_v4l2_edid32(struct v4l2_edid __user *kp,
+                          struct v4l2_edid32 __user *up)
 {
-       u32 tmp = (u32)((unsigned long)kp->edid);
-
-       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_edid32)) ||
-               put_user(kp->pad, &up->pad) ||
-               put_user(kp->start_block, &up->start_block) ||
-               put_user(kp->blocks, &up->blocks) ||
-               put_user(tmp, &up->edid) ||
-               copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
-                       return -EFAULT;
+       void *edid;
+
+       if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+           assign_in_user(&up->pad, &kp->pad) ||
+           assign_in_user(&up->start_block, &kp->start_block) ||
+           assign_in_user(&up->blocks, &kp->blocks) ||
+           get_user(edid, &kp->edid) ||
+           put_user(ptr_to_compat(edid), &up->edid) ||
+           copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+               return -EFAULT;
        return 0;
 }
 
@@ -845,7 +990,7 @@ static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up)
 #define VIDIOC_ENUMINPUT32     _IOWR('V', 26, struct v4l2_input32)
 #define VIDIOC_G_EDID32                _IOWR('V', 40, struct v4l2_edid32)
 #define VIDIOC_S_EDID32                _IOWR('V', 41, struct v4l2_edid32)
-#define VIDIOC_TRY_FMT32       _IOWR('V', 64, struct v4l2_format32)
+#define VIDIOC_TRY_FMT32       _IOWR('V', 64, struct v4l2_format32)
 #define VIDIOC_G_EXT_CTRLS32    _IOWR('V', 71, struct v4l2_ext_controls32)
 #define VIDIOC_S_EXT_CTRLS32    _IOWR('V', 72, struct v4l2_ext_controls32)
 #define VIDIOC_TRY_EXT_CTRLS32  _IOWR('V', 73, struct v4l2_ext_controls32)
@@ -861,26 +1006,26 @@ static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up)
 #define VIDIOC_G_OUTPUT32      _IOR ('V', 46, s32)
 #define VIDIOC_S_OUTPUT32      _IOWR('V', 47, s32)
 
+static int alloc_userspace(unsigned int size, u32 aux_space,
+                          void __user **up_native)
+{
+       *up_native = compat_alloc_user_space(size + aux_space);
+       if (!*up_native)
+               return -ENOMEM;
+       if (clear_user(*up_native, size))
+               return -EFAULT;
+       return 0;
+}
+
 static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-       union {
-               struct v4l2_format v2f;
-               struct v4l2_buffer v2b;
-               struct v4l2_framebuffer v2fb;
-               struct v4l2_input v2i;
-               struct v4l2_standard v2s;
-               struct v4l2_ext_controls v2ecs;
-               struct v4l2_event v2ev;
-               struct v4l2_create_buffers v2crt;
-               struct v4l2_edid v2edid;
-               unsigned long vx;
-               int vi;
-       } karg;
        void __user *up = compat_ptr(arg);
+       void __user *up_native = NULL;
+       void __user *aux_buf;
+       u32 aux_space;
        int compatible_arg = 1;
        long err = 0;
 
-       memset(&karg, 0, sizeof(karg));
        /* First, convert the command. */
        switch (cmd) {
        case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break;
@@ -916,30 +1061,52 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
        case VIDIOC_STREAMOFF:
        case VIDIOC_S_INPUT:
        case VIDIOC_S_OUTPUT:
-               err = get_user(karg.vi, (s32 __user *)up);
+               err = alloc_userspace(sizeof(unsigned int), 0, &up_native);
+               if (!err && assign_in_user((unsigned int __user *)up_native,
+                                          (compat_uint_t __user *)up))
+                       err = -EFAULT;
                compatible_arg = 0;
                break;
 
        case VIDIOC_G_INPUT:
        case VIDIOC_G_OUTPUT:
+               err = alloc_userspace(sizeof(unsigned int), 0, &up_native);
                compatible_arg = 0;
                break;
 
        case VIDIOC_G_EDID:
        case VIDIOC_S_EDID:
-               err = get_v4l2_edid32(&karg.v2edid, up);
+               err = alloc_userspace(sizeof(struct v4l2_edid), 0, &up_native);
+               if (!err)
+                       err = get_v4l2_edid32(up_native, up);
                compatible_arg = 0;
                break;
 
        case VIDIOC_G_FMT:
        case VIDIOC_S_FMT:
        case VIDIOC_TRY_FMT:
-               err = get_v4l2_format32(&karg.v2f, up);
+               err = bufsize_v4l2_format(up, &aux_space);
+               if (!err)
+                       err = alloc_userspace(sizeof(struct v4l2_format),
+                                             aux_space, &up_native);
+               if (!err) {
+                       aux_buf = up_native + sizeof(struct v4l2_format);
+                       err = get_v4l2_format32(up_native, up,
+                                               aux_buf, aux_space);
+               }
                compatible_arg = 0;
                break;
 
        case VIDIOC_CREATE_BUFS:
-               err = get_v4l2_create32(&karg.v2crt, up);
+               err = bufsize_v4l2_create(up, &aux_space);
+               if (!err)
+                       err = alloc_userspace(sizeof(struct v4l2_create_buffers),
+                                             aux_space, &up_native);
+               if (!err) {
+                       aux_buf = up_native + sizeof(struct v4l2_create_buffers);
+                       err = get_v4l2_create32(up_native, up,
+                                               aux_buf, aux_space);
+               }
                compatible_arg = 0;
                break;
 
@@ -947,36 +1114,63 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
        case VIDIOC_QUERYBUF:
        case VIDIOC_QBUF:
        case VIDIOC_DQBUF:
-               err = get_v4l2_buffer32(&karg.v2b, up);
+               err = bufsize_v4l2_buffer(up, &aux_space);
+               if (!err)
+                       err = alloc_userspace(sizeof(struct v4l2_buffer),
+                                             aux_space, &up_native);
+               if (!err) {
+                       aux_buf = up_native + sizeof(struct v4l2_buffer);
+                       err = get_v4l2_buffer32(up_native, up,
+                                               aux_buf, aux_space);
+               }
                compatible_arg = 0;
                break;
 
        case VIDIOC_S_FBUF:
-               err = get_v4l2_framebuffer32(&karg.v2fb, up);
+               err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
+                                     &up_native);
+               if (!err)
+                       err = get_v4l2_framebuffer32(up_native, up);
                compatible_arg = 0;
                break;
 
        case VIDIOC_G_FBUF:
+               err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
+                                     &up_native);
                compatible_arg = 0;
                break;
 
        case VIDIOC_ENUMSTD:
-               err = get_v4l2_standard32(&karg.v2s, up);
+               err = alloc_userspace(sizeof(struct v4l2_standard), 0,
+                                     &up_native);
+               if (!err)
+                       err = get_v4l2_standard32(up_native, up);
                compatible_arg = 0;
                break;
 
        case VIDIOC_ENUMINPUT:
-               err = get_v4l2_input32(&karg.v2i, up);
+               err = alloc_userspace(sizeof(struct v4l2_input), 0, &up_native);
+               if (!err)
+                       err = get_v4l2_input32(up_native, up);
                compatible_arg = 0;
                break;
 
        case VIDIOC_G_EXT_CTRLS:
        case VIDIOC_S_EXT_CTRLS:
        case VIDIOC_TRY_EXT_CTRLS:
-               err = get_v4l2_ext_controls32(&karg.v2ecs, up);
+               err = bufsize_v4l2_ext_controls(up, &aux_space);
+               if (!err)
+                       err = alloc_userspace(sizeof(struct v4l2_ext_controls),
+                                             aux_space, &up_native);
+               if (!err) {
+                       aux_buf = up_native + sizeof(struct v4l2_ext_controls);
+                       err = get_v4l2_ext_controls32(file, up_native, up,
+                                                     aux_buf, aux_space);
+               }
                compatible_arg = 0;
                break;
        case VIDIOC_DQEVENT:
+               err = alloc_userspace(sizeof(struct v4l2_event), 0, &up_native);
                compatible_arg = 0;
                break;
        }
@@ -985,22 +1179,26 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
 
        if (compatible_arg)
                err = native_ioctl(file, cmd, (unsigned long)up);
-       else {
-               mm_segment_t old_fs = get_fs();
+       else
+               err = native_ioctl(file, cmd, (unsigned long)up_native);
 
-               set_fs(KERNEL_DS);
-               err = native_ioctl(file, cmd, (unsigned long)&karg);
-               set_fs(old_fs);
-       }
+       if (err == -ENOTTY)
+               return err;
 
-       /* Special case: even after an error we need to put the
-          results back for these ioctls since the error_idx will
-          contain information on which control failed. */
+       /*
+        * Special case: even after an error we need to put the
+        * results back for these ioctls since the error_idx will
+        * contain information on which control failed.
+        */
        switch (cmd) {
        case VIDIOC_G_EXT_CTRLS:
        case VIDIOC_S_EXT_CTRLS:
        case VIDIOC_TRY_EXT_CTRLS:
-               if (put_v4l2_ext_controls32(&karg.v2ecs, up))
+               if (put_v4l2_ext_controls32(file, up_native, up))
+                       err = -EFAULT;
+               break;
+       case VIDIOC_S_EDID:
+               if (put_v4l2_edid32(up_native, up))
                        err = -EFAULT;
                break;
        }
@@ -1012,44 +1210,46 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
        case VIDIOC_S_OUTPUT:
        case VIDIOC_G_INPUT:
        case VIDIOC_G_OUTPUT:
-               err = put_user(((s32)karg.vi), (s32 __user *)up);
+               if (assign_in_user((compat_uint_t __user *)up,
+                                  ((unsigned int __user *)up_native)))
+                       err = -EFAULT;
                break;
 
        case VIDIOC_G_FBUF:
-               err = put_v4l2_framebuffer32(&karg.v2fb, up);
+               err = put_v4l2_framebuffer32(up_native, up);
                break;
 
        case VIDIOC_DQEVENT:
-               err = put_v4l2_event32(&karg.v2ev, up);
+               err = put_v4l2_event32(up_native, up);
                break;
 
        case VIDIOC_G_EDID:
-       case VIDIOC_S_EDID:
-               err = put_v4l2_edid32(&karg.v2edid, up);
+               err = put_v4l2_edid32(up_native, up);
                break;
 
        case VIDIOC_G_FMT:
        case VIDIOC_S_FMT:
        case VIDIOC_TRY_FMT:
-               err = put_v4l2_format32(&karg.v2f, up);
+               err = put_v4l2_format32(up_native, up);
                break;
 
        case VIDIOC_CREATE_BUFS:
-               err = put_v4l2_create32(&karg.v2crt, up);
+               err = put_v4l2_create32(up_native, up);
                break;
 
+       case VIDIOC_PREPARE_BUF:
        case VIDIOC_QUERYBUF:
        case VIDIOC_QBUF:
        case VIDIOC_DQBUF:
-               err = put_v4l2_buffer32(&karg.v2b, up);
+               err = put_v4l2_buffer32(up_native, up);
                break;
 
        case VIDIOC_ENUMSTD:
-               err = put_v4l2_standard32(&karg.v2s, up);
+               err = put_v4l2_standard32(up_native, up);
                break;
 
        case VIDIOC_ENUMINPUT:
-               err = put_v4l2_input32(&karg.v2i, up);
+               err = put_v4l2_input32(up_native, up);
                break;
        }
        return err;
index d9e04bc..79829f5 100644 (file)
@@ -2871,8 +2871,11 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
 
        /* Handles IOCTL */
        err = func(file, cmd, parg);
-       if (err == -ENOIOCTLCMD)
+       if (err == -ENOTTY || err == -ENOIOCTLCMD) {
                err = -ENOTTY;
+               goto out;
+       }
+
        if (err == 0) {
                if (cmd == VIDIOC_DQBUF)
                        trace_v4l2_dqbuf(video_devdata(file)->minor, parg);
index 6c441be..bf23234 100644 (file)
@@ -593,6 +593,12 @@ static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b,
                        b->flags & V4L2_BUF_FLAG_LAST)
                q->last_buffer_dequeued = true;
 
+       /*
+        *  After calling the VIDIOC_DQBUF V4L2_BUF_FLAG_DONE must be
+        *  cleared.
+        */
+       b->flags &= ~V4L2_BUF_FLAG_DONE;
+
        return ret;
 }
 
index 5dcc031..207370d 100644 (file)
@@ -6848,6 +6848,7 @@ mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int sh
        *size = y;
 }
 
+#ifdef CONFIG_PROC_FS
 static void seq_mpt_print_ioc_summary(MPT_ADAPTER *ioc, struct seq_file *m, int showlan)
 {
        char expVer[32];
@@ -6879,6 +6880,7 @@ static void seq_mpt_print_ioc_summary(MPT_ADAPTER *ioc, struct seq_file *m, int
 
        seq_putc(m, '\n');
 }
+#endif
 
 /**
  *     mpt_set_taskmgmt_in_progress_flag - set flags associated with task management
index a2887fc..92e6a66 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -169,6 +169,7 @@ static int bw_profiling_get(void __user *argp, struct tz_bw_svc_buf *bwbuf)
        const int numberofregs = 3;
        struct profiler_bw_cntrs_req cnt_buf;
 
+       memset(&cnt_buf, 0, sizeof(cnt_buf));
        bwgetreq = (struct tz_bw_svc_get_req *) &bwbuf->bwreq;
        /* Allocate memory for get buffer */
        buf = kzalloc(PAGE_ALIGN(numberofregs * sizeof(uint32_t)), GFP_KERNEL);
index 65d7dbe..2aa04b6 100644 (file)
@@ -335,6 +335,7 @@ static int mmc_read_switch(struct mmc_card *card)
                card->sw_caps.sd3_bus_mode = status[13];
                /* Driver Strengths supported by the card */
                card->sw_caps.sd3_drv_type = status[9];
+               card->sw_caps.sd3_curr_limit = status[7] | status[6] << 8;
        }
 
 out:
@@ -557,14 +558,25 @@ static int sd_set_current_limit(struct mmc_card *card, u8 *status)
         * when we set current limit to 200ma, the card will draw 200ma, and
         * when we set current limit to 400/600/800ma, the card will draw its
         * maximum 300ma from the host.
+        *
+        * The above is incorrect: if we try to set a current limit that is
+        * not supported by the card, the card can rightfully error out the
+        * attempt, and remain at the default current limit.  This results
+        * in a 300mA card being limited to 200mA even though the host
+        * supports 800mA. Failures seen with SanDisk 8GB UHS cards with
+        * an iMX6 host. --rmk
         */
-       if (max_current >= 800)
+       if (max_current >= 800 &&
+           card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_800)
                current_limit = SD_SET_CURRENT_LIMIT_800;
-       else if (max_current >= 600)
+       else if (max_current >= 600 &&
+                card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_600)
                current_limit = SD_SET_CURRENT_LIMIT_600;
-       else if (max_current >= 400)
+       else if (max_current >= 400 &&
+                card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_400)
                current_limit = SD_SET_CURRENT_LIMIT_400;
-       else if (max_current >= 200)
+       else if (max_current >= 200 &&
+                card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_200)
                current_limit = SD_SET_CURRENT_LIMIT_200;
 
        if (current_limit != SD_SET_CURRENT_NO_CHANGE) {
index 8a25adc..bbfa1f1 100644 (file)
@@ -67,6 +67,10 @@ endchoice
 config MTD_CFI_GEOMETRY
        bool "Specific CFI Flash geometry selection"
        depends on MTD_CFI_ADV_OPTIONS
+       select MTD_MAP_BANK_WIDTH_1 if  !(MTD_MAP_BANK_WIDTH_2 || \
+                MTD_MAP_BANK_WIDTH_4  || MTD_MAP_BANK_WIDTH_8 || \
+                MTD_MAP_BANK_WIDTH_16 || MTD_MAP_BANK_WIDTH_32)
+       select MTD_CFI_I1 if !(MTD_CFI_I2 || MTD_CFI_I4 || MTD_CFI_I8)
        help
          This option does not affect the code directly, but will enable
          some other configuration options which would allow you to reduce
index 0455166..4f206a9 100644 (file)
@@ -112,8 +112,8 @@ static void ck804xrom_cleanup(struct ck804xrom_window *window)
 }
 
 
-static int ck804xrom_init_one(struct pci_dev *pdev,
-                             const struct pci_device_id *ent)
+static int __init ck804xrom_init_one(struct pci_dev *pdev,
+                                    const struct pci_device_id *ent)
 {
        static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
        u8 byte;
index 76ed651..9646b07 100644 (file)
@@ -144,8 +144,8 @@ static void esb2rom_cleanup(struct esb2rom_window *window)
        pci_dev_put(window->pdev);
 }
 
-static int esb2rom_init_one(struct pci_dev *pdev,
-                           const struct pci_device_id *ent)
+static int __init esb2rom_init_one(struct pci_dev *pdev,
+                                  const struct pci_device_id *ent)
 {
        static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
        struct esb2rom_window *window = &esb2rom_window;
index 8636bba..976d42f 100644 (file)
@@ -57,10 +57,12 @@ static void ichxrom_cleanup(struct ichxrom_window *window)
 {
        struct ichxrom_map_info *map, *scratch;
        u16 word;
+       int ret;
 
        /* Disable writes through the rom window */
-       pci_read_config_word(window->pdev, BIOS_CNTL, &word);
-       pci_write_config_word(window->pdev, BIOS_CNTL, word & ~1);
+       ret = pci_read_config_word(window->pdev, BIOS_CNTL, &word);
+       if (!ret)
+               pci_write_config_word(window->pdev, BIOS_CNTL, word & ~1);
        pci_dev_put(window->pdev);
 
        /* Free all of the mtd devices */
@@ -84,8 +86,8 @@ static void ichxrom_cleanup(struct ichxrom_window *window)
 }
 
 
-static int ichxrom_init_one(struct pci_dev *pdev,
-                           const struct pci_device_id *ent)
+static int __init ichxrom_init_one(struct pci_dev *pdev,
+                                  const struct pci_device_id *ent)
 {
        static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
        struct ichxrom_window *window = &ichxrom_window;
index 4a07ba1..d125d19 100644 (file)
@@ -1922,16 +1922,9 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
        tmp &= ~ACC_CONTROL_PARTIAL_PAGE;
        tmp &= ~ACC_CONTROL_RD_ERASED;
        tmp &= ~ACC_CONTROL_FAST_PGM_RDIN;
-       if (ctrl->features & BRCMNAND_HAS_PREFETCH) {
-               /*
-                * FIXME: Flash DMA + prefetch may see spurious erased-page ECC
-                * errors
-                */
-               if (has_flash_dma(ctrl))
-                       tmp &= ~ACC_CONTROL_PREFETCH;
-               else
-                       tmp |= ACC_CONTROL_PREFETCH;
-       }
+       if (ctrl->features & BRCMNAND_HAS_PREFETCH)
+               tmp &= ~ACC_CONTROL_PREFETCH;
+
        nand_writereg(ctrl, offs, tmp);
 
        return 0;
index 7ba109e..27864c0 100644 (file)
@@ -2023,6 +2023,7 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd,
 static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
                            struct mtd_oob_ops *ops)
 {
+       unsigned int max_bitflips = 0;
        int page, realpage, chipnr;
        struct nand_chip *chip = mtd->priv;
        struct mtd_ecc_stats stats;
@@ -2083,6 +2084,8 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
                                nand_wait_ready(mtd);
                }
 
+               max_bitflips = max_t(unsigned int, max_bitflips, ret);
+
                readlen -= len;
                if (!readlen)
                        break;
@@ -2108,7 +2111,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
        if (mtd->ecc_stats.failed - stats.failed)
                return -EBADMSG;
 
-       return  mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
+       return max_bitflips;
 }
 
 /**
index bcba1a9..1f2785e 100644 (file)
@@ -160,7 +160,7 @@ static void flctl_setup_dma(struct sh_flctl *flctl)
 
        memset(&cfg, 0, sizeof(cfg));
        cfg.direction = DMA_MEM_TO_DEV;
-       cfg.dst_addr = (dma_addr_t)FLDTFIFO(flctl);
+       cfg.dst_addr = flctl->fifo;
        cfg.src_addr = 0;
        ret = dmaengine_slave_config(flctl->chan_fifo0_tx, &cfg);
        if (ret < 0)
@@ -176,7 +176,7 @@ static void flctl_setup_dma(struct sh_flctl *flctl)
 
        cfg.direction = DMA_DEV_TO_MEM;
        cfg.dst_addr = 0;
-       cfg.src_addr = (dma_addr_t)FLDTFIFO(flctl);
+       cfg.src_addr = flctl->fifo;
        ret = dmaengine_slave_config(flctl->chan_fifo0_rx, &cfg);
        if (ret < 0)
                goto err;
@@ -1096,6 +1096,7 @@ static int flctl_probe(struct platform_device *pdev)
        flctl->reg = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(flctl->reg))
                return PTR_ERR(flctl->reg);
+       flctl->fifo = res->start + 0x24; /* FLDTFIFO */
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
index 8247118..3bb9b34 100644 (file)
@@ -1046,8 +1046,14 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
 
        /* Add ECC info retrieval from DT */
        for (i = 0; i < ARRAY_SIZE(strengths); i++) {
-               if (ecc->strength <= strengths[i])
+               if (ecc->strength <= strengths[i]) {
+                       /*
+                        * Update ecc->strength value with the actual strength
+                        * that will be used by the ECC engine.
+                        */
+                       ecc->strength = strengths[i];
                        break;
+               }
        }
 
        if (i >= ARRAY_SIZE(strengths)) {
index ebf46ad..b2fb052 100644 (file)
@@ -99,6 +99,8 @@ struct ubiblock {
 
 /* Linked list of all ubiblock instances */
 static LIST_HEAD(ubiblock_devices);
+static DEFINE_IDR(ubiblock_minor_idr);
+/* Protects ubiblock_devices and ubiblock_minor_idr */
 static DEFINE_MUTEX(devices_mutex);
 static int ubiblock_major;
 
@@ -354,8 +356,6 @@ static struct blk_mq_ops ubiblock_mq_ops = {
        .map_queue      = blk_mq_map_queue,
 };
 
-static DEFINE_IDR(ubiblock_minor_idr);
-
 int ubiblock_create(struct ubi_volume_info *vi)
 {
        struct ubiblock *dev;
@@ -368,14 +368,15 @@ int ubiblock_create(struct ubi_volume_info *vi)
        /* Check that the volume isn't already handled */
        mutex_lock(&devices_mutex);
        if (find_dev_nolock(vi->ubi_num, vi->vol_id)) {
-               mutex_unlock(&devices_mutex);
-               return -EEXIST;
+               ret = -EEXIST;
+               goto out_unlock;
        }
-       mutex_unlock(&devices_mutex);
 
        dev = kzalloc(sizeof(struct ubiblock), GFP_KERNEL);
-       if (!dev)
-               return -ENOMEM;
+       if (!dev) {
+               ret = -ENOMEM;
+               goto out_unlock;
+       }
 
        mutex_init(&dev->dev_mutex);
 
@@ -440,14 +441,13 @@ int ubiblock_create(struct ubi_volume_info *vi)
                goto out_free_queue;
        }
 
-       mutex_lock(&devices_mutex);
        list_add_tail(&dev->list, &ubiblock_devices);
-       mutex_unlock(&devices_mutex);
 
        /* Must be the last step: anyone can call file ops from now on */
        add_disk(dev->gd);
        dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)",
                 dev->ubi_num, dev->vol_id, vi->name);
+       mutex_unlock(&devices_mutex);
        return 0;
 
 out_free_queue:
@@ -460,6 +460,8 @@ out_put_disk:
        put_disk(dev->gd);
 out_free_dev:
        kfree(dev);
+out_unlock:
+       mutex_unlock(&devices_mutex);
 
        return ret;
 }
@@ -481,30 +483,36 @@ static void ubiblock_cleanup(struct ubiblock *dev)
 int ubiblock_remove(struct ubi_volume_info *vi)
 {
        struct ubiblock *dev;
+       int ret;
 
        mutex_lock(&devices_mutex);
        dev = find_dev_nolock(vi->ubi_num, vi->vol_id);
        if (!dev) {
-               mutex_unlock(&devices_mutex);
-               return -ENODEV;
+               ret = -ENODEV;
+               goto out_unlock;
        }
 
        /* Found a device, let's lock it so we can check if it's busy */
        mutex_lock(&dev->dev_mutex);
        if (dev->refcnt > 0) {
-               mutex_unlock(&dev->dev_mutex);
-               mutex_unlock(&devices_mutex);
-               return -EBUSY;
+               ret = -EBUSY;
+               goto out_unlock_dev;
        }
 
        /* Remove from device list */
        list_del(&dev->list);
-       mutex_unlock(&devices_mutex);
-
        ubiblock_cleanup(dev);
        mutex_unlock(&dev->dev_mutex);
+       mutex_unlock(&devices_mutex);
+
        kfree(dev);
        return 0;
+
+out_unlock_dev:
+       mutex_unlock(&dev->dev_mutex);
+out_unlock:
+       mutex_unlock(&devices_mutex);
+       return ret;
 }
 
 static int ubiblock_resize(struct ubi_volume_info *vi)
@@ -633,6 +641,7 @@ static void ubiblock_remove_all(void)
        struct ubiblock *next;
        struct ubiblock *dev;
 
+       mutex_lock(&devices_mutex);
        list_for_each_entry_safe(dev, next, &ubiblock_devices, list) {
                /* The module is being forcefully removed */
                WARN_ON(dev->desc);
@@ -641,6 +650,7 @@ static void ubiblock_remove_all(void)
                ubiblock_cleanup(dev);
                kfree(dev);
        }
+       mutex_unlock(&devices_mutex);
 }
 
 int __init ubiblock_init(void)
index fe75c7d..e9d5c19 100644 (file)
@@ -411,6 +411,9 @@ config XEN_NETDEV_BACKEND
 config VMXNET3
        tristate "VMware VMXNET3 ethernet driver"
        depends on PCI && INET
+       depends on !(PAGE_SIZE_64KB || ARM64_64K_PAGES || \
+                    IA64_PAGE_SIZE_64KB || MICROBLAZE_64K_PAGES || \
+                    PARISC_PAGE_SIZE_64KB || PPC_64K_PAGES)
        help
          This driver supports VMware's vmxnet3 virtual ethernet NIC.
          To compile this driver as a module, choose M here: the
index 4547a1b..7677c74 100644 (file)
@@ -562,7 +562,7 @@ static void el3_common_remove (struct net_device *dev)
 }
 
 #ifdef CONFIG_EISA
-static int __init el3_eisa_probe (struct device *device)
+static int el3_eisa_probe(struct device *device)
 {
        short i;
        int ioaddr, irq, if_port;
index 2839af0..1c5f3b2 100644 (file)
@@ -907,7 +907,7 @@ static struct eisa_device_id vortex_eisa_ids[] = {
 };
 MODULE_DEVICE_TABLE(eisa, vortex_eisa_ids);
 
-static int __init vortex_eisa_probe(struct device *device)
+static int vortex_eisa_probe(struct device *device)
 {
        void __iomem *ioaddr;
        struct eisa_device *edev;
index 618d952..2ef4b4e 100644 (file)
@@ -829,7 +829,7 @@ static int xgbe_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int xgbe_suspend(struct device *dev)
 {
        struct net_device *netdev = dev_get_drvdata(dev);
@@ -868,7 +868,7 @@ static int xgbe_resume(struct device *dev)
 
        return ret;
 }
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id xgbe_acpi_match[] = {
index 8966f31..3acde3b 100644 (file)
@@ -1990,7 +1990,7 @@ SetMulticastFilter(struct net_device *dev)
 
 static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST;
 
-static int __init de4x5_eisa_probe (struct device *gendev)
+static int de4x5_eisa_probe(struct device *gendev)
 {
        struct eisa_device *edev;
        u_long iobase;
index 7923bfd..9016611 100644 (file)
@@ -1375,9 +1375,11 @@ static int gfar_probe(struct platform_device *ofdev)
 
        gfar_init_addr_hash_table(priv);
 
-       /* Insert receive time stamps into padding alignment bytes */
+       /* Insert receive time stamps into padding alignment bytes, and
+        * plus 2 bytes padding to ensure the cpu alignment.
+        */
        if (priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER)
-               priv->padding = 8;
+               priv->padding = 8 + DEFAULT_PADDING;
 
        if (dev->features & NETIF_F_IP_CSUM ||
            priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER)
index ae6e30d..3daf2d4 100644 (file)
@@ -194,7 +194,6 @@ static const char *hp100_isa_tbl[] = {
 };
 #endif
 
-#ifdef CONFIG_EISA
 static struct eisa_device_id hp100_eisa_tbl[] = {
        { "HWPF180" }, /* HP J2577 rev A */
        { "HWP1920" }, /* HP 27248B */
@@ -205,9 +204,7 @@ static struct eisa_device_id hp100_eisa_tbl[] = {
        { "" }         /* Mandatory final entry ! */
 };
 MODULE_DEVICE_TABLE(eisa, hp100_eisa_tbl);
-#endif
 
-#ifdef CONFIG_PCI
 static const struct pci_device_id hp100_pci_tbl[] = {
        {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A, PCI_ANY_ID, PCI_ANY_ID,},
        {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B, PCI_ANY_ID, PCI_ANY_ID,},
@@ -219,7 +216,6 @@ static const struct pci_device_id hp100_pci_tbl[] = {
        {}                      /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(pci, hp100_pci_tbl);
-#endif
 
 static int hp100_rx_ratio = HP100_DEFAULT_RX_RATIO;
 static int hp100_priority_tx = HP100_DEFAULT_PRIORITY_TX;
@@ -2842,8 +2838,7 @@ static void cleanup_dev(struct net_device *d)
        free_netdev(d);
 }
 
-#ifdef CONFIG_EISA
-static int __init hp100_eisa_probe (struct device *gendev)
+static int hp100_eisa_probe(struct device *gendev)
 {
        struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private));
        struct eisa_device *edev = to_eisa_device(gendev);
@@ -2884,9 +2879,7 @@ static struct eisa_driver hp100_eisa_driver = {
                .remove  = hp100_eisa_remove,
         }
 };
-#endif
 
-#ifdef CONFIG_PCI
 static int hp100_pci_probe(struct pci_dev *pdev,
                           const struct pci_device_id *ent)
 {
@@ -2955,7 +2948,6 @@ static struct pci_driver hp100_pci_driver = {
        .probe          = hp100_pci_probe,
        .remove         = hp100_pci_remove,
 };
-#endif
 
 /*
  *  module section
@@ -3032,23 +3024,17 @@ static int __init hp100_module_init(void)
        err = hp100_isa_init();
        if (err && err != -ENODEV)
                goto out;
-#ifdef CONFIG_EISA
        err = eisa_driver_register(&hp100_eisa_driver);
        if (err && err != -ENODEV)
                goto out2;
-#endif
-#ifdef CONFIG_PCI
        err = pci_register_driver(&hp100_pci_driver);
        if (err && err != -ENODEV)
                goto out3;
-#endif
  out:
        return err;
  out3:
-#ifdef CONFIG_EISA
        eisa_driver_unregister (&hp100_eisa_driver);
  out2:
-#endif
        hp100_isa_cleanup();
        goto out;
 }
@@ -3057,12 +3043,8 @@ static int __init hp100_module_init(void)
 static void __exit hp100_module_exit(void)
 {
        hp100_isa_cleanup();
-#ifdef CONFIG_EISA
        eisa_driver_unregister (&hp100_eisa_driver);
-#endif
-#ifdef CONFIG_PCI
        pci_unregister_driver (&hp100_pci_driver);
-#endif
 }
 
 module_init(hp100_module_init)
index 4f34e1b..ac92685 100644 (file)
@@ -5666,6 +5666,7 @@ static void mvpp2_set_rx_mode(struct net_device *dev)
        int id = port->id;
        bool allmulti = dev->flags & IFF_ALLMULTI;
 
+retry:
        mvpp2_prs_mac_promisc_set(priv, id, dev->flags & IFF_PROMISC);
        mvpp2_prs_mac_multi_set(priv, id, MVPP2_PE_MAC_MC_ALL, allmulti);
        mvpp2_prs_mac_multi_set(priv, id, MVPP2_PE_MAC_MC_IP6, allmulti);
@@ -5673,9 +5674,13 @@ static void mvpp2_set_rx_mode(struct net_device *dev)
        /* Remove all port->id's mcast enries */
        mvpp2_prs_mcast_del_all(priv, id);
 
-       if (allmulti && !netdev_mc_empty(dev)) {
-               netdev_for_each_mc_addr(ha, dev)
-                       mvpp2_prs_mac_da_accept(priv, id, ha->addr, true);
+       if (!allmulti) {
+               netdev_for_each_mc_addr(ha, dev) {
+                       if (mvpp2_prs_mac_da_accept(priv, id, ha->addr, true)) {
+                               allmulti = true;
+                               goto retry;
+                       }
+               }
        }
 }
 
index 168823d..d8359ff 100644 (file)
@@ -280,6 +280,9 @@ void mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt)
        u64 in_param = 0;
        int err;
 
+       if (!cnt)
+               return;
+
        if (mlx4_is_mfunc(dev)) {
                set_param_l(&in_param, base_qpn);
                set_param_h(&in_param, cnt);
index f9640d5..b4f3cb5 100644 (file)
@@ -3850,7 +3850,7 @@ static void qlcnic_83xx_flush_mbx_queue(struct qlcnic_adapter *adapter)
        struct list_head *head = &mbx->cmd_q;
        struct qlcnic_cmd_args *cmd = NULL;
 
-       spin_lock(&mbx->queue_lock);
+       spin_lock_bh(&mbx->queue_lock);
 
        while (!list_empty(head)) {
                cmd = list_entry(head->next, struct qlcnic_cmd_args, list);
@@ -3861,7 +3861,7 @@ static void qlcnic_83xx_flush_mbx_queue(struct qlcnic_adapter *adapter)
                qlcnic_83xx_notify_cmd_completion(adapter, cmd);
        }
 
-       spin_unlock(&mbx->queue_lock);
+       spin_unlock_bh(&mbx->queue_lock);
 }
 
 static int qlcnic_83xx_check_mbx_status(struct qlcnic_adapter *adapter)
@@ -3897,12 +3897,12 @@ static void qlcnic_83xx_dequeue_mbx_cmd(struct qlcnic_adapter *adapter,
 {
        struct qlcnic_mailbox *mbx = adapter->ahw->mailbox;
 
-       spin_lock(&mbx->queue_lock);
+       spin_lock_bh(&mbx->queue_lock);
 
        list_del(&cmd->list);
        mbx->num_cmds--;
 
-       spin_unlock(&mbx->queue_lock);
+       spin_unlock_bh(&mbx->queue_lock);
 
        qlcnic_83xx_notify_cmd_completion(adapter, cmd);
 }
@@ -3967,7 +3967,7 @@ static int qlcnic_83xx_enqueue_mbx_cmd(struct qlcnic_adapter *adapter,
                init_completion(&cmd->completion);
                cmd->rsp_opcode = QLC_83XX_MBX_RESPONSE_UNKNOWN;
 
-               spin_lock(&mbx->queue_lock);
+               spin_lock_bh(&mbx->queue_lock);
 
                list_add_tail(&cmd->list, &mbx->cmd_q);
                mbx->num_cmds++;
@@ -3975,7 +3975,7 @@ static int qlcnic_83xx_enqueue_mbx_cmd(struct qlcnic_adapter *adapter,
                *timeout = cmd->total_cmds * QLC_83XX_MBX_TIMEOUT;
                queue_work(mbx->work_q, &mbx->work);
 
-               spin_unlock(&mbx->queue_lock);
+               spin_unlock_bh(&mbx->queue_lock);
 
                return 0;
        }
@@ -4071,15 +4071,15 @@ static void qlcnic_83xx_mailbox_worker(struct work_struct *work)
                mbx->rsp_status = QLC_83XX_MBX_RESPONSE_WAIT;
                spin_unlock_irqrestore(&mbx->aen_lock, flags);
 
-               spin_lock(&mbx->queue_lock);
+               spin_lock_bh(&mbx->queue_lock);
 
                if (list_empty(head)) {
-                       spin_unlock(&mbx->queue_lock);
+                       spin_unlock_bh(&mbx->queue_lock);
                        return;
                }
                cmd = list_entry(head->next, struct qlcnic_cmd_args, list);
 
-               spin_unlock(&mbx->queue_lock);
+               spin_unlock_bh(&mbx->queue_lock);
 
                mbx_ops->encode_cmd(adapter, cmd);
                mbx_ops->nofity_fw(adapter, QLC_83XX_MBX_REQUEST);
index 2415538..3783c40 100644 (file)
@@ -1387,7 +1387,7 @@ DECLARE_RTL_COND(rtl_ocp_tx_cond)
 {
        void __iomem *ioaddr = tp->mmio_addr;
 
-       return RTL_R8(IBISR0) & 0x02;
+       return RTL_R8(IBISR0) & 0x20;
 }
 
 static void rtl8168ep_stop_cmac(struct rtl8169_private *tp)
@@ -1395,7 +1395,7 @@ static void rtl8168ep_stop_cmac(struct rtl8169_private *tp)
        void __iomem *ioaddr = tp->mmio_addr;
 
        RTL_W8(IBCR2, RTL_R8(IBCR2) & ~0x01);
-       rtl_msleep_loop_wait_low(tp, &rtl_ocp_tx_cond, 50, 2000);
+       rtl_msleep_loop_wait_high(tp, &rtl_ocp_tx_cond, 50, 2000);
        RTL_W8(IBISR0, RTL_R8(IBISR0) | 0x20);
        RTL_W8(IBCR0, RTL_R8(IBCR0) & ~0x01);
 }
index a274cd4..399a89f 100644 (file)
@@ -610,8 +610,8 @@ err_out_regions:
 #ifdef CONFIG_PCI
        if (pdev)
                pci_release_regions(pdev);
-#endif
 err_out:
+#endif
        if (pdev)
                pci_disable_device(pdev);
        return rc;
index 95c0b45..313e006 100644 (file)
@@ -1381,8 +1381,8 @@ static int rr_close(struct net_device *dev)
                            rrpriv->info_dma);
        rrpriv->info = NULL;
 
-       free_irq(pdev->irq, dev);
        spin_unlock_irqrestore(&rrpriv->lock, flags);
+       free_irq(pdev->irq, dev);
 
        return 0;
 }
index af827fa..8aecea0 100644 (file)
@@ -353,6 +353,7 @@ static int ipvlan_process_v4_outbound(struct sk_buff *skb)
                .flowi4_oif = dev->ifindex,
                .flowi4_tos = RT_TOS(ip4h->tos),
                .flowi4_flags = FLOWI_FLAG_ANYSRC,
+               .flowi4_mark = skb->mark,
                .daddr = ip4h->daddr,
                .saddr = ip4h->saddr,
        };
index 1f6893e..3a72862 100644 (file)
@@ -395,6 +395,10 @@ config USB_NET_RNDIS_HOST
          The protocol specification is incomplete, and is controlled by
          (and for) Microsoft; it isn't an "Open" ecosystem or market.
 
+config USB_NET_CDC_SUBSET_ENABLE
+       tristate
+       depends on USB_NET_CDC_SUBSET
+
 config USB_NET_CDC_SUBSET
        tristate "Simple USB Network Links (CDC Ethernet subset)"
        depends on USB_USBNET
@@ -413,6 +417,7 @@ config USB_NET_CDC_SUBSET
 config USB_ALI_M5632
        bool "ALi M5632 based 'USB 2.0 Data Link' cables"
        depends on USB_NET_CDC_SUBSET
+       select USB_NET_CDC_SUBSET_ENABLE
        help
          Choose this option if you're using a host-to-host cable
          based on this design, which supports USB 2.0 high speed.
@@ -420,6 +425,7 @@ config USB_ALI_M5632
 config USB_AN2720
        bool "AnchorChips 2720 based cables (Xircom PGUNET, ...)"
        depends on USB_NET_CDC_SUBSET
+       select USB_NET_CDC_SUBSET_ENABLE
        help
          Choose this option if you're using a host-to-host cable
          based on this design.  Note that AnchorChips is now a
@@ -428,6 +434,7 @@ config USB_AN2720
 config USB_BELKIN
        bool "eTEK based host-to-host cables (Advance, Belkin, ...)"
        depends on USB_NET_CDC_SUBSET
+       select USB_NET_CDC_SUBSET_ENABLE
        default y
        help
          Choose this option if you're using a host-to-host cable
@@ -437,6 +444,7 @@ config USB_BELKIN
 config USB_ARMLINUX
        bool "Embedded ARM Linux links (iPaq, ...)"
        depends on USB_NET_CDC_SUBSET
+       select USB_NET_CDC_SUBSET_ENABLE
        default y
        help
          Choose this option to support the "usb-eth" networking driver
@@ -454,6 +462,7 @@ config USB_ARMLINUX
 config USB_EPSON2888
        bool "Epson 2888 based firmware (DEVELOPMENT)"
        depends on USB_NET_CDC_SUBSET
+       select USB_NET_CDC_SUBSET_ENABLE
        help
          Choose this option to support the usb networking links used
          by some sample firmware from Epson.
@@ -461,6 +470,7 @@ config USB_EPSON2888
 config USB_KC2190
        bool "KT Technology KC2190 based cables (InstaNet)"
        depends on USB_NET_CDC_SUBSET
+       select USB_NET_CDC_SUBSET_ENABLE
        help
          Choose this option if you're using a host-to-host cable
          with one of these chips.
index b5f0406..37fb46a 100644 (file)
@@ -23,7 +23,7 @@ obj-$(CONFIG_USB_NET_GL620A)  += gl620a.o
 obj-$(CONFIG_USB_NET_NET1080)  += net1080.o
 obj-$(CONFIG_USB_NET_PLUSB)    += plusb.o
 obj-$(CONFIG_USB_NET_RNDIS_HOST)       += rndis_host.o
-obj-$(CONFIG_USB_NET_CDC_SUBSET)       += cdc_subset.o
+obj-$(CONFIG_USB_NET_CDC_SUBSET_ENABLE)        += cdc_subset.o
 obj-$(CONFIG_USB_NET_ZAURUS)   += zaurus.o
 obj-$(CONFIG_USB_NET_MCS7830)  += mcs7830.o
 obj-$(CONFIG_USB_USBNET)       += usbnet.o
index 1228d0d..72cb308 100644 (file)
@@ -825,6 +825,9 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
                goto error2;
        }
 
+       /* Device-specific flags */
+       ctx->drvflags = drvflags;
+
        /*
         * Some Huawei devices have been observed to come out of reset in NDP32 mode.
         * Let's check if this is the case, and set the device to NDP16 mode again if
@@ -873,9 +876,6 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
        /* finish setting up the device specific data */
        cdc_ncm_setup(dev);
 
-       /* Device-specific flags */
-       ctx->drvflags = drvflags;
-
        /* Allocate the delayed NDP if needed. */
        if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) {
                ctx->delayed_ndp16 = kzalloc(ctx->max_ndp_size, GFP_KERNEL);
index ece0eee..784a11a 100644 (file)
@@ -1303,7 +1303,7 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
        int ret;
        struct ath10k_fw_file *fw_file;
 
-       if (!ar->is_bmi && QCA_REV_WCN3990(ar)) {
+       if (!ar->is_bmi) {
                fw_file = &ar->normal_mode_fw.fw_file;
                fw_file->wmi_op_version = ATH10K_FW_WMI_OP_VERSION_TLV;
                fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_TLV;
index ed85f93..f760481 100644 (file)
@@ -174,8 +174,15 @@ static int ath10k_tm_fetch_utf_firmware_api_1(struct ath10k *ar,
 static int ath10k_tm_fetch_firmware(struct ath10k *ar)
 {
        struct ath10k_fw_components *utf_mode_fw;
+       struct ath10k_fw_file *fw_file;
        int ret;
 
+       if (!ar->is_bmi) {
+               fw_file = &ar->testmode.utf_mode_fw.fw_file;
+               fw_file->wmi_op_version = ATH10K_FW_WMI_OP_VERSION_TLV;
+               fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_TLV;
+               return 0;
+       }
        ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_UTF_API2_FILE,
                                               &ar->testmode.utf_mode_fw.fw_file);
        if (ret == 0) {
index 74a9206..262a1a1 100644 (file)
@@ -471,6 +471,7 @@ static void ath10k_wow_op_report_wakeup_reason(struct ath10k *ar)
        struct cfg80211_wowlan_wakeup *wakeup = &ar->wow.wakeup;
        struct ath10k_vif *arvif;
 
+       memset(wakeup, 0, sizeof(struct cfg80211_wowlan_wakeup));
        switch (ar->wow.wakeup_reason) {
        case WOW_REASON_UNSPECIFIED:
                wakeup = NULL;
@@ -488,6 +489,7 @@ static void ath10k_wow_op_report_wakeup_reason(struct ath10k *ar)
                wakeup->gtk_rekey_failure = true;
                break;
        }
+       ar->wow.wakeup_reason = WOW_REASON_UNSPECIFIED;
 
        if (wakeup) {
                wakeup->pattern_idx = -1;
index a740083..63f95e9 100644 (file)
@@ -446,8 +446,7 @@ static int cw1200_spi_disconnect(struct spi_device *func)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int cw1200_spi_suspend(struct device *dev)
+static int __maybe_unused cw1200_spi_suspend(struct device *dev)
 {
        struct hwbus_priv *self = spi_get_drvdata(to_spi_device(dev));
 
@@ -460,16 +459,12 @@ static int cw1200_spi_suspend(struct device *dev)
 
 static SIMPLE_DEV_PM_OPS(cw1200_pm_ops, cw1200_spi_suspend, NULL);
 
-#endif
-
 static struct spi_driver spi_driver = {
        .probe          = cw1200_spi_probe,
        .remove         = cw1200_spi_disconnect,
        .driver = {
                .name           = "cw1200_wlan_spi",
-#ifdef CONFIG_PM
-               .pm             = &cw1200_pm_ops,
-#endif
+               .pm             = IS_ENABLED(CONFIG_PM) ? &cw1200_pm_ops : NULL,
        },
 };
 
index 3ed90ff..5345484 100644 (file)
@@ -31,13 +31,18 @@ int cw1200_pm_init(struct cw1200_pm_state *pm,
 void cw1200_pm_deinit(struct cw1200_pm_state *pm);
 int cw1200_wow_suspend(struct ieee80211_hw *hw,
                       struct cfg80211_wowlan *wowlan);
-int cw1200_wow_resume(struct ieee80211_hw *hw);
 int cw1200_can_suspend(struct cw1200_common *priv);
+int cw1200_wow_resume(struct ieee80211_hw *hw);
 void cw1200_pm_stay_awake(struct cw1200_pm_state *pm,
                          unsigned long tmo);
 #else
 static inline void cw1200_pm_stay_awake(struct cw1200_pm_state *pm,
-                                       unsigned long tmo) {
+                                       unsigned long tmo)
+{
+}
+static inline int cw1200_can_suspend(struct cw1200_common *priv)
+{
+       return 0;
 }
 #endif
 #endif
index 9e0ca30..3dd46c7 100644 (file)
@@ -379,7 +379,6 @@ static int wsm_multi_tx_confirm(struct cw1200_common *priv,
 {
        int ret;
        int count;
-       int i;
 
        count = WSM_GET32(buf);
        if (WARN_ON(count <= 0))
@@ -395,11 +394,10 @@ static int wsm_multi_tx_confirm(struct cw1200_common *priv,
        }
 
        cw1200_debug_txed_multi(priv, count);
-       for (i = 0; i < count; ++i) {
+       do {
                ret = wsm_tx_confirm(priv, buf, link_id);
-               if (ret)
-                       return ret;
-       }
+       } while (!ret && --count);
+
        return ret;
 
 underflow:
index b57cfd9..7b13962 100644 (file)
@@ -2488,9 +2488,9 @@ void rtl8821ae_dm_txpower_tracking_callback_thermalmeter(
                for (p = RF90_PATH_A; p < MAX_PATH_NUM_8821A; p++)
                        rtldm->swing_idx_ofdm_base[p] = rtldm->swing_idx_ofdm[p];
 
-                       RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
-                                "pDM_Odm->RFCalibrateInfo.ThermalValue = %d ThermalValue= %d\n",
-                                rtldm->thermalvalue, thermal_value);
+               RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+                        "pDM_Odm->RFCalibrateInfo.ThermalValue = %d ThermalValue= %d\n",
+                        rtldm->thermalvalue, thermal_value);
                /*Record last Power Tracking Thermal Value*/
                rtldm->thermalvalue = thermal_value;
        }
index 738d541..348ed1b 100644 (file)
@@ -1127,7 +1127,7 @@ static u8 _rtl8821ae_dbi_read(struct rtl_priv *rtlpriv, u16 addr)
        }
        if (0 == tmp) {
                read_addr = REG_DBI_RDATA + addr % 4;
-               ret = rtl_read_word(rtlpriv, read_addr);
+               ret = rtl_read_byte(rtlpriv, read_addr);
        }
        return ret;
 }
@@ -1169,7 +1169,8 @@ static void _rtl8821ae_enable_aspm_back_door(struct ieee80211_hw *hw)
        }
 
        tmp = _rtl8821ae_dbi_read(rtlpriv, 0x70f);
-       _rtl8821ae_dbi_write(rtlpriv, 0x70f, tmp | BIT(7));
+       _rtl8821ae_dbi_write(rtlpriv, 0x70f, tmp | BIT(7) |
+                            ASPM_L1_LATENCY << 3);
 
        tmp = _rtl8821ae_dbi_read(rtlpriv, 0x719);
        _rtl8821ae_dbi_write(rtlpriv, 0x719, tmp | BIT(3) | BIT(4));
index b6faf62..d676d05 100644 (file)
@@ -99,6 +99,7 @@
 #define RTL_USB_MAX_RX_COUNT                   100
 #define QBSS_LOAD_SIZE                         5
 #define MAX_WMMELE_LENGTH                      64
+#define ASPM_L1_LATENCY                                7
 
 #define TOTAL_CAM_ENTRY                                32
 
index d6ceb8b..1c8aedf 100644 (file)
@@ -2976,10 +2976,16 @@ static void nvme_dev_shutdown(struct nvme_dev *dev)
        mutex_unlock(&dev->shutdown_lock);
 }
 
-static void nvme_dev_remove(struct nvme_dev *dev)
+static void nvme_remove_namespaces(struct nvme_dev *dev)
 {
        struct nvme_ns *ns, *next;
 
+       list_for_each_entry_safe(ns, next, &dev->namespaces, list)
+               nvme_ns_remove(ns);
+}
+
+static void nvme_dev_remove(struct nvme_dev *dev)
+{
        if (nvme_io_incapable(dev)) {
                /*
                 * If the device is not capable of IO (surprise hot-removal,
@@ -2989,8 +2995,7 @@ static void nvme_dev_remove(struct nvme_dev *dev)
                 */
                nvme_dev_shutdown(dev);
        }
-       list_for_each_entry_safe(ns, next, &dev->namespaces, list)
-               nvme_ns_remove(ns);
+       nvme_remove_namespaces(dev);
 }
 
 static int nvme_setup_prp_pools(struct nvme_dev *dev)
@@ -3174,7 +3179,7 @@ static void nvme_probe_work(struct work_struct *work)
         */
        if (dev->online_queues < 2) {
                dev_warn(dev->dev, "IO queues not created\n");
-               nvme_dev_remove(dev);
+               nvme_remove_namespaces(dev);
        } else {
                nvme_unfreeze_queues(dev);
                nvme_dev_add(dev);
index 1b580ba..907d7db 100644 (file)
@@ -145,19 +145,19 @@ static const struct sunxi_desc_pin sun9i_a80_pins[] = {
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x3, "mcsi"),          /* MCLK */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 14)), /* PB_EINT14 */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 14)), /* PB_EINT14 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 15),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x3, "mcsi"),          /* SCK */
                  SUNXI_FUNCTION(0x4, "i2c4"),          /* SCK */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 15)), /* PB_EINT15 */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 15)), /* PB_EINT15 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 16),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x3, "mcsi"),          /* SDA */
                  SUNXI_FUNCTION(0x4, "i2c4"),          /* SDA */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 16)), /* PB_EINT16 */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 16)), /* PB_EINT16 */
 
        /* Hole */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 0),
index 4a68b96..7cc3c38 100644 (file)
@@ -51,6 +51,7 @@ int __ipa_generate_rt_hw_rule_v2(enum ipa_ip_type ip,
        u32 tmp[IPA_RT_FLT_HW_RULE_BUF_SIZE/4];
        u8 *start;
        int pipe_idx;
+       struct ipa_hdr_entry *hdr_entry;
 
        if (buf == NULL) {
                memset(tmp, 0, (IPA_RT_FLT_HW_RULE_BUF_SIZE/4));
@@ -74,6 +75,18 @@ int __ipa_generate_rt_hw_rule_v2(enum ipa_ip_type ip,
        }
        rule_hdr->u.hdr.pipe_dest_idx = pipe_idx;
        rule_hdr->u.hdr.system = !ipa_ctx->hdr_tbl_lcl;
+
+       /* Adding check to confirm still
+        * header entry present in header table or not
+        */
+
+       if (entry->hdr) {
+               hdr_entry = ipa_id_find(entry->rule.hdr_hdl);
+               if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) {
+                       IPAERR_RL("Header entry already deleted\n");
+                       return -EPERM;
+               }
+       }
        if (entry->hdr) {
                if (entry->hdr->cookie == IPA_HDR_COOKIE) {
                        rule_hdr->u.hdr.hdr_offset =
@@ -140,6 +153,8 @@ int __ipa_generate_rt_hw_rule_v2_5(enum ipa_ip_type ip,
        u32 tmp[IPA_RT_FLT_HW_RULE_BUF_SIZE/4];
        u8 *start;
        int pipe_idx;
+       struct ipa_hdr_entry *hdr_entry;
+       struct ipa_hdr_proc_ctx_entry *hdr_proc_entry;
 
        if (buf == NULL) {
                memset(tmp, 0, IPA_RT_FLT_HW_RULE_BUF_SIZE);
@@ -162,6 +177,24 @@ int __ipa_generate_rt_hw_rule_v2_5(enum ipa_ip_type ip,
                return -EPERM;
        }
        rule_hdr->u.hdr_v2_5.pipe_dest_idx = pipe_idx;
+       /* Adding check to confirm still
+        * header entry present in header table or not
+        */
+
+       if (entry->hdr) {
+               hdr_entry = ipa_id_find(entry->rule.hdr_hdl);
+               if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) {
+                       IPAERR_RL("Header entry already deleted\n");
+                       return -EPERM;
+               }
+       } else if (entry->proc_ctx) {
+               hdr_proc_entry = ipa_id_find(entry->rule.hdr_proc_ctx_hdl);
+               if (!hdr_proc_entry ||
+                       hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) {
+                       IPAERR_RL("Proc header entry already deleted\n");
+                       return -EPERM;
+               }
+       }
        if (entry->proc_ctx || (entry->hdr && entry->hdr->is_hdr_proc_ctx)) {
                struct ipa_hdr_proc_ctx_entry *proc_ctx;
 
@@ -1130,6 +1163,8 @@ int __ipa_del_rt_rule(u32 rule_hdl)
 {
        struct ipa_rt_entry *entry;
        int id;
+       struct ipa_hdr_entry *hdr_entry;
+       struct ipa_hdr_proc_ctx_entry *hdr_proc_entry;
 
        entry = ipa_id_find(rule_hdl);
 
@@ -1151,6 +1186,24 @@ int __ipa_del_rt_rule(u32 rule_hdl)
                        return -EINVAL;
                }
        }
+       /* Adding check to confirm still
+        * header entry present in header table or not
+        */
+
+       if (entry->hdr) {
+               hdr_entry = ipa_id_find(entry->rule.hdr_hdl);
+               if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) {
+                       IPAERR_RL("Header entry already deleted\n");
+                       return -EINVAL;
+               }
+       } else if (entry->proc_ctx) {
+               hdr_proc_entry = ipa_id_find(entry->rule.hdr_proc_ctx_hdl);
+               if (!hdr_proc_entry ||
+                       hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) {
+                       IPAERR_RL("Proc header entry already deleted\n");
+                       return -EINVAL;
+               }
+       }
 
        if (entry->hdr)
                __ipa_release_hdr(entry->hdr->id);
@@ -1463,6 +1516,7 @@ static int __ipa_mdfy_rt_rule(struct ipa_rt_rule_mdfy *rtrule)
 {
        struct ipa_rt_entry *entry;
        struct ipa_hdr_entry *hdr = NULL;
+       struct ipa_hdr_entry *hdr_entry;
 
        if (rtrule->rule.hdr_hdl) {
                hdr = ipa_id_find(rtrule->rule.hdr_hdl);
@@ -1483,6 +1537,17 @@ static int __ipa_mdfy_rt_rule(struct ipa_rt_rule_mdfy *rtrule)
                goto error;
        }
 
+       /* Adding check to confirm still
+        * header entry present in header table or not
+        */
+
+       if (entry->hdr) {
+               hdr_entry = ipa_id_find(entry->rule.hdr_hdl);
+               if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) {
+                       IPAERR_RL("Header entry already deleted\n");
+                       return -EPERM;
+               }
+       }
        if (entry->hdr)
                entry->hdr->ref_cnt--;
 
index a10e2cb..fd455f7 100644 (file)
@@ -50,6 +50,8 @@ static int ipa_generate_rt_hw_rule(enum ipa_ip_type ip,
        struct ipa3_rt_entry *entry, u8 *buf)
 {
        struct ipahal_rt_rule_gen_params gen_params;
+       struct ipa3_hdr_entry *hdr_entry;
+       struct ipa3_hdr_proc_ctx_entry *hdr_proc_entry;
        int res = 0;
 
        memset(&gen_params, 0, sizeof(gen_params));
@@ -69,6 +71,25 @@ static int ipa_generate_rt_hw_rule(enum ipa_ip_type ip,
                return -EPERM;
        }
 
+       /* Adding check to confirm still
+        * header entry present in header table or not
+        */
+
+       if (entry->hdr) {
+               hdr_entry = ipa3_id_find(entry->rule.hdr_hdl);
+               if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) {
+                       IPAERR_RL("Header entry already deleted\n");
+                       return -EPERM;
+               }
+       } else if (entry->proc_ctx) {
+               hdr_proc_entry = ipa3_id_find(entry->rule.hdr_proc_ctx_hdl);
+               if (!hdr_proc_entry ||
+                       hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) {
+                       IPAERR_RL("Proc header entry already deleted\n");
+                       return -EPERM;
+               }
+       }
+
        if (entry->proc_ctx || (entry->hdr && entry->hdr->is_hdr_proc_ctx)) {
                struct ipa3_hdr_proc_ctx_entry *proc_ctx;
                proc_ctx = (entry->proc_ctx) ? : entry->hdr->proc_ctx;
@@ -1268,6 +1289,8 @@ int __ipa3_del_rt_rule(u32 rule_hdl)
 {
        struct ipa3_rt_entry *entry;
        int id;
+       struct ipa3_hdr_entry *hdr_entry;
+       struct ipa3_hdr_proc_ctx_entry *hdr_proc_entry;
 
        entry = ipa3_id_find(rule_hdl);
 
@@ -1290,6 +1313,25 @@ int __ipa3_del_rt_rule(u32 rule_hdl)
                }
        }
 
+       /* Adding check to confirm still
+        * header entry present in header table or not
+        */
+
+       if (entry->hdr) {
+               hdr_entry = ipa3_id_find(entry->rule.hdr_hdl);
+               if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) {
+                       IPAERR_RL("Header entry already deleted\n");
+                       return -EINVAL;
+               }
+       } else if (entry->proc_ctx) {
+               hdr_proc_entry = ipa3_id_find(entry->rule.hdr_proc_ctx_hdl);
+               if (!hdr_proc_entry ||
+                       hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) {
+                       IPAERR_RL("Proc header entry already deleted\n");
+                       return -EINVAL;
+               }
+       }
+
        if (entry->hdr)
                __ipa3_release_hdr(entry->hdr->id);
        else if (entry->proc_ctx)
@@ -1609,7 +1651,8 @@ static int __ipa_mdfy_rt_rule(struct ipa_rt_rule_mdfy *rtrule)
        struct ipa3_rt_entry *entry;
        struct ipa3_hdr_entry *hdr = NULL;
        struct ipa3_hdr_proc_ctx_entry *proc_ctx = NULL;
-
+       struct ipa3_hdr_entry *hdr_entry;
+       struct ipa3_hdr_proc_ctx_entry *hdr_proc_entry;
        if (rtrule->rule.hdr_hdl) {
                hdr = ipa3_id_find(rtrule->rule.hdr_hdl);
                if ((hdr == NULL) || (hdr->cookie != IPA_HDR_COOKIE)) {
@@ -1636,6 +1679,25 @@ static int __ipa_mdfy_rt_rule(struct ipa_rt_rule_mdfy *rtrule)
                goto error;
        }
 
+       /* Adding check to confirm still
+        * header entry present in header table or not
+        */
+
+       if (entry->hdr) {
+               hdr_entry = ipa3_id_find(entry->rule.hdr_hdl);
+               if (!hdr_entry || hdr_entry->cookie != IPA_HDR_COOKIE) {
+                       IPAERR_RL("Header entry already deleted\n");
+                       return -EPERM;
+               }
+       } else if (entry->proc_ctx) {
+               hdr_proc_entry = ipa3_id_find(entry->rule.hdr_proc_ctx_hdl);
+               if (!hdr_proc_entry ||
+                       hdr_proc_entry->cookie != IPA_PROC_HDR_COOKIE) {
+                       IPAERR_RL("Proc header entry already deleted\n");
+                       return -EPERM;
+               }
+       }
+
        if (entry->hdr)
                entry->hdr->ref_cnt--;
        if (entry->proc_ctx)
index 1089eaa..988ebe9 100644 (file)
@@ -95,6 +95,7 @@ config DELL_LAPTOP
        tristate "Dell Laptop Extras"
        depends on X86
        depends on DCDBAS
+       depends on DMI
        depends on BACKLIGHT_CLASS_DEVICE
        depends on ACPI_VIDEO || ACPI_VIDEO = n
        depends on RFKILL || RFKILL = n
@@ -110,6 +111,7 @@ config DELL_LAPTOP
 config DELL_WMI
        tristate "Dell WMI extras"
        depends on ACPI_WMI
+       depends on DMI
        depends on INPUT
        depends on ACPI_VIDEO || ACPI_VIDEO = n
        select INPUT_SPARSEKMAP
index 5c768c4..78e1bfe 100644 (file)
@@ -415,6 +415,7 @@ static struct thermal_device_info *initialize_sensor(int index)
        return td_info;
 }
 
+#ifdef CONFIG_PM_SLEEP
 /**
  * mid_thermal_resume - resume routine
  * @dev: device structure
@@ -442,6 +443,7 @@ static int mid_thermal_suspend(struct device *dev)
         */
        return configure_adc(0);
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(mid_thermal_pm,
                         mid_thermal_suspend, mid_thermal_resume);
index 89aa976..65b0a48 100644 (file)
@@ -52,7 +52,9 @@ struct tc1100_data {
        u32 jogdial;
 };
 
+#ifdef CONFIG_PM
 static struct tc1100_data suspend_data;
+#endif
 
 /* --------------------------------------------------------------------------
                                Device Management
index 91fdeaf..8017e9a 100644 (file)
@@ -159,6 +159,7 @@ config BATTERY_SBS
 
 config BATTERY_BQ27XXX
        tristate "BQ27xxx battery driver"
+       depends on I2C || I2C=n
        help
          Say Y here to enable support for batteries with BQ27xxx (I2C/HDQ) chips.
 
index 880233c..6c3a447 100644 (file)
@@ -285,7 +285,7 @@ static u8 bq27421_regs[] = {
        0x18,   /* AP           */
 };
 
-static u8 *bq27xxx_regs[] = {
+static u8 *bq27xxx_regs[] __maybe_unused = {
        [BQ27000] = bq27000_regs,
        [BQ27010] = bq27010_regs,
        [BQ27500] = bq27500_regs,
@@ -991,7 +991,7 @@ static void bq27xxx_external_power_changed(struct power_supply *psy)
        schedule_delayed_work(&di->work, 0);
 }
 
-static int bq27xxx_powersupply_init(struct bq27xxx_device_info *di,
+static int __maybe_unused bq27xxx_powersupply_init(struct bq27xxx_device_info *di,
                                    const char *name)
 {
        int ret;
@@ -1026,7 +1026,7 @@ static int bq27xxx_powersupply_init(struct bq27xxx_device_info *di,
        return 0;
 }
 
-static void bq27xxx_powersupply_unregister(struct bq27xxx_device_info *di)
+static void __maybe_unused bq27xxx_powersupply_unregister(struct bq27xxx_device_info *di)
 {
        /*
         * power_supply_unregister call bq27xxx_battery_get_property which
index 50ca3c3..d4ab6c4 100644 (file)
@@ -1636,5 +1636,13 @@ config RTC_DRV_HID_SENSOR_TIME
          If this driver is compiled as a module, it will be named
          rtc-hid-sensor-time.
 
+config RTC_DRV_GOLDFISH
+       tristate "Goldfish Real Time Clock"
+       depends on MIPS && (GOLDFISH || COMPILE_TEST)
+       help
+         Say yes to enable RTC driver for the Goldfish based virtual platform.
+
+         Goldfish is a code name for the virtual platform developed by Google
+         for Android emulation.
 
 endif # RTC_CLASS
index f264c34..138a643 100644 (file)
@@ -162,3 +162,4 @@ obj-$(CONFIG_RTC_DRV_WM8350)        += rtc-wm8350.o
 obj-$(CONFIG_RTC_DRV_X1205)    += rtc-x1205.o
 obj-$(CONFIG_RTC_DRV_XGENE)    += rtc-xgene.o
 obj-$(CONFIG_RTC_DRV_ZYNQMP)   += rtc-zynqmp.o
+obj-$(CONFIG_RTC_DRV_GOLDFISH) += rtc-goldfish.o
diff --git a/drivers/rtc/rtc-goldfish.c b/drivers/rtc/rtc-goldfish.c
new file mode 100644 (file)
index 0000000..d677692
--- /dev/null
@@ -0,0 +1,237 @@
+/* drivers/rtc/rtc-goldfish.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (C) 2017 Imagination Technologies Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/io.h>
+
+#define TIMER_TIME_LOW         0x00    /* get low bits of current time  */
+                                       /*   and update TIMER_TIME_HIGH  */
+#define TIMER_TIME_HIGH        0x04    /* get high bits of time at last */
+                                       /*   TIMER_TIME_LOW read         */
+#define TIMER_ALARM_LOW        0x08    /* set low bits of alarm and     */
+                                       /*   activate it                 */
+#define TIMER_ALARM_HIGH       0x0c    /* set high bits of next alarm   */
+#define TIMER_IRQ_ENABLED      0x10
+#define TIMER_CLEAR_ALARM      0x14
+#define TIMER_ALARM_STATUS     0x18
+#define TIMER_CLEAR_INTERRUPT  0x1c
+
+struct goldfish_rtc {
+       void __iomem *base;
+       int irq;
+       struct rtc_device *rtc;
+};
+
+static int goldfish_rtc_read_alarm(struct device *dev,
+                                  struct rtc_wkalrm *alrm)
+{
+       u64 rtc_alarm;
+       u64 rtc_alarm_low;
+       u64 rtc_alarm_high;
+       void __iomem *base;
+       struct goldfish_rtc *rtcdrv;
+
+       rtcdrv = dev_get_drvdata(dev);
+       base = rtcdrv->base;
+
+       rtc_alarm_low = readl(base + TIMER_ALARM_LOW);
+       rtc_alarm_high = readl(base + TIMER_ALARM_HIGH);
+       rtc_alarm = (rtc_alarm_high << 32) | rtc_alarm_low;
+
+       do_div(rtc_alarm, NSEC_PER_SEC);
+       memset(alrm, 0, sizeof(struct rtc_wkalrm));
+
+       rtc_time_to_tm(rtc_alarm, &alrm->time);
+
+       if (readl(base + TIMER_ALARM_STATUS))
+               alrm->enabled = 1;
+       else
+               alrm->enabled = 0;
+
+       return 0;
+}
+
+static int goldfish_rtc_set_alarm(struct device *dev,
+                                 struct rtc_wkalrm *alrm)
+{
+       struct goldfish_rtc *rtcdrv;
+       unsigned long rtc_alarm;
+       u64 rtc_alarm64;
+       u64 rtc_status_reg;
+       void __iomem *base;
+       int ret = 0;
+
+       rtcdrv = dev_get_drvdata(dev);
+       base = rtcdrv->base;
+
+       if (alrm->enabled) {
+               ret = rtc_tm_to_time(&alrm->time, &rtc_alarm);
+               if (ret != 0)
+                       return ret;
+
+               rtc_alarm64 = rtc_alarm * NSEC_PER_SEC;
+               writel((rtc_alarm64 >> 32), base + TIMER_ALARM_HIGH);
+               writel(rtc_alarm64, base + TIMER_ALARM_LOW);
+       } else {
+               /*
+                * if this function was called with enabled=0
+                * then it could mean that the application is
+                * trying to cancel an ongoing alarm
+                */
+               rtc_status_reg = readl(base + TIMER_ALARM_STATUS);
+               if (rtc_status_reg)
+                       writel(1, base + TIMER_CLEAR_ALARM);
+       }
+
+       return ret;
+}
+
+static int goldfish_rtc_alarm_irq_enable(struct device *dev,
+                                        unsigned int enabled)
+{
+       void __iomem *base;
+       struct goldfish_rtc *rtcdrv;
+
+       rtcdrv = dev_get_drvdata(dev);
+       base = rtcdrv->base;
+
+       if (enabled)
+               writel(1, base + TIMER_IRQ_ENABLED);
+       else
+               writel(0, base + TIMER_IRQ_ENABLED);
+
+       return 0;
+}
+
+static irqreturn_t goldfish_rtc_interrupt(int irq, void *dev_id)
+{
+       struct goldfish_rtc *rtcdrv = dev_id;
+       void __iomem *base = rtcdrv->base;
+
+       writel(1, base + TIMER_CLEAR_INTERRUPT);
+
+       rtc_update_irq(rtcdrv->rtc, 1, RTC_IRQF | RTC_AF);
+
+       return IRQ_HANDLED;
+}
+
+static int goldfish_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct goldfish_rtc *rtcdrv;
+       void __iomem *base;
+       u64 time_high;
+       u64 time_low;
+       u64 time;
+
+       rtcdrv = dev_get_drvdata(dev);
+       base = rtcdrv->base;
+
+       time_low = readl(base + TIMER_TIME_LOW);
+       time_high = readl(base + TIMER_TIME_HIGH);
+       time = (time_high << 32) | time_low;
+
+       do_div(time, NSEC_PER_SEC);
+
+       rtc_time_to_tm(time, tm);
+
+       return 0;
+}
+
+static int goldfish_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct goldfish_rtc *rtcdrv;
+       void __iomem *base;
+       unsigned long now;
+       u64 now64;
+       int ret;
+
+       rtcdrv = dev_get_drvdata(dev);
+       base = rtcdrv->base;
+
+       ret = rtc_tm_to_time(tm, &now);
+       if (ret == 0) {
+               now64 = now * NSEC_PER_SEC;
+               writel((now64 >> 32), base + TIMER_TIME_HIGH);
+               writel(now64, base + TIMER_TIME_LOW);
+       }
+
+       return ret;
+}
+
+static const struct rtc_class_ops goldfish_rtc_ops = {
+       .read_time      = goldfish_rtc_read_time,
+       .set_time       = goldfish_rtc_set_time,
+       .read_alarm     = goldfish_rtc_read_alarm,
+       .set_alarm      = goldfish_rtc_set_alarm,
+       .alarm_irq_enable = goldfish_rtc_alarm_irq_enable
+};
+
+static int goldfish_rtc_probe(struct platform_device *pdev)
+{
+       struct goldfish_rtc *rtcdrv;
+       struct resource *r;
+       int err;
+
+       rtcdrv = devm_kzalloc(&pdev->dev, sizeof(*rtcdrv), GFP_KERNEL);
+       if (!rtcdrv)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, rtcdrv);
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!r)
+               return -ENODEV;
+
+       rtcdrv->base = devm_ioremap_resource(&pdev->dev, r);
+       if (IS_ERR(rtcdrv->base))
+               return -ENODEV;
+
+       rtcdrv->irq = platform_get_irq(pdev, 0);
+       if (rtcdrv->irq < 0)
+               return -ENODEV;
+
+       rtcdrv->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
+                                              &goldfish_rtc_ops,
+                                              THIS_MODULE);
+       if (IS_ERR(rtcdrv->rtc))
+               return PTR_ERR(rtcdrv->rtc);
+
+       err = devm_request_irq(&pdev->dev, rtcdrv->irq,
+                              goldfish_rtc_interrupt,
+                              0, pdev->name, rtcdrv);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+static const struct of_device_id goldfish_rtc_of_match[] = {
+       { .compatible = "google,goldfish-rtc", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, goldfish_rtc_of_match);
+
+static struct platform_driver goldfish_rtc = {
+       .probe = goldfish_rtc_probe,
+       .driver = {
+               .name = "goldfish_rtc",
+               .of_match_table = goldfish_rtc_of_match,
+       }
+};
+
+module_platform_driver(goldfish_rtc);
index df39ce0..229dd2f 100644 (file)
@@ -58,6 +58,7 @@ static void tm_to_opal(struct rtc_time *tm, u32 *y_m_d, u64 *h_m_s_ms)
 static int opal_get_rtc_time(struct device *dev, struct rtc_time *tm)
 {
        long rc = OPAL_BUSY;
+       int retries = 10;
        u32 y_m_d;
        u64 h_m_s_ms;
        __be32 __y_m_d;
@@ -67,8 +68,11 @@ static int opal_get_rtc_time(struct device *dev, struct rtc_time *tm)
                rc = opal_rtc_read(&__y_m_d, &__h_m_s_ms);
                if (rc == OPAL_BUSY_EVENT)
                        opal_poll_events(NULL);
-               else
+               else if (retries-- && (rc == OPAL_HARDWARE
+                                      || rc == OPAL_INTERNAL_ERROR))
                        msleep(10);
+               else if (rc != OPAL_BUSY && rc != OPAL_BUSY_EVENT)
+                       break;
        }
 
        if (rc != OPAL_SUCCESS)
@@ -84,6 +88,7 @@ static int opal_get_rtc_time(struct device *dev, struct rtc_time *tm)
 static int opal_set_rtc_time(struct device *dev, struct rtc_time *tm)
 {
        long rc = OPAL_BUSY;
+       int retries = 10;
        u32 y_m_d = 0;
        u64 h_m_s_ms = 0;
 
@@ -92,8 +97,11 @@ static int opal_set_rtc_time(struct device *dev, struct rtc_time *tm)
                rc = opal_rtc_write(y_m_d, h_m_s_ms);
                if (rc == OPAL_BUSY_EVENT)
                        opal_poll_events(NULL);
-               else
+               else if (retries-- && (rc == OPAL_HARDWARE
+                                      || rc == OPAL_INTERNAL_ERROR))
                        msleep(10);
+               else if (rc != OPAL_BUSY && rc != OPAL_BUSY_EVENT)
+                       break;
        }
 
        return rc == OPAL_SUCCESS ? 0 : -EIO;
index 9083247..21d174e 100644 (file)
@@ -518,10 +518,12 @@ static int prefix_LRE(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata,
        pfxdata->validity.define_extent = 1;
 
        /* private uid is kept up to date, conf_data may be outdated */
-       if (startpriv->uid.type != UA_BASE_DEVICE) {
+       if (startpriv->uid.type == UA_BASE_PAV_ALIAS)
                pfxdata->validity.verify_base = 1;
-               if (startpriv->uid.type == UA_HYPER_PAV_ALIAS)
-                       pfxdata->validity.hyper_pav = 1;
+
+       if (startpriv->uid.type == UA_HYPER_PAV_ALIAS) {
+               pfxdata->validity.verify_base = 1;
+               pfxdata->validity.hyper_pav = 1;
        }
 
        /* define extend data (mostly)*/
@@ -3002,10 +3004,12 @@ static int prepare_itcw(struct itcw *itcw,
        pfxdata.validity.define_extent = 1;
 
        /* private uid is kept up to date, conf_data may be outdated */
-       if (startpriv->uid.type != UA_BASE_DEVICE) {
+       if (startpriv->uid.type == UA_BASE_PAV_ALIAS)
+               pfxdata.validity.verify_base = 1;
+
+       if (startpriv->uid.type == UA_HYPER_PAV_ALIAS) {
                pfxdata.validity.verify_base = 1;
-               if (startpriv->uid.type == UA_HYPER_PAV_ALIAS)
-                       pfxdata.validity.hyper_pav = 1;
+               pfxdata.validity.hyper_pav = 1;
        }
 
        switch (cmd) {
index febbd83..24e57e7 100644 (file)
@@ -6291,18 +6291,17 @@ static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *asc_dvc, uchar syn_time)
 static uchar
 AscMsgOutSDTR(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar sdtr_offset)
 {
-       EXT_MSG sdtr_buf;
-       uchar sdtr_period_index;
-       PortAddr iop_base;
-
-       iop_base = asc_dvc->iop_base;
-       sdtr_buf.msg_type = EXTENDED_MESSAGE;
-       sdtr_buf.msg_len = MS_SDTR_LEN;
-       sdtr_buf.msg_req = EXTENDED_SDTR;
-       sdtr_buf.xfer_period = sdtr_period;
+       PortAddr iop_base = asc_dvc->iop_base;
+       uchar sdtr_period_index = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
+       EXT_MSG sdtr_buf = {
+               .msg_type = EXTENDED_MESSAGE,
+               .msg_len = MS_SDTR_LEN,
+               .msg_req = EXTENDED_SDTR,
+               .xfer_period = sdtr_period,
+               .req_ack_offset = sdtr_offset,
+       };
        sdtr_offset &= ASC_SYN_MAX_OFFSET;
-       sdtr_buf.req_ack_offset = sdtr_offset;
-       sdtr_period_index = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
+
        if (sdtr_period_index <= asc_dvc->max_sdtr_index) {
                AscMemWordCopyPtrToLram(iop_base, ASCV_MSGOUT_BEG,
                                        (uchar *)&sdtr_buf,
@@ -11030,6 +11029,9 @@ static int advansys_board_found(struct Scsi_Host *shost, unsigned int iop,
                ASC_DBG(2, "AdvInitGetConfig()\n");
 
                ret = AdvInitGetConfig(pdev, shost) ? -ENODEV : 0;
+#else
+               share_irq = 0;
+               ret = -ENODEV;
 #endif /* CONFIG_PCI */
        }
 
index d4cda5e..21c8d21 100644 (file)
@@ -180,11 +180,14 @@ static u8 adpt_read_blink_led(adpt_hba* host)
  *============================================================================
  */
 
+#ifdef MODULE
 static struct pci_device_id dptids[] = {
        { PCI_DPT_VENDOR_ID, PCI_DPT_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
        { PCI_DPT_VENDOR_ID, PCI_DPT_RAPTOR_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
        { 0, }
 };
+#endif
+
 MODULE_DEVICE_TABLE(pci,dptids);
 
 static int adpt_detect(struct scsi_host_template* sht)
index eefe14d..b87ab38 100644 (file)
@@ -1768,7 +1768,7 @@ struct scsi_host_template fdomain_driver_template = {
 };
 
 #ifndef PCMCIA
-#ifdef CONFIG_PCI
+#if defined(CONFIG_PCI) && defined(MODULE)
 
 static struct pci_device_id fdomain_pci_tbl[] = {
        { PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70,
index f8d2478..87e081f 100644 (file)
@@ -538,7 +538,10 @@ static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst,
                        printk(KERN_ERR "53C400r: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks);
                        return -1;
                }
-               while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY);
+               while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
+               {
+                       // FIXME - no timeout
+               }
 
 #ifndef SCSI_G_NCR5380_MEM
                {
index 6a926ba..7a91cf3 100644 (file)
 #define i91u_MAXQUEUE          2
 #define i91u_REVID "Initio INI-9X00U/UW SCSI device driver; Revision: 1.04a"
 
-#define I950_DEVICE_ID 0x9500  /* Initio's inic-950 product ID   */
-#define I940_DEVICE_ID 0x9400  /* Initio's inic-940 product ID   */
-#define I935_DEVICE_ID 0x9401  /* Initio's inic-935 product ID   */
-#define I920_DEVICE_ID 0x0002  /* Initio's other product ID      */
-
 #ifdef DEBUG_i91u
 static unsigned int i91u_debug = DEBUG_DEFAULT;
 #endif
@@ -127,17 +122,6 @@ static int setup_debug = 0;
 
 static void i91uSCBPost(u8 * pHcb, u8 * pScb);
 
-/* PCI Devices supported by this driver */
-static struct pci_device_id i91u_pci_devices[] = {
-       { PCI_VENDOR_ID_INIT,  I950_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       { PCI_VENDOR_ID_INIT,  I940_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       { PCI_VENDOR_ID_INIT,  I935_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       { PCI_VENDOR_ID_INIT,  I920_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       { PCI_VENDOR_ID_DOMEX, I920_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       { }
-};
-MODULE_DEVICE_TABLE(pci, i91u_pci_devices);
-
 #define DEBUG_INTERRUPT 0
 #define DEBUG_QUEUE     0
 #define DEBUG_STATE     0
index 02360de..3928507 100644 (file)
@@ -2629,7 +2629,7 @@ static void mvumi_shutdown(struct pci_dev *pdev)
        mvumi_flush_cache(mhba);
 }
 
-static int mvumi_suspend(struct pci_dev *pdev, pm_message_t state)
+static int __maybe_unused mvumi_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct mvumi_hba *mhba = NULL;
 
@@ -2648,7 +2648,7 @@ static int mvumi_suspend(struct pci_dev *pdev, pm_message_t state)
        return 0;
 }
 
-static int mvumi_resume(struct pci_dev *pdev)
+static int __maybe_unused mvumi_resume(struct pci_dev *pdev)
 {
        int ret;
        struct mvumi_hba *mhba = NULL;
index 3b3b56f..82ed998 100644 (file)
@@ -176,8 +176,7 @@ static struct eisa_device_id sim710_eisa_ids[] = {
 };
 MODULE_DEVICE_TABLE(eisa, sim710_eisa_ids);
 
-static __init int
-sim710_eisa_probe(struct device *dev)
+static int sim710_eisa_probe(struct device *dev)
 {
        struct eisa_device *edev = to_eisa_device(dev);
        unsigned long io_addr = edev->base_addr;
index 9bf7f57..10021f2 100644 (file)
@@ -3,7 +3,7 @@
  *
  * This code is based on drivers/scsi/ufs/ufshcd.c
  * Copyright (C) 2011-2013 Samsung India Software Operations
- * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
  *
  * Authors:
  *     Santosh Yaraganavi <santosh.sy@samsung.com>
@@ -8431,7 +8431,8 @@ static void ufshcd_hba_exit(struct ufs_hba *hba)
                if (ufshcd_is_clkscaling_supported(hba)) {
                        if (hba->devfreq)
                                ufshcd_suspend_clkscaling(hba);
-                       destroy_workqueue(hba->clk_scaling.workq);
+                       if (hba->clk_scaling.workq)
+                               destroy_workqueue(hba->clk_scaling.workq);
                }
                ufshcd_disable_clocks(hba, false);
                ufshcd_setup_hba_vreg(hba, false);
index ba2ff83..8605b75 100644 (file)
@@ -47,6 +47,7 @@ ifdef CONFIG_MSM_SUBSYSTEM_RESTART
        obj-y += subsystem_notif.o
        obj-y += subsystem_restart.o
        obj-y += ramdump.o
+       obj-$(CONFIG_MSM_GVM_QUIN) += subsystem_notif_virt.o
 endif
 
 obj-$(CONFIG_QPNP_HAPTIC) += qpnp-haptic.o
index 3f2b05a..dfa00f5 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -18,6 +18,7 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/of.h>
 
 #include <asm/cacheflush.h>
 #include <asm/compiler.h>
@@ -194,6 +195,33 @@ static int scm_remap_error(int err)
        return -EINVAL;
 }
 
+static int get_hab_vmid(u32 *mm_ip_id)
+{
+       int result, i;
+       struct device_node *hab_node = NULL;
+       int tmp = -1;
+
+       /* parse device tree*/
+       pr_info("parsing hab node in device tree...\n");
+       hab_node = of_find_compatible_node(NULL, NULL, "qcom,hab");
+       if (hab_node) {
+               /* read local vmid of this VM, like 0 for host, 1 for AGL GVM */
+               result = of_property_read_u32(hab_node, "vmid", &tmp);
+               if (!result) {
+                       pr_info("local vmid = %d\n", tmp);
+                       *mm_ip_id = MM_QCPE_START + tmp;
+                       return 0;
+               }
+               pr_err("failed to read local vmid, result = %d\n", result);
+       } else {
+               pr_err("no hab device tree node\n");
+       }
+
+       pr_info("assuming default vmid = 2\n");
+       *mm_ip_id = MM_QCPE_VM2;
+       return 0;
+}
+
 static int scm_call_qcpe(u32 fn_id, struct scm_desc *desc)
 {
        static bool opened;
@@ -217,7 +245,15 @@ static int scm_call_qcpe(u32 fn_id, struct scm_desc *desc)
                desc->args[5], desc->args[6]);
 
        if (!opened) {
-               ret = habmm_socket_open(&handle, MM_QCPE_VM1, 0, 0);
+               u32 mm_ip_id;
+
+               ret = get_hab_vmid(&mm_ip_id);
+               if (ret) {
+                       pr_err("scm_call_qcpe: get_hab_vmid failed with ret = %d",
+                               ret);
+                       return ret;
+               }
+               ret = habmm_socket_open(&handle, mm_ip_id, 0, 0);
                if (ret) {
                        pr_err("scm_call_qcpe: habmm_socket_open failed with ret = %d",
                                ret);
diff --git a/drivers/soc/qcom/subsystem_notif_virt.c b/drivers/soc/qcom/subsystem_notif_virt.c
new file mode 100644 (file)
index 0000000..739600f
--- /dev/null
@@ -0,0 +1,163 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/notifier.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/of_platform.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <soc/qcom/subsystem_notif.h>
+
+static void __iomem *base_reg;
+
+struct state_notifier_block {
+       const char *subsystem;
+       struct notifier_block nb;
+       u32 offset;
+       void *handle;
+       struct list_head notifier_list;
+};
+
+static LIST_HEAD(notifier_block_list);
+
+static int subsys_state_callback(struct notifier_block *this,
+               unsigned long value, void *priv)
+{
+       struct state_notifier_block *notifier =
+               container_of(this, struct state_notifier_block, nb);
+
+       writel_relaxed(value, base_reg + notifier->offset);
+
+       return NOTIFY_OK;
+}
+
+static int subsys_notif_virt_probe(struct platform_device *pdev)
+{
+       struct device_node *node;
+       struct device_node *child = NULL;
+       struct resource *res;
+       struct state_notifier_block *notif_block;
+       int ret = 0;
+
+       if (!pdev) {
+               dev_err(&pdev->dev, "pdev is NULL\n");
+               return -EINVAL;
+       }
+
+       node = pdev->dev.of_node;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vdev_base");
+       base_reg = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR_OR_NULL(base_reg)) {
+               dev_err(&pdev->dev, "Memory mapping failed\n");
+               return -ENOMEM;
+       }
+
+       for_each_child_of_node(node, child) {
+
+               notif_block = devm_kmalloc(&pdev->dev,
+                               sizeof(struct state_notifier_block),
+                               GFP_KERNEL);
+               if (!notif_block)
+                       return -ENOMEM;
+
+               notif_block->subsystem =
+                               of_get_property(child, "subsys-name", NULL);
+               if (IS_ERR_OR_NULL(notif_block->subsystem)) {
+                       dev_err(&pdev->dev, "Could not find subsystem name\n");
+                       ret = -EINVAL;
+                       goto err_nb;
+               }
+
+               notif_block->nb.notifier_call = subsys_state_callback;
+
+               notif_block->handle =
+                       subsys_notif_register_notifier(notif_block->subsystem,
+                               &notif_block->nb);
+               if (IS_ERR_OR_NULL(notif_block->handle)) {
+                       dev_err(&pdev->dev, "Could not register SSR notifier cb\n");
+                       ret = -EINVAL;
+                       goto err_nb;
+               }
+
+               ret = of_property_read_u32(child, "offset",
+                               &notif_block->offset);
+               if (ret) {
+                       dev_err(&pdev->dev, "offset reading for %s failed\n",
+                               notif_block->subsystem);
+                       ret = -EINVAL;
+                       goto err_offset;
+               }
+
+               list_add_tail(&notif_block->notifier_list,
+                       &notifier_block_list);
+
+       }
+       return 0;
+
+err_offset:
+       subsys_notif_unregister_notifier(notif_block->handle,
+               &notif_block->nb);
+err_nb:
+       kfree(notif_block);
+       return ret;
+}
+
+static int subsys_notif_virt_remove(struct platform_device *pdev)
+{
+       struct state_notifier_block *notif_block;
+
+       list_for_each_entry(notif_block, &notifier_block_list,
+                       notifier_list) {
+               subsys_notif_unregister_notifier(notif_block->handle,
+                       &notif_block->nb);
+               list_del(&notif_block->notifier_list);
+       }
+       return 0;
+}
+
+static const struct of_device_id match_table[] = {
+       { .compatible = "qcom,subsys-notif-virt" },
+       {},
+};
+
+static struct platform_driver subsys_notif_virt_driver = {
+       .probe = subsys_notif_virt_probe,
+       .remove = subsys_notif_virt_remove,
+       .driver = {
+               .name = "subsys_notif_virt",
+               .owner = "THIS_MODULE",
+               .of_match_table = match_table,
+       },
+};
+
+static int __init subsys_notif_virt_init(void)
+{
+       return platform_driver_register(&subsys_notif_virt_driver);
+}
+module_init(subsys_notif_virt_init);
+
+static void __exit subsys_notif_virt_exit(void)
+{
+       platform_driver_unregister(&subsys_notif_virt_driver);
+}
+module_exit(subsys_notif_virt_exit);
+
+MODULE_DESCRIPTION("Subsystem Notification Virtual Driver");
+MODULE_LICENSE("GPL v2");
index 39d7c7c..2eea3de 100644 (file)
@@ -458,7 +458,7 @@ err_free_master:
 
 static int sun4i_spi_remove(struct platform_device *pdev)
 {
-       pm_runtime_disable(&pdev->dev);
+       pm_runtime_force_suspend(&pdev->dev);
 
        return 0;
 }
index 59fc761..26994be 100644 (file)
@@ -183,7 +183,7 @@ static int vspmi_pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
 {
        struct vspmi_pmic_arb *pa = spmi_controller_get_drvdata(ctrl);
        unsigned long flags;
-       u8 bc = len;
+       u8 bc = len - 1;
        u32 cmd;
        int rc;
 
@@ -228,7 +228,7 @@ static int vspmi_pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc,
 {
        struct vspmi_pmic_arb *pa = spmi_controller_get_drvdata(ctrl);
        unsigned long flags;
-       u8 bc = len;
+       u8 bc = len - 1;
        u32 cmd;
        int rc;
 
@@ -270,7 +270,8 @@ static int vspmi_pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc,
 
 static u32 vspmi_pmic_arb_fmt_cmd_v1(u8 opc, u8 sid, u16 addr, u8 bc)
 {
-       return (opc << 27) | ((sid & 0xf) << 20) | (addr << 4) | (bc & 0x7);
+       return (opc << 27) | ((sid & 0xf) << 20) | (addr << 4) |
+                  ((bc & 0x7) + 1);
 }
 
 static const struct vspmi_backend_driver_ver_ops pmic_arb_v1 = {
index 5d1e9a0..e2ff6b5 100644 (file)
@@ -613,9 +613,10 @@ out:
        return err;
 }
 
-static int ssb_bus_register(struct ssb_bus *bus,
-                           ssb_invariants_func_t get_invariants,
-                           unsigned long baseaddr)
+static int __maybe_unused
+ssb_bus_register(struct ssb_bus *bus,
+                ssb_invariants_func_t get_invariants,
+                unsigned long baseaddr)
 {
        int err;
 
index 28c9afe..a9c1d93 100644 (file)
@@ -698,30 +698,32 @@ static int ashmem_pin_unpin(struct ashmem_area *asma, unsigned long cmd,
        size_t pgstart, pgend;
        int ret = -EINVAL;
 
+       mutex_lock(&ashmem_mutex);
+
        if (unlikely(!asma->file))
-               return -EINVAL;
+               goto out_unlock;
 
-       if (unlikely(copy_from_user(&pin, p, sizeof(pin))))
-               return -EFAULT;
+       if (unlikely(copy_from_user(&pin, p, sizeof(pin)))) {
+               ret = -EFAULT;
+               goto out_unlock;
+       }
 
        /* per custom, you can pass zero for len to mean "everything onward" */
        if (!pin.len)
                pin.len = PAGE_ALIGN(asma->size) - pin.offset;
 
        if (unlikely((pin.offset | pin.len) & ~PAGE_MASK))
-               return -EINVAL;
+               goto out_unlock;
 
        if (unlikely(((__u32)-1) - pin.offset < pin.len))
-               return -EINVAL;
+               goto out_unlock;
 
        if (unlikely(PAGE_ALIGN(asma->size) < pin.offset + pin.len))
-               return -EINVAL;
+               goto out_unlock;
 
        pgstart = pin.offset / PAGE_SIZE;
        pgend = pgstart + (pin.len / PAGE_SIZE) - 1;
 
-       mutex_lock(&ashmem_mutex);
-
        switch (cmd) {
        case ASHMEM_PIN:
                ret = ashmem_pin(asma, pgstart, pgend);
@@ -734,6 +736,7 @@ static int ashmem_pin_unpin(struct ashmem_area *asma, unsigned long cmd,
                break;
        }
 
+out_unlock:
        mutex_unlock(&ashmem_mutex);
 
        return ret;
index abc6690..6f03200 100644 (file)
 #define AD7192_GPOCON_P1DAT    BIT(1) /* P1 state */
 #define AD7192_GPOCON_P0DAT    BIT(0) /* P0 state */
 
+#define AD7192_EXT_FREQ_MHZ_MIN        2457600
+#define AD7192_EXT_FREQ_MHZ_MAX        5120000
 #define AD7192_INT_FREQ_MHZ    4915200
 
 /* NOTE:
@@ -199,6 +201,12 @@ static int ad7192_calibrate_all(struct ad7192_state *st)
                                ARRAY_SIZE(ad7192_calib_arr));
 }
 
+static inline bool ad7192_valid_external_frequency(u32 freq)
+{
+       return (freq >= AD7192_EXT_FREQ_MHZ_MIN &&
+               freq <= AD7192_EXT_FREQ_MHZ_MAX);
+}
+
 static int ad7192_setup(struct ad7192_state *st,
                        const struct ad7192_platform_data *pdata)
 {
@@ -224,17 +232,20 @@ static int ad7192_setup(struct ad7192_state *st,
                         id);
 
        switch (pdata->clock_source_sel) {
-       case AD7192_CLK_EXT_MCLK1_2:
-       case AD7192_CLK_EXT_MCLK2:
-               st->mclk = AD7192_INT_FREQ_MHZ;
-               break;
        case AD7192_CLK_INT:
        case AD7192_CLK_INT_CO:
-               if (pdata->ext_clk_hz)
-                       st->mclk = pdata->ext_clk_hz;
-               else
-                       st->mclk = AD7192_INT_FREQ_MHZ;
+               st->mclk = AD7192_INT_FREQ_MHZ;
                break;
+       case AD7192_CLK_EXT_MCLK1_2:
+       case AD7192_CLK_EXT_MCLK2:
+               if (ad7192_valid_external_frequency(pdata->ext_clk_hz)) {
+                       st->mclk = pdata->ext_clk_hz;
+                       break;
+               }
+               dev_err(&st->sd.spi->dev, "Invalid frequency setting %u\n",
+                       pdata->ext_clk_hz);
+               ret = -EINVAL;
+               goto out;
        default:
                ret = -EINVAL;
                goto out;
index 824d460..58ccafb 100644 (file)
@@ -1039,7 +1039,6 @@ static int synaptics_rmi4_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
 /**
  * synaptics_rmi4_suspend() - suspend the touch screen controller
  * @dev: pointer to device structure
@@ -1047,7 +1046,7 @@ static int synaptics_rmi4_remove(struct i2c_client *client)
  * This function is used to suspend the
  * touch panel controller and returns integer
  */
-static int synaptics_rmi4_suspend(struct device *dev)
+static int __maybe_unused synaptics_rmi4_suspend(struct device *dev)
 {
        /* Touch sleep mode */
        int retval;
@@ -1081,7 +1080,7 @@ static int synaptics_rmi4_suspend(struct device *dev)
  * This function is used to resume the touch panel
  * controller and returns integer.
  */
-static int synaptics_rmi4_resume(struct device *dev)
+static int __maybe_unused synaptics_rmi4_resume(struct device *dev)
 {
        int retval;
        unsigned char intr_status;
@@ -1112,8 +1111,6 @@ static int synaptics_rmi4_resume(struct device *dev)
        return 0;
 }
 
-#endif
-
 static SIMPLE_DEV_PM_OPS(synaptics_rmi4_dev_pm_ops, synaptics_rmi4_suspend,
                         synaptics_rmi4_resume);
 
index d83deb4..6baba27 100644 (file)
@@ -4,7 +4,7 @@
 
 config UNISYS_VISORINPUT
        tristate "Unisys visorinput driver"
-       depends on UNISYSSPAR && UNISYS_VISORBUS && FB
+       depends on UNISYSSPAR && UNISYS_VISORBUS && FB && INPUT
        ---help---
        If you say Y here, you will enable the Unisys visorinput driver.
 
index be972af..bfc3e96 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <linux/semaphore.h>
 #include "linux_wlan_common.h"
+#include <linux/netdevice.h>
 
 /********************************************
  *
index a7d30e8..c43c942 100644 (file)
@@ -900,7 +900,7 @@ static int tcmu_configure_device(struct se_device *dev)
        info->version = __stringify(TCMU_MAILBOX_VERSION);
 
        info->mem[0].name = "tcm-user command & data buffer";
-       info->mem[0].addr = (phys_addr_t) udev->mb_addr;
+       info->mem[0].addr = (phys_addr_t)(uintptr_t)udev->mb_addr;
        info->mem[0].size = TCMU_RING_SIZE;
        info->mem[0].memtype = UIO_MEM_VIRTUAL;
 
index 92fe578..220cf42 100644 (file)
@@ -3,3 +3,4 @@ optee-objs += core.o
 optee-objs += call.o
 optee-objs += rpc.o
 optee-objs += supp.o
+optee-objs += shm_pool.o
index f7b7b40..a5afbe6 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/errno.h>
+#include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/tee_drv.h>
 #include <linux/types.h>
@@ -135,6 +136,7 @@ u32 optee_do_call_with_arg(struct tee_context *ctx, phys_addr_t parg)
        struct optee *optee = tee_get_drvdata(ctx->teedev);
        struct optee_call_waiter w;
        struct optee_rpc_param param = { };
+       struct optee_call_ctx call_ctx = { };
        u32 ret;
 
        param.a0 = OPTEE_SMC_CALL_WITH_ARG;
@@ -159,13 +161,14 @@ u32 optee_do_call_with_arg(struct tee_context *ctx, phys_addr_t parg)
                        param.a1 = res.a1;
                        param.a2 = res.a2;
                        param.a3 = res.a3;
-                       optee_handle_rpc(ctx, &param);
+                       optee_handle_rpc(ctx, &param, &call_ctx);
                } else {
                        ret = res.a0;
                        break;
                }
        }
 
+       optee_rpc_finalize_call(&call_ctx);
        /*
         * We're done with our thread in secure world, if there's any
         * thread waiters wake up one.
@@ -442,3 +445,218 @@ void optee_disable_shm_cache(struct optee *optee)
        }
        optee_cq_wait_final(&optee->call_queue, &w);
 }
+
+#define PAGELIST_ENTRIES_PER_PAGE                              \
+       ((OPTEE_MSG_NONCONTIG_PAGE_SIZE / sizeof(u64)) - 1)
+
+/**
+ * optee_fill_pages_list() - write list of user pages to given shared
+ * buffer.
+ *
+ * @dst: page-aligned buffer where list of pages will be stored
+ * @pages: array of pages that represents shared buffer
+ * @num_pages: number of entries in @pages
+ * @page_offset: offset of user buffer from page start
+ *
+ * @dst should be big enough to hold list of user page addresses and
+ *     links to the next pages of buffer
+ */
+void optee_fill_pages_list(u64 *dst, struct page **pages, int num_pages,
+                          size_t page_offset)
+{
+       int n = 0;
+       phys_addr_t optee_page;
+       /*
+        * Refer to OPTEE_MSG_ATTR_NONCONTIG description in optee_msg.h
+        * for details.
+        */
+       struct {
+               u64 pages_list[PAGELIST_ENTRIES_PER_PAGE];
+               u64 next_page_data;
+       } *pages_data;
+
+       /*
+        * Currently OP-TEE uses 4k page size and it does not looks
+        * like this will change in the future.  On other hand, there are
+        * no know ARM architectures with page size < 4k.
+        * Thus the next built assert looks redundant. But the following
+        * code heavily relies on this assumption, so it is better be
+        * safe than sorry.
+        */
+       BUILD_BUG_ON(PAGE_SIZE < OPTEE_MSG_NONCONTIG_PAGE_SIZE);
+
+       pages_data = (void *)dst;
+       /*
+        * If linux page is bigger than 4k, and user buffer offset is
+        * larger than 4k/8k/12k/etc this will skip first 4k pages,
+        * because they bear no value data for OP-TEE.
+        */
+       optee_page = page_to_phys(*pages) +
+               round_down(page_offset, OPTEE_MSG_NONCONTIG_PAGE_SIZE);
+
+       while (true) {
+               pages_data->pages_list[n++] = optee_page;
+
+               if (n == PAGELIST_ENTRIES_PER_PAGE) {
+                       pages_data->next_page_data =
+                               virt_to_phys(pages_data + 1);
+                       pages_data++;
+                       n = 0;
+               }
+
+               optee_page += OPTEE_MSG_NONCONTIG_PAGE_SIZE;
+               if (!(optee_page & ~PAGE_MASK)) {
+                       if (!--num_pages)
+                               break;
+                       pages++;
+                       optee_page = page_to_phys(*pages);
+               }
+       }
+}
+
+/*
+ * The final entry in each pagelist page is a pointer to the next
+ * pagelist page.
+ */
+static size_t get_pages_list_size(size_t num_entries)
+{
+       int pages = DIV_ROUND_UP(num_entries, PAGELIST_ENTRIES_PER_PAGE);
+
+       return pages * OPTEE_MSG_NONCONTIG_PAGE_SIZE;
+}
+
+u64 *optee_allocate_pages_list(size_t num_entries)
+{
+       return alloc_pages_exact(get_pages_list_size(num_entries), GFP_KERNEL);
+}
+
+void optee_free_pages_list(void *list, size_t num_entries)
+{
+       free_pages_exact(list, get_pages_list_size(num_entries));
+}
+
+static bool is_normal_memory(pgprot_t p)
+{
+#if defined(CONFIG_ARM)
+       return (pgprot_val(p) & L_PTE_MT_MASK) == L_PTE_MT_WRITEALLOC;
+#elif defined(CONFIG_ARM64)
+       return (pgprot_val(p) & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL);
+#else
+#error "Unuspported architecture"
+#endif
+}
+
+static int __check_mem_type(struct vm_area_struct *vma, unsigned long end)
+{
+       while (vma && is_normal_memory(vma->vm_page_prot)) {
+               if (vma->vm_end >= end)
+                       return 0;
+               vma = vma->vm_next;
+       }
+
+       return -EINVAL;
+}
+
+static int check_mem_type(unsigned long start, size_t num_pages)
+{
+       struct mm_struct *mm = current->mm;
+       int rc;
+
+       down_read(&mm->mmap_sem);
+       rc = __check_mem_type(find_vma(mm, start),
+                             start + num_pages * PAGE_SIZE);
+       up_read(&mm->mmap_sem);
+
+       return rc;
+}
+
+int optee_shm_register(struct tee_context *ctx, struct tee_shm *shm,
+                      struct page **pages, size_t num_pages,
+                      unsigned long start)
+{
+       struct tee_shm *shm_arg = NULL;
+       struct optee_msg_arg *msg_arg;
+       u64 *pages_list;
+       phys_addr_t msg_parg;
+       int rc;
+
+       if (!num_pages)
+               return -EINVAL;
+
+       rc = check_mem_type(start, num_pages);
+       if (rc)
+               return rc;
+
+       pages_list = optee_allocate_pages_list(num_pages);
+       if (!pages_list)
+               return -ENOMEM;
+
+       shm_arg = get_msg_arg(ctx, 1, &msg_arg, &msg_parg);
+       if (IS_ERR(shm_arg)) {
+               rc = PTR_ERR(shm_arg);
+               goto out;
+       }
+
+       optee_fill_pages_list(pages_list, pages, num_pages,
+                             tee_shm_get_page_offset(shm));
+
+       msg_arg->cmd = OPTEE_MSG_CMD_REGISTER_SHM;
+       msg_arg->params->attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT |
+                               OPTEE_MSG_ATTR_NONCONTIG;
+       msg_arg->params->u.tmem.shm_ref = (unsigned long)shm;
+       msg_arg->params->u.tmem.size = tee_shm_get_size(shm);
+       /*
+        * In the least bits of msg_arg->params->u.tmem.buf_ptr we
+        * store buffer offset from 4k page, as described in OP-TEE ABI.
+        */
+       msg_arg->params->u.tmem.buf_ptr = virt_to_phys(pages_list) |
+         (tee_shm_get_page_offset(shm) & (OPTEE_MSG_NONCONTIG_PAGE_SIZE - 1));
+
+       if (optee_do_call_with_arg(ctx, msg_parg) ||
+           msg_arg->ret != TEEC_SUCCESS)
+               rc = -EINVAL;
+
+       tee_shm_free(shm_arg);
+out:
+       optee_free_pages_list(pages_list, num_pages);
+       return rc;
+}
+
+int optee_shm_unregister(struct tee_context *ctx, struct tee_shm *shm)
+{
+       struct tee_shm *shm_arg;
+       struct optee_msg_arg *msg_arg;
+       phys_addr_t msg_parg;
+       int rc = 0;
+
+       shm_arg = get_msg_arg(ctx, 1, &msg_arg, &msg_parg);
+       if (IS_ERR(shm_arg))
+               return PTR_ERR(shm_arg);
+
+       msg_arg->cmd = OPTEE_MSG_CMD_UNREGISTER_SHM;
+
+       msg_arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_RMEM_INPUT;
+       msg_arg->params[0].u.rmem.shm_ref = (unsigned long)shm;
+
+       if (optee_do_call_with_arg(ctx, msg_parg) ||
+           msg_arg->ret != TEEC_SUCCESS)
+               rc = -EINVAL;
+       tee_shm_free(shm_arg);
+       return rc;
+}
+
+int optee_shm_register_supp(struct tee_context *ctx, struct tee_shm *shm,
+                           struct page **pages, size_t num_pages,
+                           unsigned long start)
+{
+       /*
+        * We don't want to register supplicant memory in OP-TEE.
+        * Instead information about it will be passed in RPC code.
+        */
+       return check_mem_type(start, num_pages);
+}
+
+int optee_shm_unregister_supp(struct tee_context *ctx, struct tee_shm *shm)
+{
+       return 0;
+}
index edb6e4e..e9843c5 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/uaccess.h>
 #include "optee_private.h"
 #include "optee_smc.h"
+#include "shm_pool.h"
 
 #define DRIVER_NAME "optee"
 
@@ -97,6 +98,25 @@ int optee_from_msg_param(struct tee_param *params, size_t num_params,
                                        return rc;
                        }
                        break;
+               case OPTEE_MSG_ATTR_TYPE_RMEM_INPUT:
+               case OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT:
+               case OPTEE_MSG_ATTR_TYPE_RMEM_INOUT:
+                       p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT +
+                                 attr - OPTEE_MSG_ATTR_TYPE_RMEM_INPUT;
+                       p->u.memref.size = mp->u.rmem.size;
+                       shm = (struct tee_shm *)(unsigned long)
+                               mp->u.rmem.shm_ref;
+
+                       if (!shm) {
+                               p->u.memref.shm_offs = 0;
+                               p->u.memref.shm = NULL;
+                               break;
+                       }
+                       p->u.memref.shm_offs = mp->u.rmem.offs;
+                       p->u.memref.shm = shm;
+
+                       break;
+
                default:
                        return -EINVAL;
                }
@@ -104,6 +124,46 @@ int optee_from_msg_param(struct tee_param *params, size_t num_params,
        return 0;
 }
 
+static int to_msg_param_tmp_mem(struct optee_msg_param *mp,
+                               const struct tee_param *p)
+{
+       int rc;
+       phys_addr_t pa;
+
+       mp->attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT + p->attr -
+                  TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
+
+       mp->u.tmem.shm_ref = (unsigned long)p->u.memref.shm;
+       mp->u.tmem.size = p->u.memref.size;
+
+       if (!p->u.memref.shm) {
+               mp->u.tmem.buf_ptr = 0;
+               return 0;
+       }
+
+       rc = tee_shm_get_pa(p->u.memref.shm, p->u.memref.shm_offs, &pa);
+       if (rc)
+               return rc;
+
+       mp->u.tmem.buf_ptr = pa;
+       mp->attr |= OPTEE_MSG_ATTR_CACHE_PREDEFINED <<
+                   OPTEE_MSG_ATTR_CACHE_SHIFT;
+
+       return 0;
+}
+
+static int to_msg_param_reg_mem(struct optee_msg_param *mp,
+                               const struct tee_param *p)
+{
+       mp->attr = OPTEE_MSG_ATTR_TYPE_RMEM_INPUT + p->attr -
+                  TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
+
+       mp->u.rmem.shm_ref = (unsigned long)p->u.memref.shm;
+       mp->u.rmem.size = p->u.memref.size;
+       mp->u.rmem.offs = p->u.memref.shm_offs;
+       return 0;
+}
+
 /**
  * optee_to_msg_param() - convert from struct tee_params to OPTEE_MSG parameters
  * @msg_params:        OPTEE_MSG parameters
@@ -116,7 +176,6 @@ int optee_to_msg_param(struct optee_msg_param *msg_params, size_t num_params,
 {
        int rc;
        size_t n;
-       phys_addr_t pa;
 
        for (n = 0; n < num_params; n++) {
                const struct tee_param *p = params + n;
@@ -139,22 +198,12 @@ int optee_to_msg_param(struct optee_msg_param *msg_params, size_t num_params,
                case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:
                case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
                case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
-                       mp->attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT +
-                                  p->attr -
-                                  TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
-                       mp->u.tmem.shm_ref = (unsigned long)p->u.memref.shm;
-                       mp->u.tmem.size = p->u.memref.size;
-                       if (!p->u.memref.shm) {
-                               mp->u.tmem.buf_ptr = 0;
-                               break;
-                       }
-                       rc = tee_shm_get_pa(p->u.memref.shm,
-                                           p->u.memref.shm_offs, &pa);
+                       if (tee_shm_is_registered(p->u.memref.shm))
+                               rc = to_msg_param_reg_mem(mp, p);
+                       else
+                               rc = to_msg_param_tmp_mem(mp, p);
                        if (rc)
                                return rc;
-                       mp->u.tmem.buf_ptr = pa;
-                       mp->attr |= OPTEE_MSG_ATTR_CACHE_PREDEFINED <<
-                                       OPTEE_MSG_ATTR_CACHE_SHIFT;
                        break;
                default:
                        return -EINVAL;
@@ -171,6 +220,10 @@ static void optee_get_version(struct tee_device *teedev,
                .impl_caps = TEE_OPTEE_CAP_TZ,
                .gen_caps = TEE_GEN_CAP_GP,
        };
+       struct optee *optee = tee_get_drvdata(teedev);
+
+       if (optee->sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
+               v.gen_caps |= TEE_GEN_CAP_REG_MEM;
        *vers = v;
 }
 
@@ -187,12 +240,12 @@ static int optee_open(struct tee_context *ctx)
        if (teedev == optee->supp_teedev) {
                bool busy = true;
 
-               mutex_lock(&optee->supp.ctx_mutex);
+               mutex_lock(&optee->supp.mutex);
                if (!optee->supp.ctx) {
                        busy = false;
                        optee->supp.ctx = ctx;
                }
-               mutex_unlock(&optee->supp.ctx_mutex);
+               mutex_unlock(&optee->supp.mutex);
                if (busy) {
                        kfree(ctxdata);
                        return -EBUSY;
@@ -252,11 +305,8 @@ static void optee_release(struct tee_context *ctx)
 
        ctx->data = NULL;
 
-       if (teedev == optee->supp_teedev) {
-               mutex_lock(&optee->supp.ctx_mutex);
-               optee->supp.ctx = NULL;
-               mutex_unlock(&optee->supp.ctx_mutex);
-       }
+       if (teedev == optee->supp_teedev)
+               optee_supp_release(&optee->supp);
 }
 
 static const struct tee_driver_ops optee_ops = {
@@ -267,6 +317,8 @@ static const struct tee_driver_ops optee_ops = {
        .close_session = optee_close_session,
        .invoke_func = optee_invoke_func,
        .cancel_req = optee_cancel_req,
+       .shm_register = optee_shm_register,
+       .shm_unregister = optee_shm_unregister,
 };
 
 static const struct tee_desc optee_desc = {
@@ -281,6 +333,8 @@ static const struct tee_driver_ops optee_supp_ops = {
        .release = optee_release,
        .supp_recv = optee_supp_recv,
        .supp_send = optee_supp_send,
+       .shm_register = optee_shm_register_supp,
+       .shm_unregister = optee_shm_unregister_supp,
 };
 
 static const struct tee_desc optee_supp_desc = {
@@ -345,21 +399,22 @@ static bool optee_msg_exchange_capabilities(optee_invoke_fn *invoke_fn,
 }
 
 static struct tee_shm_pool *
-optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm)
+optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm,
+                         u32 sec_caps)
 {
        union {
                struct arm_smccc_res smccc;
                struct optee_smc_get_shm_config_result result;
        } res;
-       struct tee_shm_pool *pool;
        unsigned long vaddr;
        phys_addr_t paddr;
        size_t size;
        phys_addr_t begin;
        phys_addr_t end;
        void *va;
-       struct tee_shm_pool_mem_info priv_info;
-       struct tee_shm_pool_mem_info dmabuf_info;
+       struct tee_shm_pool_mgr *priv_mgr;
+       struct tee_shm_pool_mgr *dmabuf_mgr;
+       void *rc;
 
        invoke_fn(OPTEE_SMC_GET_SHM_CONFIG, 0, 0, 0, 0, 0, 0, 0, &res.smccc);
        if (res.result.status != OPTEE_SMC_RETURN_OK) {
@@ -389,22 +444,49 @@ optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm)
        }
        vaddr = (unsigned long)va;
 
-       priv_info.vaddr = vaddr;
-       priv_info.paddr = paddr;
-       priv_info.size = OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE;
-       dmabuf_info.vaddr = vaddr + OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE;
-       dmabuf_info.paddr = paddr + OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE;
-       dmabuf_info.size = size - OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE;
-
-       pool = tee_shm_pool_alloc_res_mem(&priv_info, &dmabuf_info);
-       if (IS_ERR(pool)) {
-               memunmap(va);
-               goto out;
+       /*
+        * If OP-TEE can work with unregistered SHM, we will use own pool
+        * for private shm
+        */
+       if (sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM) {
+               rc = optee_shm_pool_alloc_pages();
+               if (IS_ERR(rc))
+                       goto err_memunmap;
+               priv_mgr = rc;
+       } else {
+               const size_t sz = OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE;
+
+               rc = tee_shm_pool_mgr_alloc_res_mem(vaddr, paddr, sz,
+                                                   3 /* 8 bytes aligned */);
+               if (IS_ERR(rc))
+                       goto err_memunmap;
+               priv_mgr = rc;
+
+               vaddr += sz;
+               paddr += sz;
+               size -= sz;
        }
 
+       rc = tee_shm_pool_mgr_alloc_res_mem(vaddr, paddr, size, PAGE_SHIFT);
+       if (IS_ERR(rc))
+               goto err_free_priv_mgr;
+       dmabuf_mgr = rc;
+
+       rc = tee_shm_pool_alloc(priv_mgr, dmabuf_mgr);
+       if (IS_ERR(rc))
+               goto err_free_dmabuf_mgr;
+
        *memremaped_shm = va;
-out:
-       return pool;
+
+       return rc;
+
+err_free_dmabuf_mgr:
+       tee_shm_pool_mgr_destroy(dmabuf_mgr);
+err_free_priv_mgr:
+       tee_shm_pool_mgr_destroy(priv_mgr);
+err_memunmap:
+       memunmap(va);
+       return rc;
 }
 
 /* Simple wrapper functions to be able to use a function pointer */
@@ -482,7 +564,7 @@ static struct optee *optee_probe(struct device_node *np)
        if (!(sec_caps & OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM))
                return ERR_PTR(-EINVAL);
 
-       pool = optee_config_shm_memremap(invoke_fn, &memremaped_shm);
+       pool = optee_config_shm_memremap(invoke_fn, &memremaped_shm, sec_caps);
        if (IS_ERR(pool))
                return (void *)pool;
 
@@ -493,6 +575,7 @@ static struct optee *optee_probe(struct device_node *np)
        }
 
        optee->invoke_fn = invoke_fn;
+       optee->sec_caps = sec_caps;
 
        teedev = tee_device_alloc(&optee_desc, NULL, pool, optee);
        if (IS_ERR(teedev)) {
index dd7a06e..3050490 100644 (file)
 #define OPTEE_MSG_ATTR_META                    BIT(8)
 
 /*
- * The temporary shared memory object is not physically contigous and this
- * temp memref is followed by another fragment until the last temp memref
- * that doesn't have this bit set.
+ * Pointer to a list of pages used to register user-defined SHM buffer.
+ * Used with OPTEE_MSG_ATTR_TYPE_TMEM_*.
+ * buf_ptr should point to the beginning of the buffer. Buffer will contain
+ * list of page addresses. OP-TEE core can reconstruct contiguous buffer from
+ * that page addresses list. Page addresses are stored as 64 bit values.
+ * Last entry on a page should point to the next page of buffer.
+ * Every entry in buffer should point to a 4k page beginning (12 least
+ * significant bits must be equal to zero).
+ *
+ * 12 least significant bints of optee_msg_param.u.tmem.buf_ptr should hold page
+ * offset of the user buffer.
+ *
+ * So, entries should be placed like members of this structure:
+ *
+ * struct page_data {
+ *   uint64_t pages_array[OPTEE_MSG_NONCONTIG_PAGE_SIZE/sizeof(uint64_t) - 1];
+ *   uint64_t next_page_data;
+ * };
+ *
+ * Structure is designed to exactly fit into the page size
+ * OPTEE_MSG_NONCONTIG_PAGE_SIZE which is a standard 4KB page.
+ *
+ * The size of 4KB is chosen because this is the smallest page size for ARM
+ * architectures. If REE uses larger pages, it should divide them to 4KB ones.
  */
-#define OPTEE_MSG_ATTR_FRAGMENT                        BIT(9)
+#define OPTEE_MSG_ATTR_NONCONTIG               BIT(9)
 
 /*
  * Memory attributes for caching passed with temp memrefs. The actual value
 #define OPTEE_MSG_LOGIN_APPLICATION_USER       0x00000005
 #define OPTEE_MSG_LOGIN_APPLICATION_GROUP      0x00000006
 
+/*
+ * Page size used in non-contiguous buffer entries
+ */
+#define OPTEE_MSG_NONCONTIG_PAGE_SIZE          4096
+
 /**
  * struct optee_msg_param_tmem - temporary memory reference parameter
  * @buf_ptr:   Address of the buffer
@@ -145,8 +171,8 @@ struct optee_msg_param_value {
  *
  * @attr & OPTEE_MSG_ATTR_TYPE_MASK indicates if tmem, rmem or value is used in
  * the union. OPTEE_MSG_ATTR_TYPE_VALUE_* indicates value,
- * OPTEE_MSG_ATTR_TYPE_TMEM_* indicates tmem and
- * OPTEE_MSG_ATTR_TYPE_RMEM_* indicates rmem.
+ * OPTEE_MSG_ATTR_TYPE_TMEM_* indicates @tmem and
+ * OPTEE_MSG_ATTR_TYPE_RMEM_* indicates @rmem,
  * OPTEE_MSG_ATTR_TYPE_NONE indicates that none of the members are used.
  */
 struct optee_msg_param {
index c374cd5..35e7938 100644 (file)
@@ -53,36 +53,24 @@ struct optee_wait_queue {
  * @ctx                        the context of current connected supplicant.
  *                     if !NULL the supplicant device is available for use,
  *                     else busy
- * @ctx_mutex:         held while accessing @ctx
- * @func:              supplicant function id to call
- * @ret:               call return value
- * @num_params:                number of elements in @param
- * @param:             parameters for @func
- * @req_posted:                if true, a request has been posted to the supplicant
- * @supp_next_send:    if true, next step is for supplicant to send response
- * @thrd_mutex:                held by the thread doing a request to supplicant
- * @supp_mutex:                held by supplicant while operating on this struct
- * @data_to_supp:      supplicant is waiting on this for next request
- * @data_from_supp:    requesting thread is waiting on this to get the result
+ * @mutex:             held while accessing content of this struct
+ * @req_id:            current request id if supplicant is doing synchronous
+ *                     communication, else -1
+ * @reqs:              queued request not yet retrieved by supplicant
+ * @idr:               IDR holding all requests currently being processed
+ *                     by supplicant
+ * @reqs_c:            completion used by supplicant when waiting for a
+ *                     request to be queued.
  */
 struct optee_supp {
+       /* Serializes access to this struct */
+       struct mutex mutex;
        struct tee_context *ctx;
-       /* Serializes access of ctx */
-       struct mutex ctx_mutex;
-
-       u32 func;
-       u32 ret;
-       size_t num_params;
-       struct tee_param *param;
-
-       bool req_posted;
-       bool supp_next_send;
-       /* Serializes access to this struct for requesting thread */
-       struct mutex thrd_mutex;
-       /* Serializes access to this struct for supplicant threads */
-       struct mutex supp_mutex;
-       struct completion data_to_supp;
-       struct completion data_from_supp;
+
+       int req_id;
+       struct list_head reqs;
+       struct idr idr;
+       struct completion reqs_c;
 };
 
 /**
@@ -96,6 +84,8 @@ struct optee_supp {
  * @supp:              supplicant synchronization struct for RPC to supplicant
  * @pool:              shared memory pool
  * @memremaped_shm     virtual address of memory in shared memory pool
+ * @sec_caps:          secure world capabilities defined by
+ *                     OPTEE_SMC_SEC_CAP_* in optee_smc.h
  */
 struct optee {
        struct tee_device *supp_teedev;
@@ -106,6 +96,7 @@ struct optee {
        struct optee_supp supp;
        struct tee_shm_pool *pool;
        void *memremaped_shm;
+       u32 sec_caps;
 };
 
 struct optee_session {
@@ -130,7 +121,16 @@ struct optee_rpc_param {
        u32     a7;
 };
 
-void optee_handle_rpc(struct tee_context *ctx, struct optee_rpc_param *param);
+/* Holds context that is preserved during one STD call */
+struct optee_call_ctx {
+       /* information about pages list used in last allocation */
+       void *pages_list;
+       size_t num_entries;
+};
+
+void optee_handle_rpc(struct tee_context *ctx, struct optee_rpc_param *param,
+                     struct optee_call_ctx *call_ctx);
+void optee_rpc_finalize_call(struct optee_call_ctx *call_ctx);
 
 void optee_wait_queue_init(struct optee_wait_queue *wq);
 void optee_wait_queue_exit(struct optee_wait_queue *wq);
@@ -142,6 +142,7 @@ int optee_supp_read(struct tee_context *ctx, void __user *buf, size_t len);
 int optee_supp_write(struct tee_context *ctx, void __user *buf, size_t len);
 void optee_supp_init(struct optee_supp *supp);
 void optee_supp_uninit(struct optee_supp *supp);
+void optee_supp_release(struct optee_supp *supp);
 
 int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params,
                    struct tee_param *param);
@@ -160,11 +161,26 @@ int optee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session);
 void optee_enable_shm_cache(struct optee *optee);
 void optee_disable_shm_cache(struct optee *optee);
 
+int optee_shm_register(struct tee_context *ctx, struct tee_shm *shm,
+                      struct page **pages, size_t num_pages,
+                      unsigned long start);
+int optee_shm_unregister(struct tee_context *ctx, struct tee_shm *shm);
+
+int optee_shm_register_supp(struct tee_context *ctx, struct tee_shm *shm,
+                           struct page **pages, size_t num_pages,
+                           unsigned long start);
+int optee_shm_unregister_supp(struct tee_context *ctx, struct tee_shm *shm);
+
 int optee_from_msg_param(struct tee_param *params, size_t num_params,
                         const struct optee_msg_param *msg_params);
 int optee_to_msg_param(struct optee_msg_param *msg_params, size_t num_params,
                       const struct tee_param *params);
 
+u64 *optee_allocate_pages_list(size_t num_entries);
+void optee_free_pages_list(void *array, size_t num_entries);
+void optee_fill_pages_list(u64 *dst, struct page **pages, int num_pages,
+                          size_t page_offset);
+
 /*
  * Small helpers
  */
index 069c8e1..7cd3272 100644 (file)
@@ -222,6 +222,13 @@ struct optee_smc_get_shm_config_result {
 #define OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM    BIT(0)
 /* Secure world can communicate via previously unregistered shared memory */
 #define OPTEE_SMC_SEC_CAP_UNREGISTERED_SHM     BIT(1)
+
+/*
+ * Secure world supports commands "register/unregister shared memory",
+ * secure world accepts command buffers located in any parts of non-secure RAM
+ */
+#define OPTEE_SMC_SEC_CAP_DYNAMIC_SHM          BIT(2)
+
 #define OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES 9
 #define OPTEE_SMC_EXCHANGE_CAPABILITIES \
        OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES)
index cef417f..41aea12 100644 (file)
@@ -192,15 +192,16 @@ static struct tee_shm *cmd_alloc_suppl(struct tee_context *ctx, size_t sz)
        if (ret)
                return ERR_PTR(-ENOMEM);
 
-       mutex_lock(&optee->supp.ctx_mutex);
+       mutex_lock(&optee->supp.mutex);
        /* Increases count as secure world doesn't have a reference */
        shm = tee_shm_get_from_id(optee->supp.ctx, param.u.value.c);
-       mutex_unlock(&optee->supp.ctx_mutex);
+       mutex_unlock(&optee->supp.mutex);
        return shm;
 }
 
 static void handle_rpc_func_cmd_shm_alloc(struct tee_context *ctx,
-                                         struct optee_msg_arg *arg)
+                                         struct optee_msg_arg *arg,
+                                         struct optee_call_ctx *call_ctx)
 {
        phys_addr_t pa;
        struct tee_shm *shm;
@@ -245,10 +246,49 @@ static void handle_rpc_func_cmd_shm_alloc(struct tee_context *ctx,
                goto bad;
        }
 
-       arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT;
-       arg->params[0].u.tmem.buf_ptr = pa;
-       arg->params[0].u.tmem.size = sz;
-       arg->params[0].u.tmem.shm_ref = (unsigned long)shm;
+       sz = tee_shm_get_size(shm);
+
+       if (tee_shm_is_registered(shm)) {
+               struct page **pages;
+               u64 *pages_list;
+               size_t page_num;
+
+               pages = tee_shm_get_pages(shm, &page_num);
+               if (!pages || !page_num) {
+                       arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
+                       goto bad;
+               }
+
+               pages_list = optee_allocate_pages_list(page_num);
+               if (!pages_list) {
+                       arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
+                       goto bad;
+               }
+
+               call_ctx->pages_list = pages_list;
+               call_ctx->num_entries = page_num;
+
+               arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT |
+                                     OPTEE_MSG_ATTR_NONCONTIG;
+               /*
+                * In the least bits of u.tmem.buf_ptr we store buffer offset
+                * from 4k page, as described in OP-TEE ABI.
+                */
+               arg->params[0].u.tmem.buf_ptr = virt_to_phys(pages_list) |
+                       (tee_shm_get_page_offset(shm) &
+                        (OPTEE_MSG_NONCONTIG_PAGE_SIZE - 1));
+               arg->params[0].u.tmem.size = tee_shm_get_size(shm);
+               arg->params[0].u.tmem.shm_ref = (unsigned long)shm;
+
+               optee_fill_pages_list(pages_list, pages, page_num,
+                                     tee_shm_get_page_offset(shm));
+       } else {
+               arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT;
+               arg->params[0].u.tmem.buf_ptr = pa;
+               arg->params[0].u.tmem.size = sz;
+               arg->params[0].u.tmem.shm_ref = (unsigned long)shm;
+       }
+
        arg->ret = TEEC_SUCCESS;
        return;
 bad:
@@ -307,8 +347,24 @@ static void handle_rpc_func_cmd_shm_free(struct tee_context *ctx,
        arg->ret = TEEC_SUCCESS;
 }
 
+static void free_pages_list(struct optee_call_ctx *call_ctx)
+{
+       if (call_ctx->pages_list) {
+               optee_free_pages_list(call_ctx->pages_list,
+                                     call_ctx->num_entries);
+               call_ctx->pages_list = NULL;
+               call_ctx->num_entries = 0;
+       }
+}
+
+void optee_rpc_finalize_call(struct optee_call_ctx *call_ctx)
+{
+       free_pages_list(call_ctx);
+}
+
 static void handle_rpc_func_cmd(struct tee_context *ctx, struct optee *optee,
-                               struct tee_shm *shm)
+                               struct tee_shm *shm,
+                               struct optee_call_ctx *call_ctx)
 {
        struct optee_msg_arg *arg;
 
@@ -329,7 +385,8 @@ static void handle_rpc_func_cmd(struct tee_context *ctx, struct optee *optee,
                handle_rpc_func_cmd_wait(arg);
                break;
        case OPTEE_MSG_RPC_CMD_SHM_ALLOC:
-               handle_rpc_func_cmd_shm_alloc(ctx, arg);
+               free_pages_list(call_ctx);
+               handle_rpc_func_cmd_shm_alloc(ctx, arg, call_ctx);
                break;
        case OPTEE_MSG_RPC_CMD_SHM_FREE:
                handle_rpc_func_cmd_shm_free(ctx, arg);
@@ -343,10 +400,12 @@ static void handle_rpc_func_cmd(struct tee_context *ctx, struct optee *optee,
  * optee_handle_rpc() - handle RPC from secure world
  * @ctx:       context doing the RPC
  * @param:     value of registers for the RPC
+ * @call_ctx:  call context. Preserved during one OP-TEE invocation
  *
  * Result of RPC is written back into @param.
  */
-void optee_handle_rpc(struct tee_context *ctx, struct optee_rpc_param *param)
+void optee_handle_rpc(struct tee_context *ctx, struct optee_rpc_param *param,
+                     struct optee_call_ctx *call_ctx)
 {
        struct tee_device *teedev = ctx->teedev;
        struct optee *optee = tee_get_drvdata(teedev);
@@ -381,7 +440,7 @@ void optee_handle_rpc(struct tee_context *ctx, struct optee_rpc_param *param)
                break;
        case OPTEE_SMC_RPC_FUNC_CMD:
                shm = reg_pair_to_ptr(param->a1, param->a2);
-               handle_rpc_func_cmd(ctx, optee, shm);
+               handle_rpc_func_cmd(ctx, optee, shm, call_ctx);
                break;
        default:
                pr_warn("Unknown RPC func 0x%x\n",
diff --git a/drivers/tee/optee/shm_pool.c b/drivers/tee/optee/shm_pool.c
new file mode 100644 (file)
index 0000000..4939781
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ * Copyright (c) 2017, EPAM Systems
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/device.h>
+#include <linux/dma-buf.h>
+#include <linux/genalloc.h>
+#include <linux/slab.h>
+#include <linux/tee_drv.h>
+#include "optee_private.h"
+#include "optee_smc.h"
+#include "shm_pool.h"
+
+static int pool_op_alloc(struct tee_shm_pool_mgr *poolm,
+                        struct tee_shm *shm, size_t size)
+{
+       unsigned int order = get_order(size);
+       struct page *page;
+
+       page = alloc_pages(GFP_KERNEL | __GFP_ZERO, order);
+       if (!page)
+               return -ENOMEM;
+
+       shm->kaddr = page_address(page);
+       shm->paddr = page_to_phys(page);
+       shm->size = PAGE_SIZE << order;
+
+       return 0;
+}
+
+static void pool_op_free(struct tee_shm_pool_mgr *poolm,
+                        struct tee_shm *shm)
+{
+       free_pages((unsigned long)shm->kaddr, get_order(shm->size));
+       shm->kaddr = NULL;
+}
+
+static void pool_op_destroy_poolmgr(struct tee_shm_pool_mgr *poolm)
+{
+       kfree(poolm);
+}
+
+static const struct tee_shm_pool_mgr_ops pool_ops = {
+       .alloc = pool_op_alloc,
+       .free = pool_op_free,
+       .destroy_poolmgr = pool_op_destroy_poolmgr,
+};
+
+/**
+ * optee_shm_pool_alloc_pages() - create page-based allocator pool
+ *
+ * This pool is used when OP-TEE supports dymanic SHM. In this case
+ * command buffers and such are allocated from kernel's own memory.
+ */
+struct tee_shm_pool_mgr *optee_shm_pool_alloc_pages(void)
+{
+       struct tee_shm_pool_mgr *mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
+
+       if (!mgr)
+               return ERR_PTR(-ENOMEM);
+
+       mgr->ops = &pool_ops;
+
+       return mgr;
+}
diff --git a/drivers/tee/optee/shm_pool.h b/drivers/tee/optee/shm_pool.h
new file mode 100644 (file)
index 0000000..4e753c3
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ * Copyright (c) 2016, EPAM Systems
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef SHM_POOL_H
+#define SHM_POOL_H
+
+#include <linux/tee_drv.h>
+
+struct tee_shm_pool_mgr *optee_shm_pool_alloc_pages(void);
+
+#endif
index b4ea067..df35fc0 100644 (file)
 #include <linux/uaccess.h>
 #include "optee_private.h"
 
+struct optee_supp_req {
+       struct list_head link;
+
+       bool busy;
+       u32 func;
+       u32 ret;
+       size_t num_params;
+       struct tee_param *param;
+
+       struct completion c;
+};
+
 void optee_supp_init(struct optee_supp *supp)
 {
        memset(supp, 0, sizeof(*supp));
-       mutex_init(&supp->ctx_mutex);
-       mutex_init(&supp->thrd_mutex);
-       mutex_init(&supp->supp_mutex);
-       init_completion(&supp->data_to_supp);
-       init_completion(&supp->data_from_supp);
+       mutex_init(&supp->mutex);
+       init_completion(&supp->reqs_c);
+       idr_init(&supp->idr);
+       INIT_LIST_HEAD(&supp->reqs);
+       supp->req_id = -1;
 }
 
 void optee_supp_uninit(struct optee_supp *supp)
 {
-       mutex_destroy(&supp->ctx_mutex);
-       mutex_destroy(&supp->thrd_mutex);
-       mutex_destroy(&supp->supp_mutex);
+       mutex_destroy(&supp->mutex);
+       idr_destroy(&supp->idr);
+}
+
+void optee_supp_release(struct optee_supp *supp)
+{
+       int id;
+       struct optee_supp_req *req;
+       struct optee_supp_req *req_tmp;
+
+       mutex_lock(&supp->mutex);
+
+       /* Abort all request retrieved by supplicant */
+       idr_for_each_entry(&supp->idr, req, id) {
+               req->busy = false;
+               idr_remove(&supp->idr, id);
+               req->ret = TEEC_ERROR_COMMUNICATION;
+               complete(&req->c);
+       }
+
+       /* Abort all queued requests */
+       list_for_each_entry_safe(req, req_tmp, &supp->reqs, link) {
+               list_del(&req->link);
+               req->ret = TEEC_ERROR_COMMUNICATION;
+               complete(&req->c);
+       }
+
+       supp->ctx = NULL;
+       supp->req_id = -1;
+
+       mutex_unlock(&supp->mutex);
 }
 
 /**
@@ -44,53 +84,42 @@ void optee_supp_uninit(struct optee_supp *supp)
  */
 u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params,
                        struct tee_param *param)
+
 {
-       bool interruptable;
        struct optee *optee = tee_get_drvdata(ctx->teedev);
        struct optee_supp *supp = &optee->supp;
+       struct optee_supp_req *req = kzalloc(sizeof(*req), GFP_KERNEL);
+       bool interruptable;
        u32 ret;
 
-       /*
-        * Other threads blocks here until we've copied our answer from
-        * supplicant.
-        */
-       while (mutex_lock_interruptible(&supp->thrd_mutex)) {
-               /* See comment below on when the RPC can be interrupted. */
-               mutex_lock(&supp->ctx_mutex);
-               interruptable = !supp->ctx;
-               mutex_unlock(&supp->ctx_mutex);
-               if (interruptable)
-                       return TEEC_ERROR_COMMUNICATION;
-       }
+       if (!req)
+               return TEEC_ERROR_OUT_OF_MEMORY;
 
-       /*
-        * We have exclusive access now since the supplicant at this
-        * point is either doing a
-        * wait_for_completion_interruptible(&supp->data_to_supp) or is in
-        * userspace still about to do the ioctl() to enter
-        * optee_supp_recv() below.
-        */
+       init_completion(&req->c);
+       req->func = func;
+       req->num_params = num_params;
+       req->param = param;
 
-       supp->func = func;
-       supp->num_params = num_params;
-       supp->param = param;
-       supp->req_posted = true;
+       /* Insert the request in the request list */
+       mutex_lock(&supp->mutex);
+       list_add_tail(&req->link, &supp->reqs);
+       mutex_unlock(&supp->mutex);
 
-       /* Let supplicant get the data */
-       complete(&supp->data_to_supp);
+       /* Tell an eventual waiter there's a new request */
+       complete(&supp->reqs_c);
 
        /*
         * Wait for supplicant to process and return result, once we've
-        * returned from wait_for_completion(data_from_supp) we have
+        * returned from wait_for_completion(&req->c) successfully we have
         * exclusive access again.
         */
-       while (wait_for_completion_interruptible(&supp->data_from_supp)) {
-               mutex_lock(&supp->ctx_mutex);
+       while (wait_for_completion_interruptible(&req->c)) {
+               mutex_lock(&supp->mutex);
                interruptable = !supp->ctx;
                if (interruptable) {
                        /*
                         * There's no supplicant available and since the
-                        * supp->ctx_mutex currently is held none can
+                        * supp->mutex currently is held none can
                         * become available until the mutex released
                         * again.
                         *
@@ -101,24 +130,91 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params,
                         * will serve all requests in a timely manner and
                         * interrupting then wouldn't make sense.
                         */
-                       supp->ret = TEEC_ERROR_COMMUNICATION;
-                       init_completion(&supp->data_to_supp);
+                       interruptable = !req->busy;
+                       if (!req->busy)
+                               list_del(&req->link);
                }
-               mutex_unlock(&supp->ctx_mutex);
-               if (interruptable)
+               mutex_unlock(&supp->mutex);
+
+               if (interruptable) {
+                       req->ret = TEEC_ERROR_COMMUNICATION;
                        break;
+               }
        }
 
-       ret = supp->ret;
-       supp->param = NULL;
-       supp->req_posted = false;
-
-       /* We're done, let someone else talk to the supplicant now. */
-       mutex_unlock(&supp->thrd_mutex);
+       ret = req->ret;
+       kfree(req);
 
        return ret;
 }
 
+static struct optee_supp_req  *supp_pop_entry(struct optee_supp *supp,
+                                             int num_params, int *id)
+{
+       struct optee_supp_req *req;
+
+       if (supp->req_id != -1) {
+               /*
+                * Supplicant should not mix synchronous and asnynchronous
+                * requests.
+                */
+               return ERR_PTR(-EINVAL);
+       }
+
+       if (list_empty(&supp->reqs))
+               return NULL;
+
+       req = list_first_entry(&supp->reqs, struct optee_supp_req, link);
+
+       if (num_params < req->num_params) {
+               /* Not enough room for parameters */
+               return ERR_PTR(-EINVAL);
+       }
+
+       *id = idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL);
+       if (*id < 0)
+               return ERR_PTR(-ENOMEM);
+
+       list_del(&req->link);
+       req->busy = true;
+
+       return req;
+}
+
+static int supp_check_recv_params(size_t num_params, struct tee_param *params,
+                                 size_t *num_meta)
+{
+       size_t n;
+
+       if (!num_params)
+               return -EINVAL;
+
+       /*
+        * If there's memrefs we need to decrease those as they where
+        * increased earlier and we'll even refuse to accept any below.
+        */
+       for (n = 0; n < num_params; n++)
+               if (tee_param_is_memref(params + n) && params[n].u.memref.shm)
+                       tee_shm_put(params[n].u.memref.shm);
+
+       /*
+        * We only expect parameters as TEE_IOCTL_PARAM_ATTR_TYPE_NONE with
+        * or without the TEE_IOCTL_PARAM_ATTR_META bit set.
+        */
+       for (n = 0; n < num_params; n++)
+               if (params[n].attr &&
+                   params[n].attr != TEE_IOCTL_PARAM_ATTR_META)
+                       return -EINVAL;
+
+       /* At most we'll need one meta parameter so no need to check for more */
+       if (params->attr == TEE_IOCTL_PARAM_ATTR_META)
+               *num_meta = 1;
+       else
+               *num_meta = 0;
+
+       return 0;
+}
+
 /**
  * optee_supp_recv() - receive request for supplicant
  * @ctx:       context receiving the request
@@ -135,65 +231,99 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params,
        struct tee_device *teedev = ctx->teedev;
        struct optee *optee = tee_get_drvdata(teedev);
        struct optee_supp *supp = &optee->supp;
+       struct optee_supp_req *req = NULL;
+       int id;
+       size_t num_meta;
        int rc;
 
-       /*
-        * In case two threads in one supplicant is calling this function
-        * simultaneously we need to protect the data with a mutex which
-        * we'll release before returning.
-        */
-       mutex_lock(&supp->supp_mutex);
+       rc = supp_check_recv_params(*num_params, param, &num_meta);
+       if (rc)
+               return rc;
+
+       while (true) {
+               mutex_lock(&supp->mutex);
+               req = supp_pop_entry(supp, *num_params - num_meta, &id);
+               mutex_unlock(&supp->mutex);
+
+               if (req) {
+                       if (IS_ERR(req))
+                               return PTR_ERR(req);
+                       break;
+               }
 
-       if (supp->supp_next_send) {
                /*
-                * optee_supp_recv() has been called again without
-                * a optee_supp_send() in between. Supplicant has
-                * probably been restarted before it was able to
-                * write back last result. Abort last request and
-                * wait for a new.
+                * If we didn't get a request we'll block in
+                * wait_for_completion() to avoid needless spinning.
+                *
+                * This is where supplicant will be hanging most of
+                * the time, let's make this interruptable so we
+                * can easily restart supplicant if needed.
                 */
-               if (supp->req_posted) {
-                       supp->ret = TEEC_ERROR_COMMUNICATION;
-                       supp->supp_next_send = false;
-                       complete(&supp->data_from_supp);
-               }
+               if (wait_for_completion_interruptible(&supp->reqs_c))
+                       return -ERESTARTSYS;
        }
 
-       /*
-        * This is where supplicant will be hanging most of the
-        * time, let's make this interruptable so we can easily
-        * restart supplicant if needed.
-        */
-       if (wait_for_completion_interruptible(&supp->data_to_supp)) {
-               rc = -ERESTARTSYS;
-               goto out;
+       if (num_meta) {
+               /*
+                * tee-supplicant support meta parameters -> requsts can be
+                * processed asynchronously.
+                */
+               param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT |
+                             TEE_IOCTL_PARAM_ATTR_META;
+               param->u.value.a = id;
+               param->u.value.b = 0;
+               param->u.value.c = 0;
+       } else {
+               mutex_lock(&supp->mutex);
+               supp->req_id = id;
+               mutex_unlock(&supp->mutex);
        }
 
-       /* We have exlusive access to the data */
+       *func = req->func;
+       *num_params = req->num_params + num_meta;
+       memcpy(param + num_meta, req->param,
+              sizeof(struct tee_param) * req->num_params);
 
-       if (*num_params < supp->num_params) {
-               /*
-                * Not enough room for parameters, tell supplicant
-                * it failed and abort last request.
-                */
-               supp->ret = TEEC_ERROR_COMMUNICATION;
-               rc = -EINVAL;
-               complete(&supp->data_from_supp);
-               goto out;
+       return 0;
+}
+
+static struct optee_supp_req *supp_pop_req(struct optee_supp *supp,
+                                          size_t num_params,
+                                          struct tee_param *param,
+                                          size_t *num_meta)
+{
+       struct optee_supp_req *req;
+       int id;
+       size_t nm;
+       const u32 attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT |
+                        TEE_IOCTL_PARAM_ATTR_META;
+
+       if (!num_params)
+               return ERR_PTR(-EINVAL);
+
+       if (supp->req_id == -1) {
+               if (param->attr != attr)
+                       return ERR_PTR(-EINVAL);
+               id = param->u.value.a;
+               nm = 1;
+       } else {
+               id = supp->req_id;
+               nm = 0;
        }
 
-       *func = supp->func;
-       *num_params = supp->num_params;
-       memcpy(param, supp->param,
-              sizeof(struct tee_param) * supp->num_params);
+       req = idr_find(&supp->idr, id);
+       if (!req)
+               return ERR_PTR(-ENOENT);
 
-       /* Allow optee_supp_send() below to do its work */
-       supp->supp_next_send = true;
+       if ((num_params - nm) != req->num_params)
+               return ERR_PTR(-EINVAL);
 
-       rc = 0;
-out:
-       mutex_unlock(&supp->supp_mutex);
-       return rc;
+       req->busy = false;
+       idr_remove(&supp->idr, id);
+       supp->req_id = -1;
+       *num_meta = nm;
+
+       return req;
 }
 
 /**
@@ -211,63 +341,42 @@ int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params,
        struct tee_device *teedev = ctx->teedev;
        struct optee *optee = tee_get_drvdata(teedev);
        struct optee_supp *supp = &optee->supp;
+       struct optee_supp_req *req;
        size_t n;
-       int rc = 0;
+       size_t num_meta;
 
-       /*
-        * We still have exclusive access to the data since that's how we
-        * left it when returning from optee_supp_read().
-        */
-
-       /* See comment on mutex in optee_supp_read() above */
-       mutex_lock(&supp->supp_mutex);
-
-       if (!supp->supp_next_send) {
-               /*
-                * Something strange is going on, supplicant shouldn't
-                * enter optee_supp_send() in this state
-                */
-               rc = -ENOENT;
-               goto out;
-       }
+       mutex_lock(&supp->mutex);
+       req = supp_pop_req(supp, num_params, param, &num_meta);
+       mutex_unlock(&supp->mutex);
 
-       if (num_params != supp->num_params) {
-               /*
-                * Something is wrong, let supplicant restart. Next call to
-                * optee_supp_recv() will give an error to the requesting
-                * thread and release it.
-                */
-               rc = -EINVAL;
-               goto out;
+       if (IS_ERR(req)) {
+               /* Something is wrong, let supplicant restart. */
+               return PTR_ERR(req);
        }
 
        /* Update out and in/out parameters */
-       for (n = 0; n < num_params; n++) {
-               struct tee_param *p = supp->param + n;
+       for (n = 0; n < req->num_params; n++) {
+               struct tee_param *p = req->param + n;
 
-               switch (p->attr) {
+               switch (p->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
                case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
                case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
-                       p->u.value.a = param[n].u.value.a;
-                       p->u.value.b = param[n].u.value.b;
-                       p->u.value.c = param[n].u.value.c;
+                       p->u.value.a = param[n + num_meta].u.value.a;
+                       p->u.value.b = param[n + num_meta].u.value.b;
+                       p->u.value.c = param[n + num_meta].u.value.c;
                        break;
                case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
                case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
-                       p->u.memref.size = param[n].u.memref.size;
+                       p->u.memref.size = param[n + num_meta].u.memref.size;
                        break;
                default:
                        break;
                }
        }
-       supp->ret = ret;
-
-       /* Allow optee_supp_recv() above to do its work */
-       supp->supp_next_send = false;
+       req->ret = ret;
 
        /* Let the requesting thread continue */
-       complete(&supp->data_from_supp);
-out:
-       mutex_unlock(&supp->supp_mutex);
-       return rc;
+       complete(&req->c);
+
+       return 0;
 }
index 58a5009..6c4b200 100644 (file)
@@ -54,6 +54,7 @@ static int tee_open(struct inode *inode, struct file *filp)
                goto err;
        }
 
+       kref_init(&ctx->refcount);
        ctx->teedev = teedev;
        INIT_LIST_HEAD(&ctx->list_shm);
        filp->private_data = ctx;
@@ -68,19 +69,40 @@ err:
        return rc;
 }
 
-static int tee_release(struct inode *inode, struct file *filp)
+void teedev_ctx_get(struct tee_context *ctx)
 {
-       struct tee_context *ctx = filp->private_data;
-       struct tee_device *teedev = ctx->teedev;
-       struct tee_shm *shm;
+       if (ctx->releasing)
+               return;
 
+       kref_get(&ctx->refcount);
+}
+
+static void teedev_ctx_release(struct kref *ref)
+{
+       struct tee_context *ctx = container_of(ref, struct tee_context,
+                                              refcount);
+       ctx->releasing = true;
        ctx->teedev->desc->ops->release(ctx);
-       mutex_lock(&ctx->teedev->mutex);
-       list_for_each_entry(shm, &ctx->list_shm, link)
-               shm->ctx = NULL;
-       mutex_unlock(&ctx->teedev->mutex);
        kfree(ctx);
-       tee_device_put(teedev);
+}
+
+void teedev_ctx_put(struct tee_context *ctx)
+{
+       if (ctx->releasing)
+               return;
+
+       kref_put(&ctx->refcount, teedev_ctx_release);
+}
+
+static void teedev_close_context(struct tee_context *ctx)
+{
+       tee_device_put(ctx->teedev);
+       teedev_ctx_put(ctx);
+}
+
+static int tee_release(struct inode *inode, struct file *filp)
+{
+       teedev_close_context(filp->private_data);
        return 0;
 }
 
@@ -114,8 +136,6 @@ static int tee_ioctl_shm_alloc(struct tee_context *ctx,
        if (data.flags)
                return -EINVAL;
 
-       data.id = -1;
-
        shm = tee_shm_alloc(ctx, data.size, TEE_SHM_MAPPED | TEE_SHM_DMA_BUF);
        if (IS_ERR(shm))
                return PTR_ERR(shm);
@@ -138,6 +158,43 @@ static int tee_ioctl_shm_alloc(struct tee_context *ctx,
        return ret;
 }
 
+static int
+tee_ioctl_shm_register(struct tee_context *ctx,
+                      struct tee_ioctl_shm_register_data __user *udata)
+{
+       long ret;
+       struct tee_ioctl_shm_register_data data;
+       struct tee_shm *shm;
+
+       if (copy_from_user(&data, udata, sizeof(data)))
+               return -EFAULT;
+
+       /* Currently no input flags are supported */
+       if (data.flags)
+               return -EINVAL;
+
+       shm = tee_shm_register(ctx, data.addr, data.length,
+                              TEE_SHM_DMA_BUF | TEE_SHM_USER_MAPPED);
+       if (IS_ERR(shm))
+               return PTR_ERR(shm);
+
+       data.id = shm->id;
+       data.flags = shm->flags;
+       data.length = shm->size;
+
+       if (copy_to_user(udata, &data, sizeof(data)))
+               ret = -EFAULT;
+       else
+               ret = tee_shm_get_fd(shm);
+       /*
+        * When user space closes the file descriptor the shared memory
+        * should be freed or if tee_shm_get_fd() failed then it will
+        * be freed immediately.
+        */
+       tee_shm_put(shm);
+       return ret;
+}
+
 static int params_from_user(struct tee_context *ctx, struct tee_param *params,
                            size_t num_params,
                            struct tee_ioctl_param __user *uparams)
@@ -152,11 +209,11 @@ static int params_from_user(struct tee_context *ctx, struct tee_param *params,
                        return -EFAULT;
 
                /* All unused attribute bits has to be zero */
-               if (ip.attr & ~TEE_IOCTL_PARAM_ATTR_TYPE_MASK)
+               if (ip.attr & ~TEE_IOCTL_PARAM_ATTR_MASK)
                        return -EINVAL;
 
                params[n].attr = ip.attr;
-               switch (ip.attr) {
+               switch (ip.attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
                case TEE_IOCTL_PARAM_ATTR_TYPE_NONE:
                case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
                        break;
@@ -221,18 +278,6 @@ static int params_to_user(struct tee_ioctl_param __user *uparams,
        return 0;
 }
 
-static bool param_is_memref(struct tee_param *param)
-{
-       switch (param->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
-       case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:
-       case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
-       case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
-               return true;
-       default:
-               return false;
-       }
-}
-
 static int tee_ioctl_open_session(struct tee_context *ctx,
                                  struct tee_ioctl_buf_data __user *ubuf)
 {
@@ -296,7 +341,7 @@ out:
        if (params) {
                /* Decrease ref count for all valid shared memory pointers */
                for (n = 0; n < arg.num_params; n++)
-                       if (param_is_memref(params + n) &&
+                       if (tee_param_is_memref(params + n) &&
                            params[n].u.memref.shm)
                                tee_shm_put(params[n].u.memref.shm);
                kfree(params);
@@ -358,7 +403,7 @@ out:
        if (params) {
                /* Decrease ref count for all valid shared memory pointers */
                for (n = 0; n < arg.num_params; n++)
-                       if (param_is_memref(params + n) &&
+                       if (tee_param_is_memref(params + n) &&
                            params[n].u.memref.shm)
                                tee_shm_put(params[n].u.memref.shm);
                kfree(params);
@@ -406,8 +451,8 @@ static int params_to_supp(struct tee_context *ctx,
                struct tee_ioctl_param ip;
                struct tee_param *p = params + n;
 
-               ip.attr = p->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK;
-               switch (p->attr) {
+               ip.attr = p->attr;
+               switch (p->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
                case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT:
                case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
                        ip.a = p->u.value.a;
@@ -471,6 +516,10 @@ static int tee_ioctl_supp_recv(struct tee_context *ctx,
        if (!params)
                return -ENOMEM;
 
+       rc = params_from_user(ctx, params, num_params, uarg->params);
+       if (rc)
+               goto out;
+
        rc = ctx->teedev->desc->ops->supp_recv(ctx, &func, &num_params, params);
        if (rc)
                goto out;
@@ -500,11 +549,11 @@ static int params_from_supp(struct tee_param *params, size_t num_params,
                        return -EFAULT;
 
                /* All unused attribute bits has to be zero */
-               if (ip.attr & ~TEE_IOCTL_PARAM_ATTR_TYPE_MASK)
+               if (ip.attr & ~TEE_IOCTL_PARAM_ATTR_MASK)
                        return -EINVAL;
 
                p->attr = ip.attr;
-               switch (ip.attr) {
+               switch (ip.attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
                case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
                case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
                        /* Only out and in/out values can be updated */
@@ -586,6 +635,8 @@ static long tee_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                return tee_ioctl_version(ctx, uarg);
        case TEE_IOC_SHM_ALLOC:
                return tee_ioctl_shm_alloc(ctx, uarg);
+       case TEE_IOC_SHM_REGISTER:
+               return tee_ioctl_shm_register(ctx, uarg);
        case TEE_IOC_OPEN_SESSION:
                return tee_ioctl_open_session(ctx, uarg);
        case TEE_IOC_INVOKE:
index 21cb6be..85d99d6 100644 (file)
 #include <linux/mutex.h>
 #include <linux/types.h>
 
-struct tee_device;
-
-/**
- * struct tee_shm - shared memory object
- * @teedev:    device used to allocate the object
- * @ctx:       context using the object, if NULL the context is gone
- * @link       link element
- * @paddr:     physical address of the shared memory
- * @kaddr:     virtual address of the shared memory
- * @size:      size of shared memory
- * @dmabuf:    dmabuf used to for exporting to user space
- * @flags:     defined by TEE_SHM_* in tee_drv.h
- * @id:                unique id of a shared memory object on this device
- */
-struct tee_shm {
-       struct tee_device *teedev;
-       struct tee_context *ctx;
-       struct list_head link;
-       phys_addr_t paddr;
-       void *kaddr;
-       size_t size;
-       struct dma_buf *dmabuf;
-       u32 flags;
-       int id;
-};
-
-struct tee_shm_pool_mgr;
-
-/**
- * struct tee_shm_pool_mgr_ops - shared memory pool manager operations
- * @alloc:     called when allocating shared memory
- * @free:      called when freeing shared memory
- */
-struct tee_shm_pool_mgr_ops {
-       int (*alloc)(struct tee_shm_pool_mgr *poolmgr, struct tee_shm *shm,
-                    size_t size);
-       void (*free)(struct tee_shm_pool_mgr *poolmgr, struct tee_shm *shm);
-};
-
-/**
- * struct tee_shm_pool_mgr - shared memory manager
- * @ops:               operations
- * @private_data:      private data for the shared memory manager
- */
-struct tee_shm_pool_mgr {
-       const struct tee_shm_pool_mgr_ops *ops;
-       void *private_data;
-};
-
 /**
  * struct tee_shm_pool - shared memory pool
  * @private_mgr:       pool manager for shared memory only between kernel
  *                     and secure world
  * @dma_buf_mgr:       pool manager for shared memory exported to user space
- * @destroy:           called when destroying the pool
- * @private_data:      private data for the pool
  */
 struct tee_shm_pool {
-       struct tee_shm_pool_mgr private_mgr;
-       struct tee_shm_pool_mgr dma_buf_mgr;
-       void (*destroy)(struct tee_shm_pool *pool);
-       void *private_data;
+       struct tee_shm_pool_mgr *private_mgr;
+       struct tee_shm_pool_mgr *dma_buf_mgr;
 };
 
 #define TEE_DEVICE_FLAG_REGISTERED     0x1
@@ -126,4 +73,7 @@ int tee_shm_get_fd(struct tee_shm *shm);
 bool tee_device_get(struct tee_device *teedev);
 void tee_device_put(struct tee_device *teedev);
 
+void teedev_ctx_get(struct tee_context *ctx);
+void teedev_ctx_put(struct tee_context *ctx);
+
 #endif /*TEE_PRIVATE_H*/
index 37207ae..ed2d71c 100644 (file)
@@ -23,7 +23,6 @@
 static void tee_shm_release(struct tee_shm *shm)
 {
        struct tee_device *teedev = shm->teedev;
-       struct tee_shm_pool_mgr *poolm;
 
        mutex_lock(&teedev->mutex);
        idr_remove(&teedev->idr, shm->id);
@@ -31,12 +30,32 @@ static void tee_shm_release(struct tee_shm *shm)
                list_del(&shm->link);
        mutex_unlock(&teedev->mutex);
 
-       if (shm->flags & TEE_SHM_DMA_BUF)
-               poolm = &teedev->pool->dma_buf_mgr;
-       else
-               poolm = &teedev->pool->private_mgr;
+       if (shm->flags & TEE_SHM_POOL) {
+               struct tee_shm_pool_mgr *poolm;
+
+               if (shm->flags & TEE_SHM_DMA_BUF)
+                       poolm = teedev->pool->dma_buf_mgr;
+               else
+                       poolm = teedev->pool->private_mgr;
+
+               poolm->ops->free(poolm, shm);
+       } else if (shm->flags & TEE_SHM_REGISTER) {
+               size_t n;
+               int rc = teedev->desc->ops->shm_unregister(shm->ctx, shm);
+
+               if (rc)
+                       dev_err(teedev->dev.parent,
+                               "unregister shm %p failed: %d", shm, rc);
+
+               for (n = 0; n < shm->num_pages; n++)
+                       put_page(shm->pages[n]);
+
+               kfree(shm->pages);
+       }
+
+       if (shm->ctx)
+               teedev_ctx_put(shm->ctx);
 
-       poolm->ops->free(poolm, shm);
        kfree(shm);
 
        tee_device_put(teedev);
@@ -76,6 +95,10 @@ static int tee_shm_op_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
        struct tee_shm *shm = dmabuf->priv;
        size_t size = vma->vm_end - vma->vm_start;
 
+       /* Refuse sharing shared memory provided by application */
+       if (shm->flags & TEE_SHM_REGISTER)
+               return -EINVAL;
+
        return remap_pfn_range(vma, vma->vm_start, shm->paddr >> PAGE_SHIFT,
                               size, vma->vm_page_prot);
 }
@@ -89,26 +112,20 @@ static const struct dma_buf_ops tee_shm_dma_buf_ops = {
        .mmap = tee_shm_op_mmap,
 };
 
-/**
- * tee_shm_alloc() - Allocate shared memory
- * @ctx:       Context that allocates the shared memory
- * @size:      Requested size of shared memory
- * @flags:     Flags setting properties for the requested shared memory.
- *
- * Memory allocated as global shared memory is automatically freed when the
- * TEE file pointer is closed. The @flags field uses the bits defined by
- * TEE_SHM_* in <linux/tee_drv.h>. TEE_SHM_MAPPED must currently always be
- * set. If TEE_SHM_DMA_BUF global shared memory will be allocated and
- * associated with a dma-buf handle, else driver private memory.
- */
-struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags)
+static struct tee_shm *__tee_shm_alloc(struct tee_context *ctx,
+                                      struct tee_device *teedev,
+                                      size_t size, u32 flags)
 {
-       struct tee_device *teedev = ctx->teedev;
        struct tee_shm_pool_mgr *poolm = NULL;
        struct tee_shm *shm;
        void *ret;
        int rc;
 
+       if (ctx && ctx->teedev != teedev) {
+               dev_err(teedev->dev.parent, "ctx and teedev mismatch\n");
+               return ERR_PTR(-EINVAL);
+       }
+
        if (!(flags & TEE_SHM_MAPPED)) {
                dev_err(teedev->dev.parent,
                        "only mapped allocations supported\n");
@@ -135,13 +152,13 @@ struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags)
                goto err_dev_put;
        }
 
-       shm->flags = flags;
+       shm->flags = flags | TEE_SHM_POOL;
        shm->teedev = teedev;
        shm->ctx = ctx;
        if (flags & TEE_SHM_DMA_BUF)
-               poolm = &teedev->pool->dma_buf_mgr;
+               poolm = teedev->pool->dma_buf_mgr;
        else
-               poolm = &teedev->pool->private_mgr;
+               poolm = teedev->pool->private_mgr;
 
        rc = poolm->ops->alloc(poolm, shm, size);
        if (rc) {
@@ -171,9 +188,13 @@ struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags)
                        goto err_rem;
                }
        }
-       mutex_lock(&teedev->mutex);
-       list_add_tail(&shm->link, &ctx->list_shm);
-       mutex_unlock(&teedev->mutex);
+
+       if (ctx) {
+               teedev_ctx_get(ctx);
+               mutex_lock(&teedev->mutex);
+               list_add_tail(&shm->link, &ctx->list_shm);
+               mutex_unlock(&teedev->mutex);
+       }
 
        return shm;
 err_rem:
@@ -188,8 +209,145 @@ err_dev_put:
        tee_device_put(teedev);
        return ret;
 }
+
+/**
+ * tee_shm_alloc() - Allocate shared memory
+ * @ctx:       Context that allocates the shared memory
+ * @size:      Requested size of shared memory
+ * @flags:     Flags setting properties for the requested shared memory.
+ *
+ * Memory allocated as global shared memory is automatically freed when the
+ * TEE file pointer is closed. The @flags field uses the bits defined by
+ * TEE_SHM_* in <linux/tee_drv.h>. TEE_SHM_MAPPED must currently always be
+ * set. If TEE_SHM_DMA_BUF global shared memory will be allocated and
+ * associated with a dma-buf handle, else driver private memory.
+ */
+struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags)
+{
+       return __tee_shm_alloc(ctx, ctx->teedev, size, flags);
+}
 EXPORT_SYMBOL_GPL(tee_shm_alloc);
 
+struct tee_shm *tee_shm_priv_alloc(struct tee_device *teedev, size_t size)
+{
+       return __tee_shm_alloc(NULL, teedev, size, TEE_SHM_MAPPED);
+}
+EXPORT_SYMBOL_GPL(tee_shm_priv_alloc);
+
+struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr,
+                                size_t length, u32 flags)
+{
+       struct tee_device *teedev = ctx->teedev;
+       const u32 req_flags = TEE_SHM_DMA_BUF | TEE_SHM_USER_MAPPED;
+       struct tee_shm *shm;
+       void *ret;
+       int rc;
+       int num_pages;
+       unsigned long start;
+
+       if (flags != req_flags)
+               return ERR_PTR(-ENOTSUPP);
+
+       if (!tee_device_get(teedev))
+               return ERR_PTR(-EINVAL);
+
+       if (!teedev->desc->ops->shm_register ||
+           !teedev->desc->ops->shm_unregister) {
+               tee_device_put(teedev);
+               return ERR_PTR(-ENOTSUPP);
+       }
+
+       teedev_ctx_get(ctx);
+
+       shm = kzalloc(sizeof(*shm), GFP_KERNEL);
+       if (!shm) {
+               ret = ERR_PTR(-ENOMEM);
+               goto err;
+       }
+
+       shm->flags = flags | TEE_SHM_REGISTER;
+       shm->teedev = teedev;
+       shm->ctx = ctx;
+       shm->id = -1;
+       start = rounddown(addr, PAGE_SIZE);
+       shm->offset = addr - start;
+       shm->size = length;
+       num_pages = (roundup(addr + length, PAGE_SIZE) - start) / PAGE_SIZE;
+       shm->pages = kcalloc(num_pages, sizeof(*shm->pages), GFP_KERNEL);
+       if (!shm->pages) {
+               ret = ERR_PTR(-ENOMEM);
+               goto err;
+       }
+
+       rc = get_user_pages_fast(start, num_pages, 1, shm->pages);
+       if (rc > 0)
+               shm->num_pages = rc;
+       if (rc != num_pages) {
+               if (rc >= 0)
+                       rc = -ENOMEM;
+               ret = ERR_PTR(rc);
+               goto err;
+       }
+
+       mutex_lock(&teedev->mutex);
+       shm->id = idr_alloc(&teedev->idr, shm, 1, 0, GFP_KERNEL);
+       mutex_unlock(&teedev->mutex);
+
+       if (shm->id < 0) {
+               ret = ERR_PTR(shm->id);
+               goto err;
+       }
+
+       rc = teedev->desc->ops->shm_register(ctx, shm, shm->pages,
+                                            shm->num_pages, start);
+       if (rc) {
+               ret = ERR_PTR(rc);
+               goto err;
+       }
+
+       if (flags & TEE_SHM_DMA_BUF) {
+               DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
+
+               exp_info.ops = &tee_shm_dma_buf_ops;
+               exp_info.size = shm->size;
+               exp_info.flags = O_RDWR;
+               exp_info.priv = shm;
+
+               shm->dmabuf = dma_buf_export(&exp_info);
+               if (IS_ERR(shm->dmabuf)) {
+                       ret = ERR_CAST(shm->dmabuf);
+                       teedev->desc->ops->shm_unregister(ctx, shm);
+                       goto err;
+               }
+       }
+
+       mutex_lock(&teedev->mutex);
+       list_add_tail(&shm->link, &ctx->list_shm);
+       mutex_unlock(&teedev->mutex);
+
+       return shm;
+err:
+       if (shm) {
+               size_t n;
+
+               if (shm->id >= 0) {
+                       mutex_lock(&teedev->mutex);
+                       idr_remove(&teedev->idr, shm->id);
+                       mutex_unlock(&teedev->mutex);
+               }
+               if (shm->pages) {
+                       for (n = 0; n < shm->num_pages; n++)
+                               put_page(shm->pages[n]);
+                       kfree(shm->pages);
+               }
+       }
+       kfree(shm);
+       teedev_ctx_put(ctx);
+       tee_device_put(teedev);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(tee_shm_register);
+
 /**
  * tee_shm_get_fd() - Increase reference count and return file descriptor
  * @shm:       Shared memory handle
@@ -197,10 +355,9 @@ EXPORT_SYMBOL_GPL(tee_shm_alloc);
  */
 int tee_shm_get_fd(struct tee_shm *shm)
 {
-       u32 req_flags = TEE_SHM_MAPPED | TEE_SHM_DMA_BUF;
        int fd;
 
-       if ((shm->flags & req_flags) != req_flags)
+       if (!(shm->flags & TEE_SHM_DMA_BUF))
                return -EINVAL;
 
        fd = dma_buf_fd(shm->dmabuf, O_CLOEXEC);
@@ -238,6 +395,8 @@ EXPORT_SYMBOL_GPL(tee_shm_free);
  */
 int tee_shm_va2pa(struct tee_shm *shm, void *va, phys_addr_t *pa)
 {
+       if (!(shm->flags & TEE_SHM_MAPPED))
+               return -EINVAL;
        /* Check that we're in the range of the shm */
        if ((char *)va < (char *)shm->kaddr)
                return -EINVAL;
@@ -258,6 +417,8 @@ EXPORT_SYMBOL_GPL(tee_shm_va2pa);
  */
 int tee_shm_pa2va(struct tee_shm *shm, phys_addr_t pa, void **va)
 {
+       if (!(shm->flags & TEE_SHM_MAPPED))
+               return -EINVAL;
        /* Check that we're in the range of the shm */
        if (pa < shm->paddr)
                return -EINVAL;
@@ -284,6 +445,8 @@ EXPORT_SYMBOL_GPL(tee_shm_pa2va);
  */
 void *tee_shm_get_va(struct tee_shm *shm, size_t offs)
 {
+       if (!(shm->flags & TEE_SHM_MAPPED))
+               return ERR_PTR(-EINVAL);
        if (offs >= shm->size)
                return ERR_PTR(-EINVAL);
        return (char *)shm->kaddr + offs;
@@ -336,17 +499,6 @@ struct tee_shm *tee_shm_get_from_id(struct tee_context *ctx, int id)
 EXPORT_SYMBOL_GPL(tee_shm_get_from_id);
 
 /**
- * tee_shm_get_id() - Get id of a shared memory object
- * @shm:       Shared memory handle
- * @returns id
- */
-int tee_shm_get_id(struct tee_shm *shm)
-{
-       return shm->id;
-}
-EXPORT_SYMBOL_GPL(tee_shm_get_id);
-
-/**
  * tee_shm_put() - Decrease reference count on a shared memory handle
  * @shm:       Shared memory handle
  */
index fb4f852..e6d4b9e 100644 (file)
@@ -44,49 +44,18 @@ static void pool_op_gen_free(struct tee_shm_pool_mgr *poolm,
        shm->kaddr = NULL;
 }
 
+static void pool_op_gen_destroy_poolmgr(struct tee_shm_pool_mgr *poolm)
+{
+       gen_pool_destroy(poolm->private_data);
+       kfree(poolm);
+}
+
 static const struct tee_shm_pool_mgr_ops pool_ops_generic = {
        .alloc = pool_op_gen_alloc,
        .free = pool_op_gen_free,
+       .destroy_poolmgr = pool_op_gen_destroy_poolmgr,
 };
 
-static void pool_res_mem_destroy(struct tee_shm_pool *pool)
-{
-       gen_pool_destroy(pool->private_mgr.private_data);
-       gen_pool_destroy(pool->dma_buf_mgr.private_data);
-}
-
-static int pool_res_mem_mgr_init(struct tee_shm_pool_mgr *mgr,
-                                struct tee_shm_pool_mem_info *info,
-                                int min_alloc_order)
-{
-       size_t page_mask = PAGE_SIZE - 1;
-       struct gen_pool *genpool = NULL;
-       int rc;
-
-       /*
-        * Start and end must be page aligned
-        */
-       if ((info->vaddr & page_mask) || (info->paddr & page_mask) ||
-           (info->size & page_mask))
-               return -EINVAL;
-
-       genpool = gen_pool_create(min_alloc_order, -1);
-       if (!genpool)
-               return -ENOMEM;
-
-       gen_pool_set_algo(genpool, gen_pool_best_fit, NULL);
-       rc = gen_pool_add_virt(genpool, info->vaddr, info->paddr, info->size,
-                              -1);
-       if (rc) {
-               gen_pool_destroy(genpool);
-               return rc;
-       }
-
-       mgr->private_data = genpool;
-       mgr->ops = &pool_ops_generic;
-       return 0;
-}
-
 /**
  * tee_shm_pool_alloc_res_mem() - Create a shared memory pool from reserved
  * memory range
@@ -104,42 +73,109 @@ struct tee_shm_pool *
 tee_shm_pool_alloc_res_mem(struct tee_shm_pool_mem_info *priv_info,
                           struct tee_shm_pool_mem_info *dmabuf_info)
 {
-       struct tee_shm_pool *pool = NULL;
-       int ret;
-
-       pool = kzalloc(sizeof(*pool), GFP_KERNEL);
-       if (!pool) {
-               ret = -ENOMEM;
-               goto err;
-       }
+       struct tee_shm_pool_mgr *priv_mgr;
+       struct tee_shm_pool_mgr *dmabuf_mgr;
+       void *rc;
 
        /*
         * Create the pool for driver private shared memory
         */
-       ret = pool_res_mem_mgr_init(&pool->private_mgr, priv_info,
-                                   3 /* 8 byte aligned */);
-       if (ret)
-               goto err;
+       rc = tee_shm_pool_mgr_alloc_res_mem(priv_info->vaddr, priv_info->paddr,
+                                           priv_info->size,
+                                           3 /* 8 byte aligned */);
+       if (IS_ERR(rc))
+               return rc;
+       priv_mgr = rc;
 
        /*
         * Create the pool for dma_buf shared memory
         */
-       ret = pool_res_mem_mgr_init(&pool->dma_buf_mgr, dmabuf_info,
-                                   PAGE_SHIFT);
-       if (ret)
+       rc = tee_shm_pool_mgr_alloc_res_mem(dmabuf_info->vaddr,
+                                           dmabuf_info->paddr,
+                                           dmabuf_info->size, PAGE_SHIFT);
+       if (IS_ERR(rc))
+               goto err_free_priv_mgr;
+       dmabuf_mgr = rc;
+
+       rc = tee_shm_pool_alloc(priv_mgr, dmabuf_mgr);
+       if (IS_ERR(rc))
+               goto err_free_dmabuf_mgr;
+
+       return rc;
+
+err_free_dmabuf_mgr:
+       tee_shm_pool_mgr_destroy(dmabuf_mgr);
+err_free_priv_mgr:
+       tee_shm_pool_mgr_destroy(priv_mgr);
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(tee_shm_pool_alloc_res_mem);
+
+struct tee_shm_pool_mgr *tee_shm_pool_mgr_alloc_res_mem(unsigned long vaddr,
+                                                       phys_addr_t paddr,
+                                                       size_t size,
+                                                       int min_alloc_order)
+{
+       const size_t page_mask = PAGE_SIZE - 1;
+       struct tee_shm_pool_mgr *mgr;
+       int rc;
+
+       /* Start and end must be page aligned */
+       if (vaddr & page_mask || paddr & page_mask || size & page_mask)
+               return ERR_PTR(-EINVAL);
+
+       mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
+       if (!mgr)
+               return ERR_PTR(-ENOMEM);
+
+       mgr->private_data = gen_pool_create(min_alloc_order, -1);
+       if (!mgr->private_data) {
+               rc = -ENOMEM;
                goto err;
+       }
 
-       pool->destroy = pool_res_mem_destroy;
-       return pool;
+       gen_pool_set_algo(mgr->private_data, gen_pool_best_fit, NULL);
+       rc = gen_pool_add_virt(mgr->private_data, vaddr, paddr, size, -1);
+       if (rc) {
+               gen_pool_destroy(mgr->private_data);
+               goto err;
+       }
+
+       mgr->ops = &pool_ops_generic;
+
+       return mgr;
 err:
-       if (ret == -ENOMEM)
-               pr_err("%s: can't allocate memory for res_mem shared memory pool\n", __func__);
-       if (pool && pool->private_mgr.private_data)
-               gen_pool_destroy(pool->private_mgr.private_data);
-       kfree(pool);
-       return ERR_PTR(ret);
+       kfree(mgr);
+
+       return ERR_PTR(rc);
 }
-EXPORT_SYMBOL_GPL(tee_shm_pool_alloc_res_mem);
+EXPORT_SYMBOL_GPL(tee_shm_pool_mgr_alloc_res_mem);
+
+static bool check_mgr_ops(struct tee_shm_pool_mgr *mgr)
+{
+       return mgr && mgr->ops && mgr->ops->alloc && mgr->ops->free &&
+               mgr->ops->destroy_poolmgr;
+}
+
+struct tee_shm_pool *tee_shm_pool_alloc(struct tee_shm_pool_mgr *priv_mgr,
+                                       struct tee_shm_pool_mgr *dmabuf_mgr)
+{
+       struct tee_shm_pool *pool;
+
+       if (!check_mgr_ops(priv_mgr) || !check_mgr_ops(dmabuf_mgr))
+               return ERR_PTR(-EINVAL);
+
+       pool = kzalloc(sizeof(*pool), GFP_KERNEL);
+       if (!pool)
+               return ERR_PTR(-ENOMEM);
+
+       pool->private_mgr = priv_mgr;
+       pool->dma_buf_mgr = dmabuf_mgr;
+
+       return pool;
+}
+EXPORT_SYMBOL_GPL(tee_shm_pool_alloc);
 
 /**
  * tee_shm_pool_free() - Free a shared memory pool
@@ -150,7 +186,10 @@ EXPORT_SYMBOL_GPL(tee_shm_pool_alloc_res_mem);
  */
 void tee_shm_pool_free(struct tee_shm_pool *pool)
 {
-       pool->destroy(pool);
+       if (pool->private_mgr)
+               tee_shm_pool_mgr_destroy(pool->private_mgr);
+       if (pool->dma_buf_mgr)
+               tee_shm_pool_mgr_destroy(pool->dma_buf_mgr);
        kfree(pool);
 }
 EXPORT_SYMBOL_GPL(tee_shm_pool_free);
index aa12234..d87a3b0 100644 (file)
@@ -339,7 +339,7 @@ config X86_PKG_TEMP_THERMAL
 
 config INTEL_SOC_DTS_IOSF_CORE
        tristate
-       depends on X86
+       depends on X86 && PCI
        select IOSF_MBI
        help
          This is becoming a common feature for Intel SoCs to expose the additional
@@ -349,7 +349,7 @@ config INTEL_SOC_DTS_IOSF_CORE
 
 config INTEL_SOC_DTS_THERMAL
        tristate "Intel SoCs DTS thermal driver"
-       depends on X86
+       depends on X86 && PCI
        select INTEL_SOC_DTS_IOSF_CORE
        select THERMAL_WRITABLE_TRIPS
        help
index 534dd91..81b35aa 100644 (file)
@@ -54,8 +54,7 @@ static struct thermal_zone_device_ops ops = {
        .get_temp = thermal_get_temp,
 };
 
-#ifdef CONFIG_PM
-static int spear_thermal_suspend(struct device *dev)
+static int __maybe_unused spear_thermal_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct thermal_zone_device *spear_thermal = platform_get_drvdata(pdev);
@@ -72,7 +71,7 @@ static int spear_thermal_suspend(struct device *dev)
        return 0;
 }
 
-static int spear_thermal_resume(struct device *dev)
+static int __maybe_unused spear_thermal_resume(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct thermal_zone_device *spear_thermal = platform_get_drvdata(pdev);
@@ -94,7 +93,6 @@ static int spear_thermal_resume(struct device *dev)
 
        return 0;
 }
-#endif
 
 static SIMPLE_DEV_PM_OPS(spear_thermal_pm_ops, spear_thermal_suspend,
                spear_thermal_resume);
index c01f450..4537abf 100644 (file)
@@ -226,7 +226,7 @@ config CYCLADES
 
 config CYZ_INTR
        bool "Cyclades-Z interrupt mode operation"
-       depends on CYCLADES
+       depends on CYCLADES && PCI
        help
          The Cyclades-Z family of multiport cards allows 2 (two) driver op
          modes: polling and interrupt. In polling mode, the driver will check
@@ -403,9 +403,16 @@ config PPC_EARLY_DEBUG_EHV_BC_HANDLE
 config GOLDFISH_TTY
        tristate "Goldfish TTY Driver"
        depends on GOLDFISH
+       select SERIAL_CORE
+       select SERIAL_CORE_CONSOLE
        help
          Console and system TTY driver for the Goldfish virtual platform.
 
+config GOLDFISH_TTY_EARLY_CONSOLE
+       bool
+       default y if GOLDFISH_TTY=y
+       select SERIAL_EARLYCON
+
 config DA_TTY
        bool "DA TTY"
        depends on METAG_DA
index 1e33285..c6ec9e6 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Copyright (C) 2007 Google, Inc.
  * Copyright (C) 2012 Intel, Inc.
+ * Copyright (C) 2017 Imagination Technologies Ltd.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/goldfish.h>
-
-enum {
-       GOLDFISH_TTY_PUT_CHAR       = 0x00,
-       GOLDFISH_TTY_BYTES_READY    = 0x04,
-       GOLDFISH_TTY_CMD            = 0x08,
-
-       GOLDFISH_TTY_DATA_PTR       = 0x10,
-       GOLDFISH_TTY_DATA_LEN       = 0x14,
-       GOLDFISH_TTY_DATA_PTR_HIGH  = 0x18,
-
-       GOLDFISH_TTY_CMD_INT_DISABLE    = 0,
-       GOLDFISH_TTY_CMD_INT_ENABLE     = 1,
-       GOLDFISH_TTY_CMD_WRITE_BUFFER   = 2,
-       GOLDFISH_TTY_CMD_READ_BUFFER    = 3,
-};
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include <linux/serial_core.h>
+
+/* Goldfish tty register's offsets */
+#define        GOLDFISH_TTY_REG_BYTES_READY    0x04
+#define        GOLDFISH_TTY_REG_CMD            0x08
+#define        GOLDFISH_TTY_REG_DATA_PTR       0x10
+#define        GOLDFISH_TTY_REG_DATA_LEN       0x14
+#define        GOLDFISH_TTY_REG_DATA_PTR_HIGH  0x18
+#define        GOLDFISH_TTY_REG_VERSION        0x20
+
+/* Goldfish tty commands */
+#define        GOLDFISH_TTY_CMD_INT_DISABLE    0
+#define        GOLDFISH_TTY_CMD_INT_ENABLE     1
+#define        GOLDFISH_TTY_CMD_WRITE_BUFFER   2
+#define        GOLDFISH_TTY_CMD_READ_BUFFER    3
 
 struct goldfish_tty {
        struct tty_port port;
@@ -45,6 +48,8 @@ struct goldfish_tty {
        u32 irq;
        int opencount;
        struct console console;
+       u32 version;
+       struct device *dev;
 };
 
 static DEFINE_MUTEX(goldfish_tty_lock);
@@ -53,38 +58,107 @@ static u32 goldfish_tty_line_count = 8;
 static u32 goldfish_tty_current_line_count;
 static struct goldfish_tty *goldfish_ttys;
 
-static void goldfish_tty_do_write(int line, const char *buf, unsigned count)
+static void do_rw_io(struct goldfish_tty *qtty,
+                    unsigned long address,
+                    unsigned int count,
+                    int is_write)
 {
        unsigned long irq_flags;
-       struct goldfish_tty *qtty = &goldfish_ttys[line];
        void __iomem *base = qtty->base;
+
        spin_lock_irqsave(&qtty->lock, irq_flags);
-       gf_write_ptr(buf, base + GOLDFISH_TTY_DATA_PTR,
-                               base + GOLDFISH_TTY_DATA_PTR_HIGH);
-       writel(count, base + GOLDFISH_TTY_DATA_LEN);
-       writel(GOLDFISH_TTY_CMD_WRITE_BUFFER, base + GOLDFISH_TTY_CMD);
+       gf_write_ptr((void *)address, base + GOLDFISH_TTY_REG_DATA_PTR,
+                    base + GOLDFISH_TTY_REG_DATA_PTR_HIGH);
+       writel(count, base + GOLDFISH_TTY_REG_DATA_LEN);
+
+       if (is_write)
+               writel(GOLDFISH_TTY_CMD_WRITE_BUFFER,
+                      base + GOLDFISH_TTY_REG_CMD);
+       else
+               writel(GOLDFISH_TTY_CMD_READ_BUFFER,
+                      base + GOLDFISH_TTY_REG_CMD);
+
        spin_unlock_irqrestore(&qtty->lock, irq_flags);
 }
 
+static void goldfish_tty_rw(struct goldfish_tty *qtty,
+                           unsigned long addr,
+                           unsigned int count,
+                           int is_write)
+{
+       dma_addr_t dma_handle;
+       enum dma_data_direction dma_dir;
+
+       dma_dir = (is_write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+       if (qtty->version > 0) {
+               /*
+                * Goldfish TTY for Ranchu platform uses
+                * physical addresses and DMA for read/write operations
+                */
+               unsigned long addr_end = addr + count;
+
+               while (addr < addr_end) {
+                       unsigned long pg_end = (addr & PAGE_MASK) + PAGE_SIZE;
+                       unsigned long next =
+                                       pg_end < addr_end ? pg_end : addr_end;
+                       unsigned long avail = next - addr;
+
+                       /*
+                        * Map the buffer's virtual address to the DMA address
+                        * so the buffer can be accessed by the device.
+                        */
+                       dma_handle = dma_map_single(qtty->dev, (void *)addr,
+                                                   avail, dma_dir);
+
+                       if (dma_mapping_error(qtty->dev, dma_handle)) {
+                               dev_err(qtty->dev, "tty: DMA mapping error.\n");
+                               return;
+                       }
+                       do_rw_io(qtty, dma_handle, avail, is_write);
+
+                       /*
+                        * Unmap the previously mapped region after
+                        * the completion of the read/write operation.
+                        */
+                       dma_unmap_single(qtty->dev, dma_handle, avail, dma_dir);
+
+                       addr += avail;
+               }
+       } else {
+               /*
+                * Old style Goldfish TTY used on the Goldfish platform
+                * uses virtual addresses.
+                */
+               do_rw_io(qtty, addr, count, is_write);
+       }
+}
+
+static void goldfish_tty_do_write(int line, const char *buf,
+                                 unsigned int count)
+{
+       struct goldfish_tty *qtty = &goldfish_ttys[line];
+       unsigned long address = (unsigned long)(void *)buf;
+
+       goldfish_tty_rw(qtty, address, count, 1);
+}
+
 static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id)
 {
        struct goldfish_tty *qtty = dev_id;
        void __iomem *base = qtty->base;
-       unsigned long irq_flags;
+       unsigned long address;
        unsigned char *buf;
        u32 count;
 
-       count = readl(base + GOLDFISH_TTY_BYTES_READY);
+       count = readl(base + GOLDFISH_TTY_REG_BYTES_READY);
        if (count == 0)
                return IRQ_NONE;
 
        count = tty_prepare_flip_string(&qtty->port, &buf, count);
-       spin_lock_irqsave(&qtty->lock, irq_flags);
-       gf_write_ptr(buf, base + GOLDFISH_TTY_DATA_PTR,
-                               base + GOLDFISH_TTY_DATA_PTR_HIGH);
-       writel(count, base + GOLDFISH_TTY_DATA_LEN);
-       writel(GOLDFISH_TTY_CMD_READ_BUFFER, base + GOLDFISH_TTY_CMD);
-       spin_unlock_irqrestore(&qtty->lock, irq_flags);
+
+       address = (unsigned long)(void *)buf;
+       goldfish_tty_rw(qtty, address, count, 0);
+
        tty_schedule_flip(&qtty->port);
        return IRQ_HANDLED;
 }
@@ -93,7 +167,7 @@ static int goldfish_tty_activate(struct tty_port *port, struct tty_struct *tty)
 {
        struct goldfish_tty *qtty = container_of(port, struct goldfish_tty,
                                                                        port);
-       writel(GOLDFISH_TTY_CMD_INT_ENABLE, qtty->base + GOLDFISH_TTY_CMD);
+       writel(GOLDFISH_TTY_CMD_INT_ENABLE, qtty->base + GOLDFISH_TTY_REG_CMD);
        return 0;
 }
 
@@ -101,7 +175,7 @@ static void goldfish_tty_shutdown(struct tty_port *port)
 {
        struct goldfish_tty *qtty = container_of(port, struct goldfish_tty,
                                                                        port);
-       writel(GOLDFISH_TTY_CMD_INT_DISABLE, qtty->base + GOLDFISH_TTY_CMD);
+       writel(GOLDFISH_TTY_CMD_INT_DISABLE, qtty->base + GOLDFISH_TTY_REG_CMD);
 }
 
 static int goldfish_tty_open(struct tty_struct *tty, struct file *filp)
@@ -136,7 +210,7 @@ static int goldfish_tty_chars_in_buffer(struct tty_struct *tty)
 {
        struct goldfish_tty *qtty = &goldfish_ttys[tty->index];
        void __iomem *base = qtty->base;
-       return readl(base + GOLDFISH_TTY_BYTES_READY);
+       return readl(base + GOLDFISH_TTY_REG_BYTES_READY);
 }
 
 static void goldfish_tty_console_write(struct console *co, const char *b,
@@ -227,7 +301,7 @@ static void goldfish_tty_delete_driver(void)
 static int goldfish_tty_probe(struct platform_device *pdev)
 {
        struct goldfish_tty *qtty;
-       int ret = -EINVAL;
+       int ret = -ENODEV;
        struct resource *r;
        struct device *ttydev;
        void __iomem *base;
@@ -235,16 +309,22 @@ static int goldfish_tty_probe(struct platform_device *pdev)
        unsigned int line;
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (r == NULL)
-               return -EINVAL;
+       if (!r) {
+               pr_err("goldfish_tty: No MEM resource available!\n");
+               return -ENOMEM;
+       }
 
        base = ioremap(r->start, 0x1000);
-       if (base == NULL)
-               pr_err("goldfish_tty: unable to remap base\n");
+       if (!base) {
+               pr_err("goldfish_tty: Unable to ioremap base!\n");
+               return -ENOMEM;
+       }
 
        r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (r == NULL)
+       if (!r) {
+               pr_err("goldfish_tty: No IRQ resource available!\n");
                goto err_unmap;
+       }
 
        irq = r->start;
 
@@ -255,13 +335,17 @@ static int goldfish_tty_probe(struct platform_device *pdev)
        else
                line = pdev->id;
 
-       if (line >= goldfish_tty_line_count)
-               goto err_create_driver_failed;
+       if (line >= goldfish_tty_line_count) {
+               pr_err("goldfish_tty: Reached maximum tty number of %d.\n",
+                      goldfish_tty_current_line_count);
+               ret = -ENOMEM;
+               goto err_unlock;
+       }
 
        if (goldfish_tty_current_line_count == 0) {
                ret = goldfish_tty_create_driver();
                if (ret)
-                       goto err_create_driver_failed;
+                       goto err_unlock;
        }
        goldfish_tty_current_line_count++;
 
@@ -271,17 +355,45 @@ static int goldfish_tty_probe(struct platform_device *pdev)
        qtty->port.ops = &goldfish_port_ops;
        qtty->base = base;
        qtty->irq = irq;
+       qtty->dev = &pdev->dev;
+
+       /*
+        * Goldfish TTY device used by the Goldfish emulator
+        * should identify itself with 0, forcing the driver
+        * to use virtual addresses. Goldfish TTY device
+        * on Ranchu emulator (qemu2) returns 1 here and
+        * driver will use physical addresses.
+        */
+       qtty->version = readl(base + GOLDFISH_TTY_REG_VERSION);
+
+       /*
+        * Goldfish TTY device on Ranchu emulator (qemu2)
+        * will use DMA for read/write IO operations.
+        */
+       if (qtty->version > 0) {
+               /*
+                * Initialize dma_mask to 32-bits.
+                */
+               if (!pdev->dev.dma_mask)
+                       pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+               ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+               if (ret) {
+                       dev_err(&pdev->dev, "No suitable DMA available.\n");
+                       goto err_dec_line_count;
+               }
+       }
 
-       writel(GOLDFISH_TTY_CMD_INT_DISABLE, base + GOLDFISH_TTY_CMD);
+       writel(GOLDFISH_TTY_CMD_INT_DISABLE, base + GOLDFISH_TTY_REG_CMD);
 
        ret = request_irq(irq, goldfish_tty_interrupt, IRQF_SHARED,
-                                               "goldfish_tty", qtty);
-       if (ret)
-               goto err_request_irq_failed;
-
+                         "goldfish_tty", qtty);
+       if (ret) {
+               pr_err("goldfish_tty: No IRQ available!\n");
+               goto err_dec_line_count;
+       }
 
        ttydev = tty_port_register_device(&qtty->port, goldfish_tty_driver,
-                                                       line, &pdev->dev);
+                                         line, &pdev->dev);
        if (IS_ERR(ttydev)) {
                ret = PTR_ERR(ttydev);
                goto err_tty_register_device_failed;
@@ -300,12 +412,12 @@ static int goldfish_tty_probe(struct platform_device *pdev)
        return 0;
 
 err_tty_register_device_failed:
-       free_irq(irq, pdev);
-err_request_irq_failed:
+       free_irq(irq, qtty);
+err_dec_line_count:
        goldfish_tty_current_line_count--;
        if (goldfish_tty_current_line_count == 0)
                goldfish_tty_delete_driver();
-err_create_driver_failed:
+err_unlock:
        mutex_unlock(&goldfish_tty_lock);
 err_unmap:
        iounmap(base);
@@ -330,6 +442,32 @@ static int goldfish_tty_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_GOLDFISH_TTY_EARLY_CONSOLE
+static void gf_early_console_putchar(struct uart_port *port, int ch)
+{
+       __raw_writel(ch, port->membase);
+}
+
+static void gf_early_write(struct console *con, const char *s, unsigned int n)
+{
+       struct earlycon_device *dev = con->data;
+
+       uart_console_write(&dev->port, s, n, gf_early_console_putchar);
+}
+
+static int __init gf_earlycon_setup(struct earlycon_device *device,
+                                   const char *opt)
+{
+       if (!device->port.membase)
+               return -ENODEV;
+
+       device->con->write = gf_early_write;
+       return 0;
+}
+
+OF_EARLYCON_DECLARE(early_gf_tty, "google,goldfish-tty", gf_earlycon_setup);
+#endif
+
 static const struct of_device_id goldfish_tty_of_match[] = {
        { .compatible = "google,goldfish-tty", },
        {},
index fa816b7..1172542 100644 (file)
@@ -323,6 +323,7 @@ void xen_console_resume(void)
        }
 }
 
+#ifdef CONFIG_HVC_XEN_FRONTEND
 static void xencons_disconnect_backend(struct xencons_info *info)
 {
        if (info->irq > 0)
@@ -363,7 +364,6 @@ static int xen_console_remove(struct xencons_info *info)
        return 0;
 }
 
-#ifdef CONFIG_HVC_XEN_FRONTEND
 static int xencons_remove(struct xenbus_device *dev)
 {
        return xen_console_remove(dev_get_drvdata(&dev->dev));
index 6412f14..6f4c180 100644 (file)
@@ -372,7 +372,7 @@ config SERIAL_8250_MID
        tristate "Support for serial ports on Intel MID platforms"
        depends on SERIAL_8250 && PCI
        select HSU_DMA if SERIAL_8250_DMA
-       select HSU_DMA_PCI if X86_INTEL_MID
+       select HSU_DMA_PCI if (HSU_DMA && X86_INTEL_MID)
        select RATIONAL
        help
          Selecting this option will enable handling of the extra features
index ad8c9b0..01656f1 100644 (file)
@@ -2202,7 +2202,7 @@ static struct configfs_item_operations uvc_item_ops = {
        .release                = uvc_attr_release,
 };
 
-#define UVCG_OPTS_ATTR(cname, conv, str2u, uxx, vnoc, limit)           \
+#define UVCG_OPTS_ATTR(cname, aname, conv, str2u, uxx, vnoc, limit)    \
 static ssize_t f_uvc_opts_##cname##_show(                              \
        struct config_item *item, char *page)                           \
 {                                                                      \
@@ -2245,16 +2245,16 @@ end:                                                                    \
        return ret;                                                     \
 }                                                                      \
                                                                        \
-UVC_ATTR(f_uvc_opts_, cname, aname)
+UVC_ATTR(f_uvc_opts_, cname, cname)
 
 #define identity_conv(x) (x)
 
-UVCG_OPTS_ATTR(streaming_interval, identity_conv, kstrtou8, u8, identity_conv,
-              16);
-UVCG_OPTS_ATTR(streaming_maxpacket, le16_to_cpu, kstrtou16, u16, le16_to_cpu,
-              3072);
-UVCG_OPTS_ATTR(streaming_maxburst, identity_conv, kstrtou8, u8, identity_conv,
-              15);
+UVCG_OPTS_ATTR(streaming_interval, streaming_interval, identity_conv,
+              kstrtou8, u8, identity_conv, 16);
+UVCG_OPTS_ATTR(streaming_maxpacket, streaming_maxpacket, le16_to_cpu,
+              kstrtou16, u16, le16_to_cpu, 3072);
+UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, identity_conv,
+              kstrtou8, u8, identity_conv, 15);
 
 #undef identity_conv
 
index 3bb0887..95e72d7 100644 (file)
@@ -220,6 +220,8 @@ config USB_EHCI_TEGRA
        depends on ARCH_TEGRA
        select USB_EHCI_ROOT_HUB_TT
        select USB_PHY
+       select USB_ULPI
+       select USB_ULPI_VIEWPORT
        help
          This driver enables support for the internal USB Host Controllers
          found in NVIDIA Tegra SoCs. The controllers are EHCI compliant.
index d0b6a1c..c92a295 100644 (file)
@@ -207,9 +207,6 @@ static int ux500_dma_channel_program(struct dma_channel *channel,
        BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN ||
                channel->status == MUSB_DMA_STATUS_BUSY);
 
-       if (!ux500_dma_is_compatible(channel, packet_sz, (void *)dma_addr, len))
-               return false;
-
        channel->status = MUSB_DMA_STATUS_BUSY;
        channel->actual_len = 0;
        ret = ux500_configure_channel(channel, packet_sz, mode, dma_addr, len);
index 732fa21..e358fc8 100644 (file)
@@ -148,6 +148,7 @@ config USB_MSM_OTG
        tristate "Qualcomm on-chip USB OTG controller support"
        depends on (USB || USB_GADGET) && (ARCH_QCOM || COMPILE_TEST)
        depends on RESET_CONTROLLER
+       depends on REGULATOR
        depends on EXTCON
        select USB_PHY
        help
index ec38370..0931f32 100644 (file)
@@ -87,6 +87,7 @@ static ssize_t store_sockfd(struct device *dev, struct device_attribute *attr,
                        goto err;
 
                sdev->ud.tcp_socket = socket;
+               sdev->ud.sockfd = sockfd;
 
                spin_unlock_irq(&sdev->ud.lock);
 
@@ -186,6 +187,7 @@ static void stub_shutdown_connection(struct usbip_device *ud)
        if (ud->tcp_socket) {
                sockfd_put(ud->tcp_socket);
                ud->tcp_socket = NULL;
+               ud->sockfd = -1;
        }
 
        /* 3. free used data */
@@ -280,6 +282,7 @@ static struct stub_device *stub_device_alloc(struct usb_device *udev)
        sdev->ud.status         = SDEV_ST_AVAILABLE;
        spin_lock_init(&sdev->ud.lock);
        sdev->ud.tcp_socket     = NULL;
+       sdev->ud.sockfd         = -1;
 
        INIT_LIST_HEAD(&sdev->priv_init);
        INIT_LIST_HEAD(&sdev->priv_tx);
index 00d6894..4d68a1e 100644 (file)
@@ -285,7 +285,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                case USB_PORT_FEAT_POWER:
                        usbip_dbg_vhci_rh(
                                " ClearPortFeature: USB_PORT_FEAT_POWER\n");
-                       dum->port_status[rhport] = 0;
+                       dum->port_status[rhport] &= ~USB_PORT_STAT_POWER;
                        dum->resuming = 0;
                        break;
                case USB_PORT_FEAT_C_RESET:
@@ -797,6 +797,7 @@ static void vhci_shutdown_connection(struct usbip_device *ud)
        if (vdev->ud.tcp_socket) {
                sockfd_put(vdev->ud.tcp_socket);
                vdev->ud.tcp_socket = NULL;
+               vdev->ud.sockfd = -1;
        }
        pr_info("release socket\n");
 
@@ -844,6 +845,7 @@ static void vhci_device_reset(struct usbip_device *ud)
        if (ud->tcp_socket) {
                sockfd_put(ud->tcp_socket);
                ud->tcp_socket = NULL;
+               ud->sockfd = -1;
        }
        ud->status = VDEV_ST_NULL;
 
index 1c7f41a..b9432fd 100644 (file)
@@ -53,7 +53,7 @@ static ssize_t status_show(struct device *dev, struct device_attribute *attr,
         * a security hole, the change is made to use sockfd instead.
         */
        out += sprintf(out,
-                      "prt sta spd bus dev sockfd local_busid\n");
+                      "prt sta spd dev      sockfd local_busid\n");
 
        for (i = 0; i < VHCI_NPORTS; i++) {
                struct vhci_device *vdev = port_to_vdev(i);
@@ -64,12 +64,11 @@ static ssize_t status_show(struct device *dev, struct device_attribute *attr,
                if (vdev->ud.status == VDEV_ST_USED) {
                        out += sprintf(out, "%03u %08x ",
                                       vdev->speed, vdev->devid);
-                       out += sprintf(out, "%16p ", vdev->ud.tcp_socket);
-                       out += sprintf(out, "%06u", vdev->ud.sockfd);
+                       out += sprintf(out, "%06u ", vdev->ud.sockfd);
                        out += sprintf(out, "%s", dev_name(&vdev->udev->dev));
 
                } else
-                       out += sprintf(out, "000 000 000 000000 0-0");
+                       out += sprintf(out, "000 00000000 000000 0-0");
 
                out += sprintf(out, "\n");
                spin_unlock(&vdev->ud.lock);
index 9eda69e..44a5a87 100644 (file)
@@ -981,6 +981,7 @@ static long vhost_net_reset_owner(struct vhost_net *n)
        }
        vhost_net_stop(n, &tx_sock, &rx_sock);
        vhost_net_flush(n);
+       vhost_dev_stop(&n->dev);
        vhost_dev_reset_owner(&n->dev, memory);
        vhost_net_vq_reset(n);
 done:
index 0efc52f..b30e7d8 100644 (file)
@@ -68,7 +68,6 @@ const struct consw dummy_con = {
     .con_switch =      DUMMY,
     .con_blank =       DUMMY,
     .con_font_set =    DUMMY,
-    .con_font_get =    DUMMY,
     .con_font_default =        DUMMY,
     .con_font_copy =   DUMMY,
     .con_set_palette = DUMMY,
index 9868d8a..3f7f92a 100644 (file)
@@ -1506,6 +1506,7 @@ config FB_SIS
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
        select FB_BOOT_VESA_SUPPORT if FB_SIS = y
+       select FB_SIS_300 if !FB_SIS_315
        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.
index 19eb42b..a6da826 100644 (file)
@@ -1120,7 +1120,7 @@ static int atmel_lcdfb_of_init(struct atmel_lcdfb_info *sinfo)
                goto put_display_node;
        }
 
-       timings_np = of_find_node_by_name(display_np, "display-timings");
+       timings_np = of_get_child_by_name(display_np, "display-timings");
        if (!timings_np) {
                dev_err(dev, "failed to find display-timings node\n");
                ret = -ENODEV;
@@ -1141,6 +1141,12 @@ static int atmel_lcdfb_of_init(struct atmel_lcdfb_info *sinfo)
                fb_add_videomode(&fb_vm, &info->modelist);
        }
 
+       /*
+        * FIXME: Make sure we are not referencing any fields in display_np
+        * and timings_np and drop our references to them before returning to
+        * avoid leaking the nodes on probe deferral and driver unbind.
+        */
+
        return 0;
 
 put_timings_node:
index 8d2499d..9580374 100644 (file)
@@ -773,9 +773,7 @@ static void auok190x_recover(struct auok190xfb_par *par)
 /*
  * Power-management
  */
-
-#ifdef CONFIG_PM
-static int auok190x_runtime_suspend(struct device *dev)
+static int __maybe_unused auok190x_runtime_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct fb_info *info = platform_get_drvdata(pdev);
@@ -822,7 +820,7 @@ finish:
        return 0;
 }
 
-static int auok190x_runtime_resume(struct device *dev)
+static int __maybe_unused auok190x_runtime_resume(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct fb_info *info = platform_get_drvdata(pdev);
@@ -856,7 +854,7 @@ static int auok190x_runtime_resume(struct device *dev)
        return 0;
 }
 
-static int auok190x_suspend(struct device *dev)
+static int __maybe_unused auok190x_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct fb_info *info = platform_get_drvdata(pdev);
@@ -896,7 +894,7 @@ static int auok190x_suspend(struct device *dev)
        return 0;
 }
 
-static int auok190x_resume(struct device *dev)
+static int __maybe_unused auok190x_resume(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct fb_info *info = platform_get_drvdata(pdev);
@@ -933,7 +931,6 @@ static int auok190x_resume(struct device *dev)
 
        return 0;
 }
-#endif
 
 const struct dev_pm_ops auok190x_pm = {
        SET_RUNTIME_PM_OPS(auok190x_runtime_suspend, auok190x_runtime_resume,
index 95873f2..de2f3e7 100644 (file)
@@ -829,8 +829,7 @@ static int s6e8ax0_probe(struct mipi_dsim_lcd_device *dsim_dev)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int s6e8ax0_suspend(struct mipi_dsim_lcd_device *dsim_dev)
+static int __maybe_unused s6e8ax0_suspend(struct mipi_dsim_lcd_device *dsim_dev)
 {
        struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
 
@@ -843,7 +842,7 @@ static int s6e8ax0_suspend(struct mipi_dsim_lcd_device *dsim_dev)
        return 0;
 }
 
-static int s6e8ax0_resume(struct mipi_dsim_lcd_device *dsim_dev)
+static int __maybe_unused s6e8ax0_resume(struct mipi_dsim_lcd_device *dsim_dev)
 {
        struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
 
@@ -855,10 +854,6 @@ static int s6e8ax0_resume(struct mipi_dsim_lcd_device *dsim_dev)
 
        return 0;
 }
-#else
-#define s6e8ax0_suspend                NULL
-#define s6e8ax0_resume         NULL
-#endif
 
 static struct mipi_dsim_lcd_driver s6e8ax0_dsim_ddi_driver = {
        .name = "s6e8ax0",
@@ -867,8 +862,8 @@ static struct mipi_dsim_lcd_driver s6e8ax0_dsim_ddi_driver = {
        .power_on = s6e8ax0_power_on,
        .set_sequence = s6e8ax0_set_sequence,
        .probe = s6e8ax0_probe,
-       .suspend = s6e8ax0_suspend,
-       .resume = s6e8ax0_resume,
+       .suspend = IS_ENABLED(CONFIG_PM) ? s6e8ax0_suspend : NULL,
+       .resume = IS_ENABLED(CONFIG_PM) ? s6e8ax0_resume : NULL,
 };
 
 static int s6e8ax0_init(void)
index bbec737..bf20744 100644 (file)
@@ -302,7 +302,7 @@ static __inline__ int get_opt_int(const char *this_opt, const char *name,
 }
 
 static __inline__ int get_opt_bool(const char *this_opt, const char *name,
-                                  int *ret)
+                                  bool *ret)
 {
        if (!ret)
                return 0;
index a0f4960..3a6bb65 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/slab.h>
 #include <linux/dma-mapping.h>
 #include <linux/export.h>
+#include <linux/module.h>
 #include <video/mmp_disp.h>
 
 static struct mmp_overlay *path_get_overlay(struct mmp_path *path,
@@ -249,3 +250,7 @@ void mmp_unregister_path(struct mmp_path *path)
        mutex_unlock(&disp_lock);
 }
 EXPORT_SYMBOL_GPL(mmp_unregister_path);
+
+MODULE_AUTHOR("Zhou Zhu <zzhu3@marvell.com>");
+MODULE_DESCRIPTION("Marvell MMP display framework");
+MODULE_LICENSE("GPL");
index 5548f0f..1ccb271 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -255,6 +255,13 @@ struct mdss_scaler_block {
        u32 *dest_scaler_off;
        u32 *dest_scaler_lut_off;
        struct mdss_mdp_qseed3_lut_tbl lut_tbl;
+
+       /*
+        * Lock is mainly to serialize access to LUT.
+        * LUT values come asynchronously from userspace
+        * via ioctl.
+        */
+       struct mutex scaler_lock;
 };
 
 struct mdss_data_type;
index 410d36a..a77e5c4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * MDSS MDP Interface (used by framebuffer core)
  *
- * Copyright (c) 2007-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2007-2018, The Linux Foundation. All rights reserved.
  * Copyright (C) 2007 Google Incorporated
  *
  * This software is licensed under the terms of the GNU General Public
@@ -2436,6 +2436,8 @@ static u32 mdss_mdp_scaler_init(struct mdss_data_type *mdata,
                ret = mdss_mdp_ds_addr_setup(mdata);
        }
 
+       mutex_init(&mdata->scaler_off->scaler_lock);
+
        return ret;
 }
 
index 54fb21a..632d73e 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -5912,9 +5912,7 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg,
                } else {
                        sctl_flush_bits = sctl->flush_bits;
                }
-               sctl->commit_in_progress = true;
        }
-       ctl->commit_in_progress = true;
        ctl_flush_bits = ctl->flush_bits;
 
        ATRACE_END("postproc_programming");
@@ -5928,6 +5926,9 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg,
                        MDP_COMMIT_STAGE_SETUP_DONE,
                        commit_cb->data);
        ret = mdss_mdp_ctl_notify(ctl, MDP_NOTIFY_FRAME_READY);
+       ctl->commit_in_progress = true;
+       if (sctl)
+               sctl->commit_in_progress = true;
 
        /*
         * When wait for fence timed out, driver ignores the fences
index 11c1596..791c73b 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -6631,14 +6631,18 @@ static int mdss_mdp_scaler_lut_init(struct mdss_data_type *mdata,
        if (!mdata->scaler_off)
                return -EFAULT;
 
+       mutex_lock(&mdata->scaler_off->scaler_lock);
+
        qseed3_lut_tbl = &mdata->scaler_off->lut_tbl;
        if ((lut_tbl->dir_lut_size !=
                DIR_LUT_IDX * DIR_LUT_COEFFS * sizeof(uint32_t)) ||
                (lut_tbl->cir_lut_size !=
                 CIR_LUT_IDX * CIR_LUT_COEFFS * sizeof(uint32_t)) ||
                (lut_tbl->sep_lut_size !=
-                SEP_LUT_IDX * SEP_LUT_COEFFS * sizeof(uint32_t)))
-                       return -EINVAL;
+                SEP_LUT_IDX * SEP_LUT_COEFFS * sizeof(uint32_t))) {
+               mutex_unlock(&mdata->scaler_off->scaler_lock);
+               return -EINVAL;
+       }
 
        if (!qseed3_lut_tbl->dir_lut) {
                qseed3_lut_tbl->dir_lut = devm_kzalloc(&mdata->pdev->dev,
@@ -6646,7 +6650,7 @@ static int mdss_mdp_scaler_lut_init(struct mdss_data_type *mdata,
                                GFP_KERNEL);
                if (!qseed3_lut_tbl->dir_lut) {
                        ret = -ENOMEM;
-                       goto fail;
+                       goto err;
                }
        }
 
@@ -6656,7 +6660,7 @@ static int mdss_mdp_scaler_lut_init(struct mdss_data_type *mdata,
                                GFP_KERNEL);
                if (!qseed3_lut_tbl->cir_lut) {
                        ret = -ENOMEM;
-                       goto fail;
+                       goto fail_free_dir_lut;
                }
        }
 
@@ -6666,44 +6670,52 @@ static int mdss_mdp_scaler_lut_init(struct mdss_data_type *mdata,
                                GFP_KERNEL);
                if (!qseed3_lut_tbl->sep_lut) {
                        ret = -ENOMEM;
-                       goto fail;
+                       goto fail_free_cir_lut;
                }
        }
 
        /* Invalidate before updating */
        qseed3_lut_tbl->valid = false;
 
-
        if (copy_from_user(qseed3_lut_tbl->dir_lut,
                                (void *)(unsigned long)lut_tbl->dir_lut,
                                lut_tbl->dir_lut_size)) {
                        ret = -EINVAL;
-                       goto err;
+                       goto fail_free_sep_lut;
        }
 
        if (copy_from_user(qseed3_lut_tbl->cir_lut,
                                (void *)(unsigned long)lut_tbl->cir_lut,
                                lut_tbl->cir_lut_size)) {
                        ret = -EINVAL;
-                       goto err;
+                       goto fail_free_sep_lut;
        }
 
        if (copy_from_user(qseed3_lut_tbl->sep_lut,
                                (void *)(unsigned long)lut_tbl->sep_lut,
                                lut_tbl->sep_lut_size)) {
                        ret = -EINVAL;
-                       goto err;
+                       goto fail_free_sep_lut;
        }
 
        qseed3_lut_tbl->valid = true;
+       mutex_unlock(&mdata->scaler_off->scaler_lock);
+
        return ret;
 
-fail:
-       kfree(qseed3_lut_tbl->dir_lut);
-       kfree(qseed3_lut_tbl->cir_lut);
-       kfree(qseed3_lut_tbl->sep_lut);
+fail_free_sep_lut:
+       devm_kfree(&mdata->pdev->dev, qseed3_lut_tbl->sep_lut);
+fail_free_cir_lut:
+       devm_kfree(&mdata->pdev->dev, qseed3_lut_tbl->cir_lut);
+fail_free_dir_lut:
+       devm_kfree(&mdata->pdev->dev, qseed3_lut_tbl->dir_lut);
 err:
+       qseed3_lut_tbl->dir_lut = NULL;
+       qseed3_lut_tbl->cir_lut = NULL;
+       qseed3_lut_tbl->sep_lut = NULL;
        qseed3_lut_tbl->valid = false;
+       mutex_unlock(&mdata->scaler_off->scaler_lock);
+
        return ret;
 }
 
index 9c2b1d4..ee338ba 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1604,11 +1604,16 @@ int mdss_mdp_scaler_lut_cfg(struct mdp_scale_data_v2 *scaler,
        };
 
        mdata = mdss_mdp_get_mdata();
+
+       mutex_lock(&mdata->scaler_off->scaler_lock);
+
        lut_tbl = &mdata->scaler_off->lut_tbl;
        if ((!lut_tbl) || (!lut_tbl->valid)) {
+               mutex_unlock(&mdata->scaler_off->scaler_lock);
                pr_err("%s:Invalid QSEED3 LUT TABLE\n", __func__);
                return -EINVAL;
        }
+
        if ((scaler->lut_flag & SCALER_LUT_DIR_WR) ||
                (scaler->lut_flag & SCALER_LUT_Y_CIR_WR) ||
                (scaler->lut_flag & SCALER_LUT_UV_CIR_WR) ||
@@ -1656,6 +1661,8 @@ int mdss_mdp_scaler_lut_cfg(struct mdp_scale_data_v2 *scaler,
                }
        }
 
+       mutex_unlock(&mdata->scaler_off->scaler_lock);
+
        return 0;
 }
 
index bb3a551..086946e 100644 (file)
@@ -761,7 +761,7 @@ static void adv7533_notify_clients(struct msm_dba_device_info *dev,
 u32 adv7533_read_edid(struct adv7533 *pdata, u32 size, char *edid_buf)
 {
        u32 ret = 0, read_size = size / 2;
-       u8 edid_addr;
+       u8 edid_addr = 0;
        int ndx;
 
        if (!pdata || !edid_buf)
@@ -1008,7 +1008,7 @@ end:
 static void *adv7533_handle_hpd_intr(struct adv7533 *pdata)
 {
        int ret = 0;
-       u8 hpd_state;
+       u8 hpd_state = 0;
        u8 connected = 0, disconnected = 0;
 
        if (!pdata) {
@@ -1040,7 +1040,8 @@ end:
 static int adv7533_enable_interrupts(struct adv7533 *pdata, int interrupts)
 {
        int ret = 0;
-       u8 reg_val, init_reg_val;
+       u8 reg_val = 0;
+       u8 init_reg_val;
 
        if (!pdata) {
                pr_err("%s: invalid input\n", __func__);
@@ -1086,7 +1087,8 @@ end:
 static int adv7533_disable_interrupts(struct adv7533 *pdata, int interrupts)
 {
        int ret = 0;
-       u8 reg_val, init_reg_val;
+       u8 reg_val = 0;
+       u8 init_reg_val;
 
        if (!pdata) {
                pr_err("%s: invalid input\n", __func__);
@@ -1652,7 +1654,7 @@ static int adv7533_hdcp_enable(void *client, bool hdcp_on,
        bool enc_on, u32 flags)
 {
        int ret = -EINVAL;
-       u8 reg_val;
+       u8 reg_val = 0;
        struct adv7533 *pdata =
                adv7533_get_platform_data(client);
 
index 295e0de..20f7234 100644 (file)
@@ -2151,17 +2151,15 @@ SiS_GetVCLK2Ptr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned shor
                unsigned short RefreshRateTableIndex)
 {
   unsigned short CRT2Index, VCLKIndex = 0, VCLKIndexGEN = 0, VCLKIndexGENCRT = 0;
-  unsigned short modeflag, resinfo, tempbx;
+  unsigned short resinfo, tempbx;
   const unsigned char *CHTVVCLKPtr = NULL;
 
   if(ModeNo <= 0x13) {
-     modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
      resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
      CRT2Index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
      VCLKIndexGEN = (SiS_GetRegByte((SiS_Pr->SiS_P3ca+0x02)) >> 2) & 0x03;
      VCLKIndexGENCRT = VCLKIndexGEN;
   } else {
-     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
      resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
      CRT2Index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
      VCLKIndexGEN = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
@@ -7270,7 +7268,7 @@ SiS_ShiftXPos(struct SiS_Private *SiS_Pr, int shift)
 static void
 SiS_SetGroup4_C_ELV(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex)
 {
-   unsigned short temp, temp1, resinfo = 0;
+   unsigned short temp, temp1;
    unsigned char  *ROMAddr = SiS_Pr->VirtualRomBase;
 
    if(!(SiS_Pr->SiS_VBType & VB_SIS30xCLV)) return;
@@ -7282,10 +7280,6 @@ SiS_SetGroup4_C_ELV(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned
       if(!(ROMAddr[0x61] & 0x04)) return;
    }
 
-   if(ModeNo > 0x13) {
-      resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
-   }
-
    SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x3a,0x08);
    temp = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x3a);
    if(!(temp & 0x01)) {
index 629bfa2..86ae1d4 100644 (file)
@@ -28,9 +28,7 @@
 #include <linux/console.h>
 #include <linux/screen_info.h>
 
-#ifdef CONFIG_PM
 #include <linux/pm.h>
-#endif
 
 #include "sm712.h"
 
@@ -1545,8 +1543,7 @@ static void smtcfb_pci_remove(struct pci_dev *pdev)
        pci_disable_device(pdev);
 }
 
-#ifdef CONFIG_PM
-static int smtcfb_pci_suspend(struct device *device)
+static int __maybe_unused smtcfb_pci_suspend(struct device *device)
 {
        struct pci_dev *pdev = to_pci_dev(device);
        struct smtcfb_info *sfb;
@@ -1569,7 +1566,7 @@ static int smtcfb_pci_suspend(struct device *device)
        return 0;
 }
 
-static int smtcfb_pci_resume(struct device *device)
+static int __maybe_unused smtcfb_pci_resume(struct device *device)
 {
        struct pci_dev *pdev = to_pci_dev(device);
        struct smtcfb_info *sfb;
@@ -1610,20 +1607,13 @@ static int smtcfb_pci_resume(struct device *device)
 }
 
 static SIMPLE_DEV_PM_OPS(sm7xx_pm_ops, smtcfb_pci_suspend, smtcfb_pci_resume);
-#define SM7XX_PM_OPS (&sm7xx_pm_ops)
-
-#else  /* !CONFIG_PM */
-
-#define SM7XX_PM_OPS NULL
-
-#endif /* !CONFIG_PM */
 
 static struct pci_driver smtcfb_driver = {
        .name = "smtcfb",
        .id_table = smtcfb_pci_table,
        .probe = smtcfb_pci_probe,
        .remove = smtcfb_pci_remove,
-       .driver.pm  = SM7XX_PM_OPS,
+       .driver.pm  = &sm7xx_pm_ops,
 };
 
 static int __init sm712fb_init(void)
index f9718f0..badee04 100644 (file)
@@ -1630,16 +1630,14 @@ static void viafb_init_proc(struct viafb_shared *shared)
 }
 static void viafb_remove_proc(struct viafb_shared *shared)
 {
-       struct proc_dir_entry *viafb_entry = shared->proc_entry,
-               *iga1_entry = shared->iga1_proc_entry,
-               *iga2_entry = shared->iga2_proc_entry;
+       struct proc_dir_entry *viafb_entry = shared->proc_entry;
 
        if (!viafb_entry)
                return;
 
-       remove_proc_entry("output_devices", iga2_entry);
+       remove_proc_entry("output_devices", shared->iga2_proc_entry);
        remove_proc_entry("iga2", viafb_entry);
-       remove_proc_entry("output_devices", iga1_entry);
+       remove_proc_entry("output_devices", shared->iga1_proc_entry);
        remove_proc_entry("iga1", viafb_entry);
        remove_proc_entry("supported_output_devices", viafb_entry);
 
index 84c6add..f978f25 100644 (file)
@@ -244,12 +244,14 @@ static void update_balloon_stats(struct virtio_balloon *vb)
        all_vm_events(events);
        si_meminfo(&i);
 
+#ifdef CONFIG_VM_EVENT_COUNTERS
        update_stat(vb, idx++, VIRTIO_BALLOON_S_SWAP_IN,
                                pages_to_bytes(events[PSWPIN]));
        update_stat(vb, idx++, VIRTIO_BALLOON_S_SWAP_OUT,
                                pages_to_bytes(events[PSWPOUT]));
        update_stat(vb, idx++, VIRTIO_BALLOON_S_MAJFLT, events[PGMAJFAULT]);
        update_stat(vb, idx++, VIRTIO_BALLOON_S_MINFLT, events[PGFAULT]);
+#endif
        update_stat(vb, idx++, VIRTIO_BALLOON_S_MEMFREE,
                                pages_to_bytes(i.freeram));
        update_stat(vb, idx++, VIRTIO_BALLOON_S_MEMTOT,
index 29ef719..d69ab1e 100644 (file)
@@ -161,15 +161,21 @@ static void imx2_wdt_timer_ping(unsigned long arg)
        mod_timer(&wdev->timer, jiffies + wdog->timeout * HZ / 2);
 }
 
-static int imx2_wdt_set_timeout(struct watchdog_device *wdog,
-                               unsigned int new_timeout)
+static void __imx2_wdt_set_timeout(struct watchdog_device *wdog,
+                                  unsigned int new_timeout)
 {
        struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
 
-       wdog->timeout = new_timeout;
-
        regmap_update_bits(wdev->regmap, IMX2_WDT_WCR, IMX2_WDT_WCR_WT,
                           WDOG_SEC_TO_COUNT(new_timeout));
+}
+
+static int imx2_wdt_set_timeout(struct watchdog_device *wdog,
+                               unsigned int new_timeout)
+{
+       __imx2_wdt_set_timeout(wdog, new_timeout);
+
+       wdog->timeout = new_timeout;
        return 0;
 }
 
@@ -353,7 +359,11 @@ static int imx2_wdt_suspend(struct device *dev)
 
        /* The watchdog IP block is running */
        if (imx2_wdt_is_running(wdev)) {
-               imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME);
+               /*
+                * Don't update wdog->timeout, we'll restore the current value
+                * during resume.
+                */
+               __imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME);
                imx2_wdt_ping(wdog);
 
                /* The watchdog is not active */
index 73708ac..3a14948 100644 (file)
@@ -239,7 +239,7 @@ config XEN_ACPI_HOTPLUG_CPU
 
 config XEN_ACPI_PROCESSOR
        tristate "Xen ACPI processor"
-       depends on XEN && X86 && ACPI_PROCESSOR && CPU_FREQ
+       depends on XEN && XEN_DOM0 && X86 && ACPI_PROCESSOR && CPU_FREQ
        default m
        help
           This ACPI processor uploads Power Management information to the Xen
index 8a0243e..b9065d6 100644 (file)
@@ -491,6 +491,7 @@ static inline int arch_elf_pt_proc(struct elfhdr *ehdr,
  * arch_check_elf() - check an ELF executable
  * @ehdr:      The main ELF header
  * @has_interp:        True if the ELF has an interpreter, else false.
+ * @interp_ehdr: The interpreter's ELF header
  * @state:     Architecture-specific state preserved throughout the process
  *             of loading the ELF.
  *
@@ -502,6 +503,7 @@ static inline int arch_elf_pt_proc(struct elfhdr *ehdr,
  *         with that return code.
  */
 static inline int arch_check_elf(struct elfhdr *ehdr, bool has_interp,
+                                struct elfhdr *interp_ehdr,
                                 struct arch_elf_state *state)
 {
        /* Dummy implementation, always proceed */
@@ -829,7 +831,9 @@ static int load_elf_binary(struct linux_binprm *bprm)
         * still possible to return an error to the code that invoked
         * the exec syscall.
         */
-       retval = arch_check_elf(&loc->elf_ex, !!interpreter, &arch_state);
+       retval = arch_check_elf(&loc->elf_ex,
+                               !!interpreter, &loc->interp_elf_ex,
+                               &arch_state);
        if (retval)
                goto out_free_dentry;
 
index af1da85..81b5a46 100644 (file)
@@ -1292,8 +1292,11 @@ next_slot:
                leaf = path->nodes[0];
                if (path->slots[0] >= btrfs_header_nritems(leaf)) {
                        ret = btrfs_next_leaf(root, path);
-                       if (ret < 0)
+                       if (ret < 0) {
+                               if (cow_start != (u64)-1)
+                                       cur_offset = cow_start;
                                goto error;
+                       }
                        if (ret > 0)
                                break;
                        leaf = path->nodes[0];
@@ -2015,7 +2018,15 @@ again:
                goto out;
         }
 
-       btrfs_set_extent_delalloc(inode, page_start, page_end, &cached_state);
+       ret = btrfs_set_extent_delalloc(inode, page_start, page_end,
+                                       &cached_state);
+       if (ret) {
+               mapping_set_error(page->mapping, ret);
+               end_extent_writepage(page, ret, page_start, page_end);
+               ClearPageChecked(page);
+               goto out;
+       }
+
        ClearPageChecked(page);
        set_page_dirty(page);
 out:
index 9c3b9d0..4e3c889 100644 (file)
@@ -2231,7 +2231,7 @@ static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info,
        if (!path)
                return -ENOMEM;
 
-       ptr = &name[BTRFS_INO_LOOKUP_PATH_MAX];
+       ptr = &name[BTRFS_INO_LOOKUP_PATH_MAX - 1];
 
        key.objectid = tree_id;
        key.type = BTRFS_ROOT_ITEM_KEY;
index ee7832e..d6359af 100644 (file)
@@ -26,6 +26,7 @@
 #include "print-tree.h"
 #include "backref.h"
 #include "hash.h"
+#include "inode-map.h"
 
 /* magic values for the inode_only field in btrfs_log_inode:
  *
@@ -2445,6 +2446,9 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
                                                        next);
                                        btrfs_wait_tree_block_writeback(next);
                                        btrfs_tree_unlock(next);
+                               } else {
+                                       if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &next->bflags))
+                                               clear_extent_buffer_dirty(next);
                                }
 
                                WARN_ON(root_owner !=
@@ -2524,6 +2528,9 @@ static noinline int walk_up_log_tree(struct btrfs_trans_handle *trans,
                                                        next);
                                        btrfs_wait_tree_block_writeback(next);
                                        btrfs_tree_unlock(next);
+                               } else {
+                                       if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &next->bflags))
+                                               clear_extent_buffer_dirty(next);
                                }
 
                                WARN_ON(root_owner != BTRFS_TREE_LOG_OBJECTID);
@@ -2600,6 +2607,9 @@ static int walk_log_tree(struct btrfs_trans_handle *trans,
                                clean_tree_block(trans, log->fs_info, next);
                                btrfs_wait_tree_block_writeback(next);
                                btrfs_tree_unlock(next);
+                       } else {
+                               if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &next->bflags))
+                                       clear_extent_buffer_dirty(next);
                        }
 
                        WARN_ON(log->root_key.objectid !=
@@ -5514,6 +5524,23 @@ again:
                                                      path);
                }
 
+               if (!ret && wc.stage == LOG_WALK_REPLAY_ALL) {
+                       struct btrfs_root *root = wc.replay_dest;
+
+                       btrfs_release_path(path);
+
+                       /*
+                        * We have just replayed everything, and the highest
+                        * objectid of fs roots probably has changed in case
+                        * some inode_item's got replayed.
+                        *
+                        * root->objectid_mutex is not acquired as log replay
+                        * could only happen during mount.
+                        */
+                       ret = btrfs_find_highest_objectid(root,
+                                                 &root->highest_objectid);
+               }
+
                key.offset = found_key.offset - 1;
                wc.replay_dest->log_root = NULL;
                free_extent_buffer(log->node);
index 4acbc39..1d707a6 100644 (file)
@@ -306,9 +306,8 @@ int calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt,
 {
        int i;
        int rc;
-       char password_with_pad[CIFS_ENCPWD_SIZE];
+       char password_with_pad[CIFS_ENCPWD_SIZE] = {0};
 
-       memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
        if (password)
                strncpy(password_with_pad, password, CIFS_ENCPWD_SIZE);
 
index 0a2bf94..077ad3a 100644 (file)
@@ -1695,7 +1695,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                        tmp_end++;
                        if (!(tmp_end < end && tmp_end[1] == delim)) {
                                /* No it is not. Set the password to NULL */
-                               kfree(vol->password);
+                               kzfree(vol->password);
                                vol->password = NULL;
                                break;
                        }
@@ -1733,7 +1733,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                                        options = end;
                        }
 
-                       kfree(vol->password);
+                       kzfree(vol->password);
                        /* Now build new password string */
                        temp_len = strlen(value);
                        vol->password = kzalloc(temp_len+1, GFP_KERNEL);
@@ -4148,7 +4148,7 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid)
                reset_cifs_unix_caps(0, tcon, NULL, vol_info);
 out:
        kfree(vol_info->username);
-       kfree(vol_info->password);
+       kzfree(vol_info->password);
        kfree(vol_info);
 
        return tcon;
index ec2d07b..744be3c 100644 (file)
@@ -3241,20 +3241,18 @@ static const struct vm_operations_struct cifs_file_vm_ops = {
 
 int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma)
 {
-       int rc, xid;
+       int xid, rc = 0;
        struct inode *inode = file_inode(file);
 
        xid = get_xid();
 
-       if (!CIFS_CACHE_READ(CIFS_I(inode))) {
+       if (!CIFS_CACHE_READ(CIFS_I(inode)))
                rc = cifs_zap_mapping(inode);
-               if (rc)
-                       return rc;
-       }
-
-       rc = generic_file_mmap(file, vma);
-       if (rc == 0)
+       if (!rc)
+               rc = generic_file_mmap(file, vma);
+       if (!rc)
                vma->vm_ops = &cifs_file_vm_ops;
+
        free_xid(xid);
        return rc;
 }
@@ -3264,16 +3262,16 @@ int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
        int rc, xid;
 
        xid = get_xid();
+
        rc = cifs_revalidate_file(file);
-       if (rc) {
+       if (rc)
                cifs_dbg(FYI, "Validation prior to mmap failed, error=%d\n",
                         rc);
-               free_xid(xid);
-               return rc;
-       }
-       rc = generic_file_mmap(file, vma);
-       if (rc == 0)
+       if (!rc)
+               rc = generic_file_mmap(file, vma);
+       if (!rc)
                vma->vm_ops = &cifs_file_vm_ops;
+
        free_xid(xid);
        return rc;
 }
index 2396ab0..0cc699d 100644 (file)
@@ -99,14 +99,11 @@ sesInfoFree(struct cifs_ses *buf_to_free)
        kfree(buf_to_free->serverOS);
        kfree(buf_to_free->serverDomain);
        kfree(buf_to_free->serverNOS);
-       if (buf_to_free->password) {
-               memset(buf_to_free->password, 0, strlen(buf_to_free->password));
-               kfree(buf_to_free->password);
-       }
+       kzfree(buf_to_free->password);
        kfree(buf_to_free->user_name);
        kfree(buf_to_free->domainName);
-       kfree(buf_to_free->auth_key.response);
-       kfree(buf_to_free);
+       kzfree(buf_to_free->auth_key.response);
+       kzfree(buf_to_free);
 }
 
 struct cifs_tcon *
@@ -137,10 +134,7 @@ tconInfoFree(struct cifs_tcon *buf_to_free)
        }
        atomic_dec(&tconInfoAllocCount);
        kfree(buf_to_free->nativeFileSystem);
-       if (buf_to_free->password) {
-               memset(buf_to_free->password, 0, strlen(buf_to_free->password));
-               kfree(buf_to_free->password);
-       }
+       kzfree(buf_to_free->password);
        kfree(buf_to_free);
 }
 
index f2ff60e..84614a5 100644 (file)
@@ -580,8 +580,7 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
        }
 
        /* check validate negotiate info response matches what we got earlier */
-       if (pneg_rsp->Dialect !=
-                       cpu_to_le16(tcon->ses->server->vals->protocol_id))
+       if (pneg_rsp->Dialect != cpu_to_le16(tcon->ses->server->dialect))
                goto vneg_out;
 
        if (pneg_rsp->SecurityMode != cpu_to_le16(tcon->ses->server->sec_mode))
index 4d24d17..943be5e 100644 (file)
@@ -51,6 +51,7 @@
 #define elf_prstatus   compat_elf_prstatus
 #define elf_prpsinfo   compat_elf_prpsinfo
 
+#ifdef CONFIG_ELF_CORE
 /*
  * Compat version of cputime_to_compat_timeval, perhaps this
  * should be an inline in <linux/compat.h>.
@@ -63,6 +64,7 @@ static void cputime_to_compat_timeval(const cputime_t cputime,
        value->tv_sec = tv.tv_sec;
        value->tv_usec = tv.tv_usec;
 }
+#endif
 
 #undef cputime_to_timeval
 #define cputime_to_timeval cputime_to_compat_timeval
index 2e57ac8..7870144 100644 (file)
@@ -4503,6 +4503,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
                        inode->i_op = &ext4_symlink_inode_operations;
                        ext4_set_aops(inode);
                }
+               inode_nohighmem(inode);
        } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
              S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
                inode->i_op = &ext4_special_inode_operations;
index e0c5c9b..b9324d0 100644 (file)
@@ -3148,6 +3148,7 @@ static int ext4_symlink(struct inode *dir,
        if ((disk_link.len > EXT4_N_BLOCKS * 4)) {
                if (!encryption_required)
                        inode->i_op = &ext4_symlink_inode_operations;
+               inode_nohighmem(inode);
                ext4_set_aops(inode);
                /*
                 * We cannot call page_symlink() with transaction started
index d3cbdbc..bc79e2c 100644 (file)
@@ -688,6 +688,7 @@ __acquires(bitlock)
        }
 
        ext4_unlock_group(sb, grp);
+       ext4_commit_super(sb, 1);
        ext4_handle_error(sb);
        /*
         * We only get here in the ERRORS_RO case; relocking the group
index e8e7af6..287c398 100644 (file)
@@ -45,7 +45,7 @@ static const char *ext4_encrypted_follow_link(struct dentry *dentry, void **cook
                cpage = read_mapping_page(inode->i_mapping, 0, NULL);
                if (IS_ERR(cpage))
                        return ERR_CAST(cpage);
-               caddr = kmap(cpage);
+               caddr = page_address(cpage);
                caddr[size] = 0;
        }
 
@@ -75,16 +75,12 @@ static const char *ext4_encrypted_follow_link(struct dentry *dentry, void **cook
        /* Null-terminate the name */
        if (res <= plen)
                paddr[res] = '\0';
-       if (cpage) {
-               kunmap(cpage);
+       if (cpage)
                page_cache_release(cpage);
-       }
        return *cookie = paddr;
 errout:
-       if (cpage) {
-               kunmap(cpage);
+       if (cpage)
                page_cache_release(cpage);
-       }
        kfree(paddr);
        return ERR_PTR(res);
 }
index 2eb7781..3c343e9 100644 (file)
@@ -238,12 +238,15 @@ static int __f2fs_write_meta_page(struct page *page,
 
        trace_f2fs_writepage(page, META);
 
+       if (unlikely(f2fs_cp_error(sbi))) {
+               dec_page_count(sbi, F2FS_DIRTY_META);
+               unlock_page(page);
+               return 0;
+       }
        if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
                goto redirty_out;
        if (wbc->for_reclaim && page->index < GET_SUM_BLOCK(sbi, 0))
                goto redirty_out;
-       if (unlikely(f2fs_cp_error(sbi)))
-               goto redirty_out;
 
        write_meta_page(sbi, page, io_type);
        dec_page_count(sbi, F2FS_DIRTY_META);
@@ -797,7 +800,7 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi)
        block_t cp_blk_no;
        int i;
 
-       sbi->ckpt = kzalloc(cp_blks * blk_size, GFP_KERNEL);
+       sbi->ckpt = f2fs_kzalloc(sbi, cp_blks * blk_size, GFP_KERNEL);
        if (!sbi->ckpt)
                return -ENOMEM;
        /*
@@ -1158,6 +1161,7 @@ static void update_ckpt_flags(struct f2fs_sb_info *sbi, struct cp_control *cpc)
 
        /* set this flag to activate crc|cp_ver for recovery */
        __set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG);
+       __clear_ckpt_flags(ckpt, CP_NOCRC_RECOVERY_FLAG);
 
        spin_unlock_irqrestore(&sbi->cp_lock, flags);
 }
index cdccc42..d529926 100644 (file)
@@ -111,8 +111,13 @@ static void f2fs_write_end_io(struct bio *bio)
 
                if (unlikely(bio->bi_error)) {
                        set_bit(AS_EIO, &page->mapping->flags);
-                       f2fs_stop_checkpoint(sbi, true);
+                       if (type == F2FS_WB_CP_DATA)
+                               f2fs_stop_checkpoint(sbi, true);
                }
+
+               f2fs_bug_on(sbi, page->mapping == NODE_MAPPING(sbi) &&
+                                       page->index != nid_of_node(page));
+
                dec_page_count(sbi, type);
                clear_cold_data(page);
                end_page_writeback(page);
@@ -168,6 +173,7 @@ static bool __same_bdev(struct f2fs_sb_info *sbi,
  * Low-level block read/write IO operations.
  */
 static struct bio *__bio_alloc(struct f2fs_sb_info *sbi, block_t blk_addr,
+                               struct writeback_control *wbc,
                                int npages, bool is_read)
 {
        struct bio *bio;
@@ -177,6 +183,8 @@ static struct bio *__bio_alloc(struct f2fs_sb_info *sbi, block_t blk_addr,
        f2fs_target_device(sbi, blk_addr, bio);
        bio->bi_end_io = is_read ? f2fs_read_end_io : f2fs_write_end_io;
        bio->bi_private = is_read ? NULL : sbi;
+       if (wbc)
+               wbc_init_bio(wbc, bio);
 
        return bio;
 }
@@ -372,7 +380,8 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
        f2fs_trace_ios(fio, 0);
 
        /* Allocate a new bio */
-       bio = __bio_alloc(fio->sbi, fio->new_blkaddr, 1, is_read_io(fio->op));
+       bio = __bio_alloc(fio->sbi, fio->new_blkaddr, fio->io_wbc,
+                               1, is_read_io(fio->op));
 
        if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
                bio_put(bio);
@@ -434,7 +443,7 @@ alloc_new:
                        dec_page_count(sbi, WB_DATA_TYPE(bio_page));
                        goto out_fail;
                }
-               io->bio = __bio_alloc(sbi, fio->new_blkaddr,
+               io->bio = __bio_alloc(sbi, fio->new_blkaddr, fio->io_wbc,
                                                BIO_MAX_PAGES, false);
                io->fio = *fio;
        }
@@ -444,6 +453,9 @@ alloc_new:
                goto alloc_new;
        }
 
+       if (fio->io_wbc)
+               wbc_account_io(fio->io_wbc, bio_page, PAGE_SIZE);
+
        io->last_block_in_bio = fio->new_blkaddr;
        f2fs_trace_ios(fio, 0);
 
@@ -782,7 +794,7 @@ got_it:
        return page;
 }
 
-static int __allocate_data_block(struct dnode_of_data *dn)
+static int __allocate_data_block(struct dnode_of_data *dn, int seg_type)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
        struct f2fs_summary sum;
@@ -807,7 +819,7 @@ alloc:
        set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version);
 
        allocate_data_block(sbi, NULL, dn->data_blkaddr, &dn->data_blkaddr,
-                                       &sum, CURSEG_WARM_DATA, NULL, false);
+                                       &sum, seg_type, NULL, false);
        set_data_blkaddr(dn);
 
        /* update i_size */
@@ -830,10 +842,12 @@ int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from)
 {
        struct inode *inode = file_inode(iocb->ki_filp);
        struct f2fs_map_blocks map;
+       int flag;
        int err = 0;
+       bool direct_io = iocb->ki_flags & IOCB_DIRECT;
 
        /* convert inline data for Direct I/O*/
-       if (iocb->ki_flags & IOCB_DIRECT) {
+       if (direct_io) {
                err = f2fs_convert_inline_inode(inode);
                if (err)
                        return err;
@@ -850,19 +864,34 @@ int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from)
                map.m_len = 0;
 
        map.m_next_pgofs = NULL;
+       map.m_next_extent = NULL;
+       map.m_seg_type = NO_CHECK_TYPE;
 
-       if (iocb->ki_flags & IOCB_DIRECT)
-               return f2fs_map_blocks(inode, &map, 1,
-                       __force_buffered_io(inode, WRITE) ?
-                               F2FS_GET_BLOCK_PRE_AIO :
-                               F2FS_GET_BLOCK_PRE_DIO);
+       if (direct_io) {
+               /* map.m_seg_type = rw_hint_to_seg_type(iocb->ki_hint); */
+               map.m_seg_type = rw_hint_to_seg_type(WRITE_LIFE_NOT_SET);
+               flag = __force_buffered_io(inode, WRITE) ?
+                                       F2FS_GET_BLOCK_PRE_AIO :
+                                       F2FS_GET_BLOCK_PRE_DIO;
+               goto map_blocks;
+       }
        if (iocb->ki_pos + iov_iter_count(from) > MAX_INLINE_DATA(inode)) {
                err = f2fs_convert_inline_inode(inode);
                if (err)
                        return err;
        }
-       if (!f2fs_has_inline_data(inode))
-               return f2fs_map_blocks(inode, &map, 1, F2FS_GET_BLOCK_PRE_AIO);
+       if (f2fs_has_inline_data(inode))
+               return err;
+
+       flag = F2FS_GET_BLOCK_PRE_AIO;
+
+map_blocks:
+       err = f2fs_map_blocks(inode, &map, 1, flag);
+       if (map.m_len > 0 && err == -ENOSPC) {
+               if (!direct_io)
+                       set_inode_flag(inode, FI_NO_PREALLOC);
+               err = 0;
+       }
        return err;
 }
 
@@ -903,6 +932,7 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
        blkcnt_t prealloc;
        struct extent_info ei = {0,0,0};
        block_t blkaddr;
+       unsigned int start_pgofs;
 
        if (!maxblocks)
                return 0;
@@ -918,6 +948,8 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
                map->m_pblk = ei.blk + pgofs - ei.fofs;
                map->m_len = min((pgoff_t)maxblocks, ei.fofs + ei.len - pgofs);
                map->m_flags = F2FS_MAP_MAPPED;
+               if (map->m_next_extent)
+                       *map->m_next_extent = pgofs + map->m_len;
                goto out;
        }
 
@@ -936,10 +968,14 @@ next_dnode:
                        if (map->m_next_pgofs)
                                *map->m_next_pgofs =
                                        get_next_page_offset(&dn, pgofs);
+                       if (map->m_next_extent)
+                               *map->m_next_extent =
+                                       get_next_page_offset(&dn, pgofs);
                }
                goto unlock_out;
        }
 
+       start_pgofs = pgofs;
        prealloc = 0;
        last_ofs_in_node = ofs_in_node = dn.ofs_in_node;
        end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
@@ -959,7 +995,8 @@ next_block:
                                        last_ofs_in_node = dn.ofs_in_node;
                                }
                        } else {
-                               err = __allocate_data_block(&dn);
+                               err = __allocate_data_block(&dn,
+                                                       map->m_seg_type);
                                if (!err)
                                        set_inode_flag(inode, FI_APPEND_WRITE);
                        }
@@ -972,14 +1009,20 @@ next_block:
                                map->m_pblk = 0;
                                goto sync_out;
                        }
+                       if (flag == F2FS_GET_BLOCK_PRECACHE)
+                               goto sync_out;
                        if (flag == F2FS_GET_BLOCK_FIEMAP &&
                                                blkaddr == NULL_ADDR) {
                                if (map->m_next_pgofs)
                                        *map->m_next_pgofs = pgofs + 1;
+                               goto sync_out;
                        }
-                       if (flag != F2FS_GET_BLOCK_FIEMAP ||
-                                               blkaddr != NEW_ADDR)
+                       if (flag != F2FS_GET_BLOCK_FIEMAP) {
+                               /* for defragment case */
+                               if (map->m_next_pgofs)
+                                       *map->m_next_pgofs = pgofs + 1;
                                goto sync_out;
+                       }
                }
        }
 
@@ -1030,6 +1073,16 @@ skip:
        else if (dn.ofs_in_node < end_offset)
                goto next_block;
 
+       if (flag == F2FS_GET_BLOCK_PRECACHE) {
+               if (map->m_flags & F2FS_MAP_MAPPED) {
+                       unsigned int ofs = start_pgofs - map->m_lblk;
+
+                       f2fs_update_extent_cache_range(&dn,
+                               start_pgofs, map->m_pblk + ofs,
+                               map->m_len - ofs);
+               }
+       }
+
        f2fs_put_dnode(&dn);
 
        if (create) {
@@ -1039,6 +1092,17 @@ skip:
        goto next_dnode;
 
 sync_out:
+       if (flag == F2FS_GET_BLOCK_PRECACHE) {
+               if (map->m_flags & F2FS_MAP_MAPPED) {
+                       unsigned int ofs = start_pgofs - map->m_lblk;
+
+                       f2fs_update_extent_cache_range(&dn,
+                               start_pgofs, map->m_pblk + ofs,
+                               map->m_len - ofs);
+               }
+               if (map->m_next_extent)
+                       *map->m_next_extent = pgofs + 1;
+       }
        f2fs_put_dnode(&dn);
 unlock_out:
        if (create) {
@@ -1052,7 +1116,7 @@ out:
 
 static int __get_data_block(struct inode *inode, sector_t iblock,
                        struct buffer_head *bh, int create, int flag,
-                       pgoff_t *next_pgofs)
+                       pgoff_t *next_pgofs, int seg_type)
 {
        struct f2fs_map_blocks map;
        int err;
@@ -1060,6 +1124,8 @@ static int __get_data_block(struct inode *inode, sector_t iblock,
        map.m_lblk = iblock;
        map.m_len = bh->b_size >> inode->i_blkbits;
        map.m_next_pgofs = next_pgofs;
+       map.m_next_extent = NULL;
+       map.m_seg_type = seg_type;
 
        err = f2fs_map_blocks(inode, &map, create, flag);
        if (!err) {
@@ -1075,14 +1141,18 @@ static int get_data_block(struct inode *inode, sector_t iblock,
                        pgoff_t *next_pgofs)
 {
        return __get_data_block(inode, iblock, bh_result, create,
-                                                       flag, next_pgofs);
+                                                       flag, next_pgofs,
+                                                       NO_CHECK_TYPE);
 }
 
 static int get_data_block_dio(struct inode *inode, sector_t iblock,
                        struct buffer_head *bh_result, int create)
 {
        return __get_data_block(inode, iblock, bh_result, create,
-                                               F2FS_GET_BLOCK_DEFAULT, NULL);
+                                               F2FS_GET_BLOCK_DEFAULT, NULL,
+                                               rw_hint_to_seg_type(
+                                                       WRITE_LIFE_NOT_SET));
+                                               /* inode->i_write_hint)); */
 }
 
 static int get_data_block_bmap(struct inode *inode, sector_t iblock,
@@ -1093,7 +1163,8 @@ static int get_data_block_bmap(struct inode *inode, sector_t iblock,
                return -EFBIG;
 
        return __get_data_block(inode, iblock, bh_result, create,
-                                               F2FS_GET_BLOCK_BMAP, NULL);
+                                               F2FS_GET_BLOCK_BMAP, NULL,
+                                               NO_CHECK_TYPE);
 }
 
 static inline sector_t logical_to_blk(struct inode *inode, loff_t offset)
@@ -1106,6 +1177,68 @@ static inline loff_t blk_to_logical(struct inode *inode, sector_t blk)
        return (blk << inode->i_blkbits);
 }
 
+static int f2fs_xattr_fiemap(struct inode *inode,
+                               struct fiemap_extent_info *fieinfo)
+{
+       struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+       struct page *page;
+       struct node_info ni;
+       __u64 phys = 0, len;
+       __u32 flags;
+       nid_t xnid = F2FS_I(inode)->i_xattr_nid;
+       int err = 0;
+
+       if (f2fs_has_inline_xattr(inode)) {
+               int offset;
+
+               page = f2fs_grab_cache_page(NODE_MAPPING(sbi),
+                                               inode->i_ino, false);
+               if (!page)
+                       return -ENOMEM;
+
+               get_node_info(sbi, inode->i_ino, &ni);
+
+               phys = (__u64)blk_to_logical(inode, ni.blk_addr);
+               offset = offsetof(struct f2fs_inode, i_addr) +
+                                       sizeof(__le32) * (DEF_ADDRS_PER_INODE -
+                                       get_inline_xattr_addrs(inode));
+
+               phys += offset;
+               len = inline_xattr_size(inode);
+
+               f2fs_put_page(page, 1);
+
+               flags = FIEMAP_EXTENT_DATA_INLINE | FIEMAP_EXTENT_NOT_ALIGNED;
+
+               if (!xnid)
+                       flags |= FIEMAP_EXTENT_LAST;
+
+               err = fiemap_fill_next_extent(fieinfo, 0, phys, len, flags);
+               if (err || err == 1)
+                       return err;
+       }
+
+       if (xnid) {
+               page = f2fs_grab_cache_page(NODE_MAPPING(sbi), xnid, false);
+               if (!page)
+                       return -ENOMEM;
+
+               get_node_info(sbi, xnid, &ni);
+
+               phys = (__u64)blk_to_logical(inode, ni.blk_addr);
+               len = inode->i_sb->s_blocksize;
+
+               f2fs_put_page(page, 1);
+
+               flags = FIEMAP_EXTENT_LAST;
+       }
+
+       if (phys)
+               err = fiemap_fill_next_extent(fieinfo, 0, phys, len, flags);
+
+       return (err < 0 ? err : 0);
+}
+
 int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                u64 start, u64 len)
 {
@@ -1116,18 +1249,29 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
        u32 flags = 0;
        int ret = 0;
 
-       ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC);
+       if (fieinfo->fi_flags & FIEMAP_FLAG_CACHE) {
+               ret = f2fs_precache_extents(inode);
+               if (ret)
+                       return ret;
+       }
+
+       ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC | FIEMAP_FLAG_XATTR);
        if (ret)
                return ret;
 
+       inode_lock(inode);
+
+       if (fieinfo->fi_flags & FIEMAP_FLAG_XATTR) {
+               ret = f2fs_xattr_fiemap(inode, fieinfo);
+               goto out;
+       }
+
        if (f2fs_has_inline_data(inode)) {
                ret = f2fs_inline_data_fiemap(inode, fieinfo, start, len);
                if (ret != -EAGAIN)
-                       return ret;
+                       goto out;
        }
 
-       inode_lock(inode);
-
        if (logical_to_blk(inode, len) == 0)
                len = blk_to_logical(inode, 1);
 
@@ -1197,7 +1341,6 @@ static int f2fs_mpage_readpages(struct address_space *mapping,
                        unsigned nr_pages)
 {
        struct bio *bio = NULL;
-       unsigned page_idx;
        sector_t last_block_in_bio = 0;
        struct inode *inode = mapping->host;
        const unsigned blkbits = inode->i_blkbits;
@@ -1213,9 +1356,10 @@ static int f2fs_mpage_readpages(struct address_space *mapping,
        map.m_len = 0;
        map.m_flags = 0;
        map.m_next_pgofs = NULL;
+       map.m_next_extent = NULL;
+       map.m_seg_type = NO_CHECK_TYPE;
 
-       for (page_idx = 0; nr_pages; page_idx++, nr_pages--) {
-
+       for (; nr_pages; nr_pages--) {
                if (pages) {
                        page = list_last_entry(pages, struct page, lru);
 
@@ -1374,18 +1518,79 @@ retry_encrypt:
        return PTR_ERR(fio->encrypted_page);
 }
 
+static inline bool check_inplace_update_policy(struct inode *inode,
+                               struct f2fs_io_info *fio)
+{
+       struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+       unsigned int policy = SM_I(sbi)->ipu_policy;
+
+       if (policy & (0x1 << F2FS_IPU_FORCE))
+               return true;
+       if (policy & (0x1 << F2FS_IPU_SSR) && need_SSR(sbi))
+               return true;
+       if (policy & (0x1 << F2FS_IPU_UTIL) &&
+                       utilization(sbi) > SM_I(sbi)->min_ipu_util)
+               return true;
+       if (policy & (0x1 << F2FS_IPU_SSR_UTIL) && need_SSR(sbi) &&
+                       utilization(sbi) > SM_I(sbi)->min_ipu_util)
+               return true;
+
+       /*
+        * IPU for rewrite async pages
+        */
+       if (policy & (0x1 << F2FS_IPU_ASYNC) &&
+                       fio && fio->op == REQ_OP_WRITE &&
+                       !(fio->op_flags & REQ_SYNC) &&
+                       !f2fs_encrypted_inode(inode))
+               return true;
+
+       /* this is only set during fdatasync */
+       if (policy & (0x1 << F2FS_IPU_FSYNC) &&
+                       is_inode_flag_set(inode, FI_NEED_IPU))
+               return true;
+
+       return false;
+}
+
+bool should_update_inplace(struct inode *inode, struct f2fs_io_info *fio)
+{
+       if (f2fs_is_pinned_file(inode))
+               return true;
+
+       /* if this is cold file, we should overwrite to avoid fragmentation */
+       if (file_is_cold(inode))
+               return true;
+
+       return check_inplace_update_policy(inode, fio);
+}
+
+bool should_update_outplace(struct inode *inode, struct f2fs_io_info *fio)
+{
+       struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+
+       if (test_opt(sbi, LFS))
+               return true;
+       if (S_ISDIR(inode->i_mode))
+               return true;
+       if (f2fs_is_atomic_file(inode))
+               return true;
+       if (fio) {
+               if (is_cold_data(fio->page))
+                       return true;
+               if (IS_ATOMIC_WRITTEN_PAGE(fio->page))
+                       return true;
+       }
+       return false;
+}
+
 static inline bool need_inplace_update(struct f2fs_io_info *fio)
 {
        struct inode *inode = fio->page->mapping->host;
 
-       if (S_ISDIR(inode->i_mode) || f2fs_is_atomic_file(inode))
-               return false;
-       if (is_cold_data(fio->page))
-               return false;
-       if (IS_ATOMIC_WRITTEN_PAGE(fio->page))
+       if (should_update_outplace(inode, fio))
                return false;
 
-       return need_inplace_update_policy(inode, fio);
+       return should_update_inplace(inode, fio);
 }
 
 static inline bool valid_ipu_blkaddr(struct f2fs_io_info *fio)
@@ -1506,10 +1711,17 @@ static int __write_data_page(struct page *page, bool *submitted,
                .submitted = false,
                .need_lock = LOCK_RETRY,
                .io_type = io_type,
+               .io_wbc = wbc,
        };
 
        trace_f2fs_writepage(page, DATA);
 
+       /* we should bypass data pages to proceed the kworkder jobs */
+       if (unlikely(f2fs_cp_error(sbi))) {
+               mapping_set_error(page->mapping, -EIO);
+               goto out;
+       }
+
        if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
                goto redirty_out;
 
@@ -1534,12 +1746,6 @@ write:
                        available_free_memory(sbi, BASE_CHECK))))
                goto redirty_out;
 
-       /* we should bypass data pages to proceed the kworkder jobs */
-       if (unlikely(f2fs_cp_error(sbi))) {
-               mapping_set_error(page->mapping, -EIO);
-               goto out;
-       }
-
        /* Dentry blocks are controlled by checkpoint */
        if (S_ISDIR(inode->i_mode)) {
                fio.need_lock = LOCK_DONE;
@@ -1569,10 +1775,14 @@ write:
                }
        }
 
-       down_write(&F2FS_I(inode)->i_sem);
-       if (F2FS_I(inode)->last_disk_size < psize)
-               F2FS_I(inode)->last_disk_size = psize;
-       up_write(&F2FS_I(inode)->i_sem);
+       if (err) {
+               file_set_keep_isize(inode);
+       } else {
+               down_write(&F2FS_I(inode)->i_sem);
+               if (F2FS_I(inode)->last_disk_size < psize)
+                       F2FS_I(inode)->last_disk_size = psize;
+               up_write(&F2FS_I(inode)->i_sem);
+       }
 
 done:
        if (err && err != -ENOENT)
@@ -1936,7 +2146,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
        struct page *page = NULL;
        pgoff_t index = ((unsigned long long) pos) >> PAGE_SHIFT;
-       bool need_balance = false;
+       bool need_balance = false, drop_atomic = false;
        block_t blkaddr = NULL_ADDR;
        int err = 0;
 
@@ -1955,6 +2165,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
        if (f2fs_is_atomic_file(inode) &&
                        !available_free_memory(sbi, INMEM_PAGES)) {
                err = -ENOMEM;
+               drop_atomic = true;
                goto fail;
        }
 
@@ -2035,7 +2246,7 @@ repeat:
 fail:
        f2fs_put_page(page, 1);
        f2fs_write_failed(mapping, pos + len);
-       if (f2fs_is_atomic_file(inode))
+       if (drop_atomic)
                drop_inmem_pages_all(sbi);
        return err;
 }
index ecada84..a66107b 100644 (file)
@@ -49,14 +49,7 @@ static void update_general_status(struct f2fs_sb_info *sbi)
        si->ndirty_imeta = get_pages(sbi, F2FS_DIRTY_IMETA);
        si->ndirty_dirs = sbi->ndirty_inode[DIR_INODE];
        si->ndirty_files = sbi->ndirty_inode[FILE_INODE];
-
-       si->nquota_files = 0;
-       if (f2fs_sb_has_quota_ino(sbi->sb)) {
-               for (i = 0; i < MAXQUOTAS; i++) {
-                       if (f2fs_qf_ino(sbi->sb, i))
-                               si->nquota_files++;
-               }
-       }
+       si->nquota_files = sbi->nquota_files;
        si->ndirty_all = sbi->ndirty_inode[DIRTY_META];
        si->inmem_pages = get_pages(sbi, F2FS_INMEM_PAGES);
        si->aw_cnt = atomic_read(&sbi->aw_cnt);
@@ -186,7 +179,6 @@ static void update_mem_info(struct f2fs_sb_info *sbi)
        si->base_mem += sizeof(struct f2fs_sb_info) + sbi->sb->s_blocksize;
        si->base_mem += 2 * sizeof(struct f2fs_inode_info);
        si->base_mem += sizeof(*sbi->ckpt);
-       si->base_mem += sizeof(struct percpu_counter) * NR_COUNT_TYPE;
 
        /* build sm */
        si->base_mem += sizeof(struct f2fs_sm_info);
@@ -447,7 +439,7 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi)
        struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
        struct f2fs_stat_info *si;
 
-       si = kzalloc(sizeof(struct f2fs_stat_info), GFP_KERNEL);
+       si = f2fs_kzalloc(sbi, sizeof(struct f2fs_stat_info), GFP_KERNEL);
        if (!si)
                return -ENOMEM;
 
index 1955707..bde445e 100644 (file)
@@ -713,6 +713,8 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
 
        f2fs_update_time(F2FS_I_SB(dir), REQ_TIME);
 
+       add_ino_entry(F2FS_I_SB(dir), dir->i_ino, TRANS_DIR_INO);
+
        if (f2fs_has_inline_dentry(dir))
                return f2fs_delete_inline_entry(dentry, page, dir, inode);
 
@@ -798,6 +800,7 @@ int f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,
        unsigned int bit_pos;
        struct f2fs_dir_entry *de = NULL;
        struct fscrypt_str de_name = FSTR_INIT(NULL, 0);
+       struct f2fs_sb_info *sbi = F2FS_I_SB(d->inode);
 
        bit_pos = ((unsigned long)ctx->pos % d->max);
 
@@ -836,6 +839,9 @@ int f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,
                                        le32_to_cpu(de->ino), d_type))
                        return 1;
 
+               if (sbi->readdir_ra == 1)
+                       ra_node_page(sbi, le32_to_cpu(de->ino));
+
                bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
                ctx->pos = start_pos + bit_pos;
        }
index 983f4a7..d2a6b68 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/magic.h>
 #include <linux/kobject.h>
 #include <linux/sched.h>
+#include <linux/cred.h>
 #include <linux/vmalloc.h>
 #include <linux/bio.h>
 #include <linux/blkdev.h>
@@ -44,6 +45,7 @@
 #ifdef CONFIG_F2FS_FAULT_INJECTION
 enum {
        FAULT_KMALLOC,
+       FAULT_KVMALLOC,
        FAULT_PAGE_ALLOC,
        FAULT_PAGE_GET,
        FAULT_ALLOC_BIO,
@@ -95,6 +97,7 @@ extern char *fault_name[FAULT_MAX];
 #define F2FS_MOUNT_PRJQUOTA            0x00200000
 #define F2FS_MOUNT_QUOTA               0x00400000
 #define F2FS_MOUNT_INLINE_XATTR_SIZE   0x00800000
+#define F2FS_MOUNT_RESERVE_ROOT                0x01000000
 
 #define clear_opt(sbi, option) ((sbi)->mount_opt.opt &= ~F2FS_MOUNT_##option)
 #define set_opt(sbi, option)   ((sbi)->mount_opt.opt |= F2FS_MOUNT_##option)
@@ -122,6 +125,7 @@ struct f2fs_mount_info {
 #define F2FS_FEATURE_INODE_CHKSUM      0x0020
 #define F2FS_FEATURE_FLEXIBLE_INLINE_XATTR     0x0040
 #define F2FS_FEATURE_QUOTA_INO         0x0080
+#define F2FS_FEATURE_INODE_CRTIME      0x0100
 
 #define F2FS_HAS_FEATURE(sb, mask)                                     \
        ((F2FS_SB(sb)->raw_super->feature & cpu_to_le32(mask)) != 0)
@@ -169,11 +173,6 @@ static inline bool wq_has_sleeper(wait_queue_head_t *wq)
        return waitqueue_active(wq);
 }
 
-static inline void inode_nohighmem(struct inode *inode)
-{
-       mapping_set_gfp_mask(inode->i_mapping, GFP_USER);
-}
-
 /**
  * current_time - Return FS time
  * @inode: inode.
@@ -197,6 +196,12 @@ static inline struct timespec current_time(struct inode *inode)
 }
 
 /*
+ * Default values for user and/or group using reserved blocks
+ */
+#define        F2FS_DEF_RESUID         0
+#define        F2FS_DEF_RESGID         0
+
+/*
  * For checkpoint manager
  */
 enum {
@@ -246,6 +251,7 @@ enum {
        ORPHAN_INO,             /* for orphan ino list */
        APPEND_INO,             /* for append ino list */
        UPDATE_INO,             /* for update ino list */
+       TRANS_DIR_INO,          /* for trasactions dir ino list */
        FLUSH_INO,              /* for multiple device flushing */
        MAX_INO_ENTRY,          /* max. list */
 };
@@ -331,7 +337,6 @@ struct discard_cmd_control {
        struct task_struct *f2fs_issue_discard; /* discard thread */
        struct list_head entry_list;            /* 4KB discard entry list */
        struct list_head pend_list[MAX_PLIST_NUM];/* store pending entries */
-       unsigned char pend_list_tag[MAX_PLIST_NUM];/* tag for pending entries */
        struct list_head wait_list;             /* store on-flushing entries */
        struct list_head fstrim_list;           /* in-flight discard from fstrim */
        wait_queue_head_t discard_wait_queue;   /* waiting queue for wake-up */
@@ -414,6 +419,9 @@ static inline bool __has_cursum_space(struct f2fs_journal *journal,
 #define F2FS_IOC_GARBAGE_COLLECT_RANGE _IOW(F2FS_IOCTL_MAGIC, 11,      \
                                                struct f2fs_gc_range)
 #define F2FS_IOC_GET_FEATURES          _IOR(F2FS_IOCTL_MAGIC, 12, __u32)
+#define F2FS_IOC_SET_PIN_FILE          _IOW(F2FS_IOCTL_MAGIC, 13, __u32)
+#define F2FS_IOC_GET_PIN_FILE          _IOR(F2FS_IOCTL_MAGIC, 14, __u32)
+#define F2FS_IOC_PRECACHE_EXTENTS      _IO(F2FS_IOCTL_MAGIC, 15)
 
 #define F2FS_IOC_SET_ENCRYPTION_POLICY FS_IOC_SET_ENCRYPTION_POLICY
 #define F2FS_IOC_GET_ENCRYPTION_POLICY FS_IOC_GET_ENCRYPTION_POLICY
@@ -466,10 +474,9 @@ struct f2fs_flush_device {
 #define DEF_MIN_INLINE_SIZE            1
 static inline int get_extra_isize(struct inode *inode);
 static inline int get_inline_xattr_addrs(struct inode *inode);
-#define F2FS_INLINE_XATTR_ADDRS(inode) get_inline_xattr_addrs(inode)
 #define MAX_INLINE_DATA(inode) (sizeof(__le32) *                       \
                                (CUR_ADDRS_PER_INODE(inode) -           \
-                               F2FS_INLINE_XATTR_ADDRS(inode) -        \
+                               get_inline_xattr_addrs(inode) - \
                                DEF_INLINE_RESERVED_SIZE))
 
 /* for inline dir */
@@ -606,6 +613,8 @@ struct f2fs_map_blocks {
        unsigned int m_len;
        unsigned int m_flags;
        pgoff_t *m_next_pgofs;          /* point next possible non-hole pgofs */
+       pgoff_t *m_next_extent;         /* point to next possible extent */
+       int m_seg_type;
 };
 
 /* for flag in get_data_block */
@@ -615,6 +624,7 @@ enum {
        F2FS_GET_BLOCK_BMAP,
        F2FS_GET_BLOCK_PRE_DIO,
        F2FS_GET_BLOCK_PRE_AIO,
+       F2FS_GET_BLOCK_PRECACHE,
 };
 
 /*
@@ -647,7 +657,10 @@ struct f2fs_inode_info {
        unsigned long i_flags;          /* keep an inode flags for ioctl */
        unsigned char i_advise;         /* use to give file attribute hints */
        unsigned char i_dir_level;      /* use for dentry level for large dir */
-       unsigned int i_current_depth;   /* use only in directory structure */
+       union {
+               unsigned int i_current_depth;   /* only for directory depth */
+               unsigned short i_gc_failures;   /* only for regular file */
+       };
        unsigned int i_pino;            /* parent inode number */
        umode_t i_acl_mode;             /* keep file acl mode temporarily */
 
@@ -682,6 +695,7 @@ struct f2fs_inode_info {
        int i_extra_isize;              /* size of extra space located in i_addr */
        kprojid_t i_projid;             /* id for project quota */
        int i_inline_xattr_size;        /* inline xattr size */
+       struct timespec i_crtime;       /* inode creation time */
 };
 
 static inline void get_extent_info(struct extent_info *ext,
@@ -986,6 +1000,7 @@ enum cp_reason_type {
        CP_NODE_NEED_CP,
        CP_FASTBOOT_MODE,
        CP_SPEC_LOG_NUM,
+       CP_RECOVER_DIR,
 };
 
 enum iostat_type {
@@ -1021,6 +1036,7 @@ struct f2fs_io_info {
        int need_lock;          /* indicate we need to lock cp_rwsem */
        bool in_list;           /* indicate fio is in io_list */
        enum iostat_type io_type;       /* io type */
+       struct writeback_control *io_wbc; /* writeback control */
 };
 
 #define is_read_io(rw) ((rw) == READ)
@@ -1157,6 +1173,7 @@ struct f2fs_sb_info {
        int dir_level;                          /* directory level */
        int inline_xattr_size;                  /* inline xattr size */
        unsigned int trigger_ssr_threshold;     /* threshold to trigger ssr */
+       int readdir_ra;                         /* readahead inode in readdir */
 
        block_t user_block_count;               /* # of user blocks */
        block_t total_valid_block_count;        /* # of valid blocks */
@@ -1164,6 +1181,11 @@ struct f2fs_sb_info {
        block_t last_valid_block_count;         /* for recovery */
        block_t reserved_blocks;                /* configurable reserved blocks */
        block_t current_reserved_blocks;        /* current reserved blocks */
+       block_t root_reserved_blocks;           /* root reserved blocks */
+       kuid_t s_resuid;                        /* reserved blocks for uid */
+       kgid_t s_resgid;                        /* reserved blocks for gid */
+
+       unsigned int nquota_files;              /* # of quota sysfile */
 
        u32 s_next_generation;                  /* for NFS support */
 
@@ -1188,6 +1210,9 @@ struct f2fs_sb_info {
        /* threshold for converting bg victims for fg */
        u64 fggc_threshold;
 
+       /* threshold for gc trials on pinned files */
+       u64 gc_pin_file_threshold;
+
        /* maximum # of trials to find a victim segment for SSR and GC */
        unsigned int max_victim_search;
 
@@ -1314,33 +1339,7 @@ static inline bool is_idle(struct f2fs_sb_info *sbi)
 /*
  * Inline functions
  */
-static inline u32 f2fs_crc32(struct f2fs_sb_info *sbi, const void *address,
-                          unsigned int length)
-{
-       SHASH_DESC_ON_STACK(shash, sbi->s_chksum_driver);
-       u32 *ctx = (u32 *)shash_desc_ctx(shash);
-       u32 retval;
-       int err;
-
-       shash->tfm = sbi->s_chksum_driver;
-       shash->flags = 0;
-       *ctx = F2FS_SUPER_MAGIC;
-
-       err = crypto_shash_update(shash, address, length);
-       BUG_ON(err);
-
-       retval = *ctx;
-       barrier_data(ctx);
-       return retval;
-}
-
-static inline bool f2fs_crc_valid(struct f2fs_sb_info *sbi, __u32 blk_crc,
-                                 void *buf, size_t buf_size)
-{
-       return f2fs_crc32(sbi, buf, buf_size) == blk_crc;
-}
-
-static inline u32 f2fs_chksum(struct f2fs_sb_info *sbi, u32 crc,
+static inline u32 __f2fs_crc32(struct f2fs_sb_info *sbi, u32 crc,
                              const void *address, unsigned int length)
 {
        struct {
@@ -1361,6 +1360,24 @@ static inline u32 f2fs_chksum(struct f2fs_sb_info *sbi, u32 crc,
        return *(u32 *)desc.ctx;
 }
 
+static inline u32 f2fs_crc32(struct f2fs_sb_info *sbi, const void *address,
+                          unsigned int length)
+{
+       return __f2fs_crc32(sbi, F2FS_SUPER_MAGIC, address, length);
+}
+
+static inline bool f2fs_crc_valid(struct f2fs_sb_info *sbi, __u32 blk_crc,
+                                 void *buf, size_t buf_size)
+{
+       return f2fs_crc32(sbi, buf, buf_size) == blk_crc;
+}
+
+static inline u32 f2fs_chksum(struct f2fs_sb_info *sbi, u32 crc,
+                             const void *address, unsigned int length)
+{
+       return __f2fs_crc32(sbi, crc, address, length);
+}
+
 static inline struct f2fs_inode_info *F2FS_I(struct inode *inode)
 {
        return container_of(inode, struct f2fs_inode_info, vfs_inode);
@@ -1619,6 +1636,25 @@ static inline bool f2fs_has_xattr_block(unsigned int ofs)
        return ofs == XATTR_NODE_OFFSET;
 }
 
+static inline bool __allow_reserved_blocks(struct f2fs_sb_info *sbi,
+                                       struct inode *inode)
+{
+       if (!inode)
+               return true;
+       if (!test_opt(sbi, RESERVE_ROOT))
+               return false;
+       if (IS_NOQUOTA(inode))
+               return true;
+       if (capable(CAP_SYS_RESOURCE))
+               return true;
+       if (uid_eq(sbi->s_resuid, current_fsuid()))
+               return true;
+       if (!gid_eq(sbi->s_resgid, GLOBAL_ROOT_GID) &&
+                                       in_group_p(sbi->s_resgid))
+               return true;
+       return false;
+}
+
 static inline void f2fs_i_blocks_write(struct inode *, block_t, bool, bool);
 static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
                                 struct inode *inode, blkcnt_t *count)
@@ -1648,11 +1684,17 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
        sbi->total_valid_block_count += (block_t)(*count);
        avail_user_block_count = sbi->user_block_count -
                                        sbi->current_reserved_blocks;
+
+       if (!__allow_reserved_blocks(sbi, inode))
+               avail_user_block_count -= sbi->root_reserved_blocks;
+
        if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) {
                diff = sbi->total_valid_block_count - avail_user_block_count;
+               if (diff > *count)
+                       diff = *count;
                *count -= diff;
                release = diff;
-               sbi->total_valid_block_count = avail_user_block_count;
+               sbi->total_valid_block_count -= diff;
                if (!*count) {
                        spin_unlock(&sbi->stat_lock);
                        percpu_counter_sub(&sbi->alloc_valid_block_count, diff);
@@ -1661,7 +1703,7 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
        }
        spin_unlock(&sbi->stat_lock);
 
-       if (release)
+       if (unlikely(release))
                dquot_release_reservation_block(inode, release);
        f2fs_i_blocks_write(inode, *count, true, true);
        return 0;
@@ -1841,9 +1883,13 @@ static inline int inc_valid_node_count(struct f2fs_sb_info *sbi,
 
        spin_lock(&sbi->stat_lock);
 
-       valid_block_count = sbi->total_valid_block_count + 1;
-       if (unlikely(valid_block_count + sbi->current_reserved_blocks >
-                                               sbi->user_block_count)) {
+       valid_block_count = sbi->total_valid_block_count +
+                                       sbi->current_reserved_blocks + 1;
+
+       if (!__allow_reserved_blocks(sbi, inode))
+               valid_block_count += sbi->root_reserved_blocks;
+
+       if (unlikely(valid_block_count > sbi->user_block_count)) {
                spin_unlock(&sbi->stat_lock);
                goto enospc;
        }
@@ -2056,11 +2102,11 @@ static inline block_t datablock_addr(struct inode *inode,
        raw_node = F2FS_NODE(node_page);
 
        /* from GC path only */
-       if (!inode) {
-               if (is_inode)
+       if (is_inode) {
+               if (!inode)
                        base = offset_in_addr(&raw_node->i);
-       } else if (f2fs_has_extra_attr(inode) && is_inode) {
-               base = get_extra_isize(inode);
+               else if (f2fs_has_extra_attr(inode))
+                       base = get_extra_isize(inode);
        }
 
        addr_array = blkaddr_in_node(raw_node);
@@ -2171,6 +2217,7 @@ enum {
        FI_HOT_DATA,            /* indicate file is hot */
        FI_EXTRA_ATTR,          /* indicate file has extra attribute */
        FI_PROJ_INHERIT,        /* indicate file inherits projectid */
+       FI_PIN_FILE,            /* indicate file should not be gced */
 };
 
 static inline void __mark_inode_dirty_flag(struct inode *inode,
@@ -2180,10 +2227,12 @@ static inline void __mark_inode_dirty_flag(struct inode *inode,
        case FI_INLINE_XATTR:
        case FI_INLINE_DATA:
        case FI_INLINE_DENTRY:
+       case FI_NEW_INODE:
                if (set)
                        return;
        case FI_DATA_EXIST:
        case FI_INLINE_DOTS:
+       case FI_PIN_FILE:
                f2fs_mark_inode_dirty_sync(inode, true);
        }
 }
@@ -2264,6 +2313,13 @@ static inline void f2fs_i_depth_write(struct inode *inode, unsigned int depth)
        f2fs_mark_inode_dirty_sync(inode, true);
 }
 
+static inline void f2fs_i_gc_failures_write(struct inode *inode,
+                                       unsigned int count)
+{
+       F2FS_I(inode)->i_gc_failures = count;
+       f2fs_mark_inode_dirty_sync(inode, true);
+}
+
 static inline void f2fs_i_xnid_write(struct inode *inode, nid_t xnid)
 {
        F2FS_I(inode)->i_xattr_nid = xnid;
@@ -2292,6 +2348,8 @@ static inline void get_inline_info(struct inode *inode, struct f2fs_inode *ri)
                set_bit(FI_INLINE_DOTS, &fi->flags);
        if (ri->i_inline & F2FS_EXTRA_ATTR)
                set_bit(FI_EXTRA_ATTR, &fi->flags);
+       if (ri->i_inline & F2FS_PIN_FILE)
+               set_bit(FI_PIN_FILE, &fi->flags);
 }
 
 static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri)
@@ -2310,6 +2368,8 @@ static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri)
                ri->i_inline |= F2FS_INLINE_DOTS;
        if (is_inode_flag_set(inode, FI_EXTRA_ATTR))
                ri->i_inline |= F2FS_EXTRA_ATTR;
+       if (is_inode_flag_set(inode, FI_PIN_FILE))
+               ri->i_inline |= F2FS_PIN_FILE;
 }
 
 static inline int f2fs_has_extra_attr(struct inode *inode)
@@ -2324,7 +2384,7 @@ static inline int f2fs_has_inline_xattr(struct inode *inode)
 
 static inline unsigned int addrs_per_inode(struct inode *inode)
 {
-       return CUR_ADDRS_PER_INODE(inode) - F2FS_INLINE_XATTR_ADDRS(inode);
+       return CUR_ADDRS_PER_INODE(inode) - get_inline_xattr_addrs(inode);
 }
 
 static inline void *inline_xattr_addr(struct inode *inode, struct page *page)
@@ -2332,7 +2392,7 @@ static inline void *inline_xattr_addr(struct inode *inode, struct page *page)
        struct f2fs_inode *ri = F2FS_INODE(page);
 
        return (void *)&(ri->i_addr[DEF_ADDRS_PER_INODE -
-                                       F2FS_INLINE_XATTR_ADDRS(inode)]);
+                                       get_inline_xattr_addrs(inode)]);
 }
 
 static inline int inline_xattr_size(struct inode *inode)
@@ -2355,6 +2415,11 @@ static inline int f2fs_has_inline_dots(struct inode *inode)
        return is_inode_flag_set(inode, FI_INLINE_DOTS);
 }
 
+static inline bool f2fs_is_pinned_file(struct inode *inode)
+{
+       return is_inode_flag_set(inode, FI_PIN_FILE);
+}
+
 static inline bool f2fs_is_atomic_file(struct inode *inode)
 {
        return is_inode_flag_set(inode, FI_ATOMIC_FILE);
@@ -2503,12 +2568,44 @@ static inline void *kvzalloc(size_t size, gfp_t flags)
        return ret;
 }
 
+enum rw_hint {
+       WRITE_LIFE_NOT_SET      = 0,
+       WRITE_LIFE_NONE         = 1, /* RWH_WRITE_LIFE_NONE */
+       WRITE_LIFE_SHORT        = 2, /* RWH_WRITE_LIFE_SHORT */
+       WRITE_LIFE_MEDIUM       = 3, /* RWH_WRITE_LIFE_MEDIUM */
+       WRITE_LIFE_LONG         = 4, /* RWH_WRITE_LIFE_LONG */
+       WRITE_LIFE_EXTREME      = 5, /* RWH_WRITE_LIFE_EXTREME */
+};
+
+static inline void *f2fs_kzalloc(struct f2fs_sb_info *sbi,
+                                       size_t size, gfp_t flags)
+{
+       return f2fs_kmalloc(sbi, size, flags | __GFP_ZERO);
+}
+
+static inline void *f2fs_kvmalloc(struct f2fs_sb_info *sbi,
+                                       size_t size, gfp_t flags)
+{
+#ifdef CONFIG_F2FS_FAULT_INJECTION
+       if (time_to_inject(sbi, FAULT_KVMALLOC)) {
+               f2fs_show_injection_info(FAULT_KVMALLOC);
+               return NULL;
+       }
+#endif
+       return kvmalloc(size, flags);
+}
+
+static inline void *f2fs_kvzalloc(struct f2fs_sb_info *sbi,
+                                       size_t size, gfp_t flags)
+{
+       return f2fs_kvmalloc(sbi, size, flags | __GFP_ZERO);
+}
+
 static inline int get_extra_isize(struct inode *inode)
 {
        return F2FS_I(inode)->i_extra_isize / sizeof(__le32);
 }
 
-static inline int f2fs_sb_has_flexible_inline_xattr(struct super_block *sb);
 static inline int get_inline_xattr_addrs(struct inode *inode)
 {
        return F2FS_I(inode)->i_inline_xattr_size;
@@ -2564,9 +2661,11 @@ int f2fs_getattr(struct vfsmount *mnt, struct dentry *dentry,
                        struct kstat *stat);
 int f2fs_setattr(struct dentry *dentry, struct iattr *attr);
 int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end);
-int truncate_data_blocks_range(struct dnode_of_data *dn, int count);
+void truncate_data_blocks_range(struct dnode_of_data *dn, int count);
+int f2fs_precache_extents(struct inode *inode);
 long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
 long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+int f2fs_pin_file_control(struct inode *inode, bool inc);
 
 /*
  * inode.c
@@ -2577,8 +2676,8 @@ void f2fs_inode_chksum_set(struct f2fs_sb_info *sbi, struct page *page);
 struct inode *f2fs_iget(struct super_block *sb, unsigned long ino);
 struct inode *f2fs_iget_retry(struct super_block *sb, unsigned long ino);
 int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink);
-int update_inode(struct inode *inode, struct page *node_page);
-int update_inode_page(struct inode *inode);
+void update_inode(struct inode *inode, struct page *node_page);
+void update_inode_page(struct inode *inode);
 int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc);
 void f2fs_evict_inode(struct inode *inode);
 void handle_failed_inode(struct inode *inode);
@@ -2689,10 +2788,9 @@ void alloc_nid_done(struct f2fs_sb_info *sbi, nid_t nid);
 void alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid);
 int try_to_free_nids(struct f2fs_sb_info *sbi, int nr_shrink);
 void recover_inline_xattr(struct inode *inode, struct page *page);
-int recover_xattr_data(struct inode *inode, struct page *page,
-                       block_t blkaddr);
+int recover_xattr_data(struct inode *inode, struct page *page);
 int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page);
-int restore_node_summary(struct f2fs_sb_info *sbi,
+void restore_node_summary(struct f2fs_sb_info *sbi,
                        unsigned int segno, struct f2fs_summary_block *sum);
 void flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc);
 int build_node_manager(struct f2fs_sb_info *sbi);
@@ -2719,6 +2817,7 @@ void invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr);
 bool is_checkpointed_data(struct f2fs_sb_info *sbi, block_t blkaddr);
 void init_discard_policy(struct discard_policy *dpolicy, int discard_type,
                                                unsigned int granularity);
+void drop_discard_cmd(struct f2fs_sb_info *sbi);
 void stop_discard_thread(struct f2fs_sb_info *sbi);
 bool f2fs_wait_discard_bios(struct f2fs_sb_info *sbi);
 void clear_prefree_segments(struct f2fs_sb_info *sbi, struct cp_control *cpc);
@@ -2757,6 +2856,7 @@ int build_segment_manager(struct f2fs_sb_info *sbi);
 void destroy_segment_manager(struct f2fs_sb_info *sbi);
 int __init create_segment_manager_caches(void);
 void destroy_segment_manager_caches(void);
+int rw_hint_to_seg_type(enum rw_hint hint);
 
 /*
  * checkpoint.c
@@ -2826,6 +2926,8 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
                        int create, int flag);
 int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                        u64 start, u64 len);
+bool should_update_inplace(struct inode *inode, struct f2fs_io_info *fio);
+bool should_update_outplace(struct inode *inode, struct f2fs_io_info *fio);
 void f2fs_set_page_dirty_nobuffers(struct page *page);
 int __f2fs_write_data_pages(struct address_space *mapping,
                                                struct writeback_control *wbc,
@@ -3194,6 +3296,11 @@ static inline int f2fs_sb_has_quota_ino(struct super_block *sb)
        return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_QUOTA_INO);
 }
 
+static inline int f2fs_sb_has_inode_crtime(struct super_block *sb)
+{
+       return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_INODE_CRTIME);
+}
+
 #ifdef CONFIG_BLK_DEV_ZONED
 static inline int get_blkz_type(struct f2fs_sb_info *sbi,
                        struct block_device *bdev, block_t blkaddr)
index bfff53f..65cda5b 100644 (file)
@@ -168,6 +168,9 @@ static inline enum cp_reason_type need_do_checkpoint(struct inode *inode)
                cp_reason = CP_FASTBOOT_MODE;
        else if (sbi->active_logs == 2)
                cp_reason = CP_SPEC_LOG_NUM;
+       else if (need_dentry_mark(sbi, inode->i_ino) &&
+               exist_written_data(sbi, F2FS_I(inode)->i_pino, TRANS_DIR_INO))
+               cp_reason = CP_RECOVER_DIR;
 
        return cp_reason;
 }
@@ -474,26 +477,14 @@ static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma)
 
 static int f2fs_file_open(struct inode *inode, struct file *filp)
 {
-       struct dentry *dir;
+       int err = fscrypt_file_open(inode, filp);
 
-       if (f2fs_encrypted_inode(inode)) {
-               int ret = fscrypt_get_encryption_info(inode);
-               if (ret)
-                       return -EACCES;
-               if (!fscrypt_has_encryption_key(inode))
-                       return -ENOKEY;
-       }
-       dir = dget_parent(file_dentry(filp));
-       if (f2fs_encrypted_inode(d_inode(dir)) &&
-                       !fscrypt_has_permitted_context(d_inode(dir), inode)) {
-               dput(dir);
-               return -EPERM;
-       }
-       dput(dir);
+       if (err)
+               return err;
        return dquot_file_open(inode, filp);
 }
 
-int truncate_data_blocks_range(struct dnode_of_data *dn, int count)
+void truncate_data_blocks_range(struct dnode_of_data *dn, int count)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
        struct f2fs_node *raw_node;
@@ -536,7 +527,6 @@ int truncate_data_blocks_range(struct dnode_of_data *dn, int count)
        f2fs_update_time(sbi, REQ_TIME);
        trace_f2fs_truncate_data_blocks_range(dn->inode, dn->nid,
                                         dn->ofs_in_node, nr_free);
-       return nr_free;
 }
 
 void truncate_data_blocks(struct dnode_of_data *dn)
@@ -683,6 +673,37 @@ int f2fs_getattr(struct vfsmount *mnt,
                         struct dentry *dentry, struct kstat *stat)
 {
        struct inode *inode = d_inode(dentry);
+#if 0
+       struct f2fs_inode_info *fi = F2FS_I(inode);
+       struct f2fs_inode *ri;
+       unsigned int flags;
+
+       if (f2fs_has_extra_attr(inode) &&
+                       f2fs_sb_has_inode_crtime(inode->i_sb) &&
+                       F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_crtime)) {
+               stat->result_mask |= STATX_BTIME;
+               stat->btime.tv_sec = fi->i_crtime.tv_sec;
+               stat->btime.tv_nsec = fi->i_crtime.tv_nsec;
+       }
+
+       flags = fi->i_flags & (FS_FL_USER_VISIBLE | FS_PROJINHERIT_FL);
+       if (flags & FS_APPEND_FL)
+               stat->attributes |= STATX_ATTR_APPEND;
+       if (flags & FS_COMPR_FL)
+               stat->attributes |= STATX_ATTR_COMPRESSED;
+       if (f2fs_encrypted_inode(inode))
+               stat->attributes |= STATX_ATTR_ENCRYPTED;
+       if (flags & FS_IMMUTABLE_FL)
+               stat->attributes |= STATX_ATTR_IMMUTABLE;
+       if (flags & FS_NODUMP_FL)
+               stat->attributes |= STATX_ATTR_NODUMP;
+
+       stat->attributes_mask |= (STATX_ATTR_APPEND |
+                                 STATX_ATTR_COMPRESSED |
+                                 STATX_ATTR_ENCRYPTED |
+                                 STATX_ATTR_IMMUTABLE |
+                                 STATX_ATTR_NODUMP);
+#endif
        generic_fillattr(inode, stat);
 
        /* we need to show initial sectors used for inline_data/dentries */
@@ -736,6 +757,10 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)
        if (err)
                return err;
 
+       err = fscrypt_prepare_setattr(dentry, attr);
+       if (err)
+               return err;
+
        if (is_quota_modification(inode, attr)) {
                err = dquot_initialize(inode);
                if (err)
@@ -751,14 +776,6 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)
        }
 
        if (attr->ia_valid & ATTR_SIZE) {
-               if (f2fs_encrypted_inode(inode)) {
-                       err = fscrypt_get_encryption_info(inode);
-                       if (err)
-                               return err;
-                       if (!fscrypt_has_encryption_key(inode))
-                               return -ENOKEY;
-               }
-
                if (attr->ia_size <= i_size_read(inode)) {
                        down_write(&F2FS_I(inode)->i_mmap_sem);
                        truncate_setsize(inode, attr->ia_size);
@@ -1098,11 +1115,13 @@ static int __exchange_data_block(struct inode *src_inode,
        while (len) {
                olen = min((pgoff_t)4 * ADDRS_PER_BLOCK, len);
 
-               src_blkaddr = kvzalloc(sizeof(block_t) * olen, GFP_KERNEL);
+               src_blkaddr = f2fs_kvzalloc(F2FS_I_SB(src_inode),
+                                       sizeof(block_t) * olen, GFP_KERNEL);
                if (!src_blkaddr)
                        return -ENOMEM;
 
-               do_replace = kvzalloc(sizeof(int) * olen, GFP_KERNEL);
+               do_replace = f2fs_kvzalloc(F2FS_I_SB(src_inode),
+                                       sizeof(int) * olen, GFP_KERNEL);
                if (!do_replace) {
                        kvfree(src_blkaddr);
                        return -ENOMEM;
@@ -1170,14 +1189,14 @@ static int f2fs_collapse_range(struct inode *inode, loff_t offset, loff_t len)
        pg_start = offset >> PAGE_SHIFT;
        pg_end = (offset + len) >> PAGE_SHIFT;
 
+       /* avoid gc operation during block exchange */
+       down_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
+
        down_write(&F2FS_I(inode)->i_mmap_sem);
        /* write out all dirty pages from offset */
        ret = filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX);
        if (ret)
-               goto out;
-
-       /* avoid gc operation during block exchange */
-       down_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
+               goto out_unlock;
 
        truncate_pagecache(inode, offset);
 
@@ -1196,9 +1215,8 @@ static int f2fs_collapse_range(struct inode *inode, loff_t offset, loff_t len)
        if (!ret)
                f2fs_i_size_write(inode, new_size);
 out_unlock:
-       up_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
-out:
        up_write(&F2FS_I(inode)->i_mmap_sem);
+       up_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
        return ret;
 }
 
@@ -1369,6 +1387,9 @@ static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len)
 
        f2fs_balance_fs(sbi, true);
 
+       /* avoid gc operation during block exchange */
+       down_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
+
        down_write(&F2FS_I(inode)->i_mmap_sem);
        ret = truncate_blocks(inode, i_size_read(inode), true);
        if (ret)
@@ -1379,9 +1400,6 @@ static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len)
        if (ret)
                goto out;
 
-       /* avoid gc operation during block exchange */
-       down_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
-
        truncate_pagecache(inode, offset);
 
        pg_start = offset >> PAGE_SHIFT;
@@ -1409,10 +1427,9 @@ static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len)
 
        if (!ret)
                f2fs_i_size_write(inode, new_size);
-
-       up_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
 out:
        up_write(&F2FS_I(inode)->i_mmap_sem);
+       up_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
        return ret;
 }
 
@@ -1420,7 +1437,8 @@ static int expand_inode_data(struct inode *inode, loff_t offset,
                                        loff_t len, int mode)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
-       struct f2fs_map_blocks map = { .m_next_pgofs = NULL };
+       struct f2fs_map_blocks map = { .m_next_pgofs = NULL,
+                       .m_next_extent = NULL, .m_seg_type = NO_CHECK_TYPE };
        pgoff_t pg_end;
        loff_t new_size = i_size_read(inode);
        loff_t off_end;
@@ -1828,14 +1846,20 @@ static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg)
        switch (in) {
        case F2FS_GOING_DOWN_FULLSYNC:
                sb = freeze_bdev(sb->s_bdev);
-               if (sb && !IS_ERR(sb)) {
+               if (IS_ERR(sb)) {
+                       ret = PTR_ERR(sb);
+                       goto out;
+               }
+               if (sb) {
                        f2fs_stop_checkpoint(sbi, false);
                        thaw_bdev(sb->s_bdev, sb);
                }
                break;
        case F2FS_GOING_DOWN_METASYNC:
                /* do checkpoint only */
-               f2fs_sync_fs(sb, 1);
+               ret = f2fs_sync_fs(sb, 1);
+               if (ret)
+                       goto out;
                f2fs_stop_checkpoint(sbi, false);
                break;
        case F2FS_GOING_DOWN_NOSYNC:
@@ -1849,6 +1873,13 @@ static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg)
                ret = -EINVAL;
                goto out;
        }
+
+       stop_gc_thread(sbi);
+       stop_discard_thread(sbi);
+
+       drop_discard_cmd(sbi);
+       clear_opt(sbi, DISCARD);
+
        f2fs_update_time(sbi, REQ_TIME);
 out:
        mnt_drop_write_file(filp);
@@ -2060,9 +2091,10 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi,
                                        struct f2fs_defragment *range)
 {
        struct inode *inode = file_inode(filp);
-       struct f2fs_map_blocks map = { .m_next_pgofs = NULL };
+       struct f2fs_map_blocks map = { .m_next_extent = NULL,
+                                       .m_seg_type = NO_CHECK_TYPE };
        struct extent_info ei = {0,0,0};
-       pgoff_t pg_start, pg_end;
+       pgoff_t pg_start, pg_end, next_pgofs;
        unsigned int blk_per_seg = sbi->blocks_per_seg;
        unsigned int total = 0, sec_num;
        block_t blk_end = 0;
@@ -2070,7 +2102,7 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi,
        int err;
 
        /* if in-place-update policy is enabled, don't waste time here */
-       if (need_inplace_update_policy(inode, NULL))
+       if (should_update_inplace(inode, NULL))
                return -EINVAL;
 
        pg_start = range->start >> PAGE_SHIFT;
@@ -2096,6 +2128,7 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi,
        }
 
        map.m_lblk = pg_start;
+       map.m_next_pgofs = &next_pgofs;
 
        /*
         * lookup mapping info in dnode page cache, skip defragmenting if all
@@ -2109,14 +2142,16 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi,
                        goto out;
 
                if (!(map.m_flags & F2FS_MAP_FLAGS)) {
-                       map.m_lblk++;
+                       map.m_lblk = next_pgofs;
                        continue;
                }
 
-               if (blk_end && blk_end != map.m_pblk) {
+               if (blk_end && blk_end != map.m_pblk)
                        fragmented = true;
-                       break;
-               }
+
+               /* record total count of block that we're going to move */
+               total += map.m_len;
+
                blk_end = map.m_pblk + map.m_len;
 
                map.m_lblk += map.m_len;
@@ -2125,10 +2160,7 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi,
        if (!fragmented)
                goto out;
 
-       map.m_lblk = pg_start;
-       map.m_len = pg_end - pg_start;
-
-       sec_num = (map.m_len + BLKS_PER_SEC(sbi) - 1) / BLKS_PER_SEC(sbi);
+       sec_num = (total + BLKS_PER_SEC(sbi) - 1) / BLKS_PER_SEC(sbi);
 
        /*
         * make sure there are enough free section for LFS allocation, this can
@@ -2140,6 +2172,10 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi,
                goto out;
        }
 
+       map.m_lblk = pg_start;
+       map.m_len = pg_end - pg_start;
+       total = 0;
+
        while (map.m_lblk < pg_end) {
                pgoff_t idx;
                int cnt = 0;
@@ -2151,7 +2187,7 @@ do_map:
                        goto clear_out;
 
                if (!(map.m_flags & F2FS_MAP_FLAGS)) {
-                       map.m_lblk++;
+                       map.m_lblk = next_pgofs;
                        continue;
                }
 
@@ -2463,6 +2499,125 @@ static int f2fs_ioc_get_features(struct file *filp, unsigned long arg)
        return put_user(sb_feature, (u32 __user *)arg);
 }
 
+int f2fs_pin_file_control(struct inode *inode, bool inc)
+{
+       struct f2fs_inode_info *fi = F2FS_I(inode);
+       struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+
+       /* Use i_gc_failures for normal file as a risk signal. */
+       if (inc)
+               f2fs_i_gc_failures_write(inode, fi->i_gc_failures + 1);
+
+       if (fi->i_gc_failures > sbi->gc_pin_file_threshold) {
+               f2fs_msg(sbi->sb, KERN_WARNING,
+                       "%s: Enable GC = ino %lx after %x GC trials\n",
+                       __func__, inode->i_ino, fi->i_gc_failures);
+               clear_inode_flag(inode, FI_PIN_FILE);
+               return -EAGAIN;
+       }
+       return 0;
+}
+
+static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg)
+{
+       struct inode *inode = file_inode(filp);
+       __u32 pin;
+       int ret = 0;
+
+       if (!inode_owner_or_capable(inode))
+               return -EACCES;
+
+       if (get_user(pin, (__u32 __user *)arg))
+               return -EFAULT;
+
+       if (!S_ISREG(inode->i_mode))
+               return -EINVAL;
+
+       if (f2fs_readonly(F2FS_I_SB(inode)->sb))
+               return -EROFS;
+
+       ret = mnt_want_write_file(filp);
+       if (ret)
+               return ret;
+
+       inode_lock(inode);
+
+       if (should_update_outplace(inode, NULL)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (!pin) {
+               clear_inode_flag(inode, FI_PIN_FILE);
+               F2FS_I(inode)->i_gc_failures = 1;
+               goto done;
+       }
+
+       if (f2fs_pin_file_control(inode, false)) {
+               ret = -EAGAIN;
+               goto out;
+       }
+       ret = f2fs_convert_inline_inode(inode);
+       if (ret)
+               goto out;
+
+       set_inode_flag(inode, FI_PIN_FILE);
+       ret = F2FS_I(inode)->i_gc_failures;
+done:
+       f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
+out:
+       inode_unlock(inode);
+       mnt_drop_write_file(filp);
+       return ret;
+}
+
+static int f2fs_ioc_get_pin_file(struct file *filp, unsigned long arg)
+{
+       struct inode *inode = file_inode(filp);
+       __u32 pin = 0;
+
+       if (is_inode_flag_set(inode, FI_PIN_FILE))
+               pin = F2FS_I(inode)->i_gc_failures;
+       return put_user(pin, (u32 __user *)arg);
+}
+
+int f2fs_precache_extents(struct inode *inode)
+{
+       struct f2fs_inode_info *fi = F2FS_I(inode);
+       struct f2fs_map_blocks map;
+       pgoff_t m_next_extent;
+       loff_t end;
+       int err;
+
+       if (is_inode_flag_set(inode, FI_NO_EXTENT))
+               return -EOPNOTSUPP;
+
+       map.m_lblk = 0;
+       map.m_next_pgofs = NULL;
+       map.m_next_extent = &m_next_extent;
+       map.m_seg_type = NO_CHECK_TYPE;
+       end = F2FS_I_SB(inode)->max_file_blocks;
+
+       while (map.m_lblk < end) {
+               map.m_len = end - map.m_lblk;
+
+               down_write(&fi->dio_rwsem[WRITE]);
+               err = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_PRECACHE);
+               up_write(&fi->dio_rwsem[WRITE]);
+               if (err)
+                       return err;
+
+               map.m_lblk = m_next_extent;
+       }
+
+       return err;
+}
+
+static int f2fs_ioc_precache_extents(struct file *filp, unsigned long arg)
+{
+       return f2fs_precache_extents(file_inode(filp));
+}
+
 long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
        if (unlikely(f2fs_cp_error(F2FS_I_SB(file_inode(filp)))))
@@ -2509,6 +2664,12 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                return f2fs_ioc_flush_device(filp, arg);
        case F2FS_IOC_GET_FEATURES:
                return f2fs_ioc_get_features(filp, arg);
+       case F2FS_IOC_GET_PIN_FILE:
+               return f2fs_ioc_get_pin_file(filp, arg);
+       case F2FS_IOC_SET_PIN_FILE:
+               return f2fs_ioc_set_pin_file(filp, arg);
+       case F2FS_IOC_PRECACHE_EXTENTS:
+               return f2fs_ioc_precache_extents(filp, arg);
        default:
                return -ENOTTY;
        }
@@ -2587,6 +2748,9 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case F2FS_IOC_MOVE_RANGE:
        case F2FS_IOC_FLUSH_DEVICE:
        case F2FS_IOC_GET_FEATURES:
+       case F2FS_IOC_GET_PIN_FILE:
+       case F2FS_IOC_SET_PIN_FILE:
+       case F2FS_IOC_PRECACHE_EXTENTS:
                break;
        default:
                return -ENOIOCTLCMD;
index be9fd61..d0de342 100644 (file)
@@ -624,6 +624,11 @@ static void move_data_block(struct inode *inode, block_t bidx,
        if (f2fs_is_atomic_file(inode))
                goto out;
 
+       if (f2fs_is_pinned_file(inode)) {
+               f2fs_pin_file_control(inode, true);
+               goto out;
+       }
+
        set_new_dnode(&dn, inode, NULL, NULL, 0);
        err = get_dnode_of_data(&dn, bidx, LOOKUP_NODE);
        if (err)
@@ -686,7 +691,12 @@ static void move_data_block(struct inode *inode, block_t bidx,
        fio.op = REQ_OP_WRITE;
        fio.op_flags = REQ_SYNC | REQ_NOIDLE;
        fio.new_blkaddr = newaddr;
-       f2fs_submit_page_write(&fio);
+       err = f2fs_submit_page_write(&fio);
+       if (err) {
+               if (PageWriteback(fio.encrypted_page))
+                       end_page_writeback(fio.encrypted_page);
+               goto put_page_out;
+       }
 
        f2fs_update_iostat(fio.sbi, FS_GC_DATA_IO, F2FS_BLKSIZE);
 
@@ -720,6 +730,11 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type,
 
        if (f2fs_is_atomic_file(inode))
                goto out;
+       if (f2fs_is_pinned_file(inode)) {
+               if (gc_type == FG_GC)
+                       f2fs_pin_file_control(inode, true);
+               goto out;
+       }
 
        if (gc_type == BG_GC) {
                if (PageWriteback(page))
@@ -1091,6 +1106,7 @@ void build_gc_manager(struct f2fs_sb_info *sbi)
 
        sbi->fggc_threshold = div64_u64((main_count - ovp_count) *
                                BLKS_PER_SEC(sbi), (main_count - resv_count));
+       sbi->gc_pin_file_threshold = DEF_GC_FAILED_PINNED_FILES;
 
        /* give warm/cold data area from slower device */
        if (sbi->s_ndevs && sbi->segs_per_sec == 1)
index 9325191..b0045d4 100644 (file)
@@ -20,6 +20,8 @@
 #define LIMIT_INVALID_BLOCK    40 /* percentage over total user space */
 #define LIMIT_FREE_BLOCK       40 /* percentage over invalid + free space */
 
+#define DEF_GC_FAILED_PINNED_FILES     2048
+
 /* Search max. number of dirty segments to select a victim segment */
 #define DEF_MAX_VICTIM_SEARCH 4096 /* covers 8GB */
 
index b4c4f2b..89c838b 100644 (file)
@@ -22,6 +22,9 @@
 
 void f2fs_mark_inode_dirty_sync(struct inode *inode, bool sync)
 {
+       if (is_inode_flag_set(inode, FI_NEW_INODE))
+               return;
+
        if (f2fs_inode_dirtied(inode, sync))
                return;
 
@@ -275,6 +278,12 @@ static int do_read_inode(struct inode *inode)
                i_projid = F2FS_DEF_PROJID;
        fi->i_projid = make_kprojid(&init_user_ns, i_projid);
 
+       if (f2fs_has_extra_attr(inode) && f2fs_sb_has_inode_crtime(sbi->sb) &&
+                       F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_crtime)) {
+               fi->i_crtime.tv_sec = le64_to_cpu(ri->i_crtime);
+               fi->i_crtime.tv_nsec = le32_to_cpu(ri->i_crtime_nsec);
+       }
+
        f2fs_put_page(node_page, 1);
 
        stat_inc_inline_xattr(inode);
@@ -360,14 +369,15 @@ retry:
        return inode;
 }
 
-int update_inode(struct inode *inode, struct page *node_page)
+void update_inode(struct inode *inode, struct page *node_page)
 {
        struct f2fs_inode *ri;
        struct extent_tree *et = F2FS_I(inode)->extent_tree;
 
-       f2fs_inode_synced(inode);
-
        f2fs_wait_on_page_writeback(node_page, NODE, true);
+       set_page_dirty(node_page);
+
+       f2fs_inode_synced(inode);
 
        ri = F2FS_INODE(node_page);
 
@@ -417,6 +427,15 @@ int update_inode(struct inode *inode, struct page *node_page)
                                                F2FS_I(inode)->i_projid);
                        ri->i_projid = cpu_to_le32(i_projid);
                }
+
+               if (f2fs_sb_has_inode_crtime(F2FS_I_SB(inode)->sb) &&
+                       F2FS_FITS_IN_INODE(ri, F2FS_I(inode)->i_extra_isize,
+                                                               i_crtime)) {
+                       ri->i_crtime =
+                               cpu_to_le64(F2FS_I(inode)->i_crtime.tv_sec);
+                       ri->i_crtime_nsec =
+                               cpu_to_le32(F2FS_I(inode)->i_crtime.tv_nsec);
+               }
        }
 
        __set_inode_rdev(inode, ri);
@@ -426,14 +445,12 @@ int update_inode(struct inode *inode, struct page *node_page)
        if (inode->i_nlink == 0)
                clear_inline_node(node_page);
 
-       return set_page_dirty(node_page);
 }
 
-int update_inode_page(struct inode *inode)
+void update_inode_page(struct inode *inode)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
        struct page *node_page;
-       int ret = 0;
 retry:
        node_page = get_node_page(sbi, inode->i_ino);
        if (IS_ERR(node_page)) {
@@ -444,11 +461,10 @@ retry:
                } else if (err != -ENOENT) {
                        f2fs_stop_checkpoint(sbi, false);
                }
-               return 0;
+               return;
        }
-       ret = update_inode(inode, node_page);
+       update_inode(inode, node_page);
        f2fs_put_page(node_page, 1);
-       return ret;
 }
 
 int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc)
index cf8f437..da7f709 100644 (file)
@@ -50,7 +50,8 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
 
        inode->i_ino = ino;
        inode->i_blocks = 0;
-       inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
+       inode->i_mtime = inode->i_atime = inode->i_ctime =
+                       F2FS_I(inode)->i_crtime = current_time(inode);
        inode->i_generation = sbi->s_next_generation++;
 
        err = insert_inode_locked(inode);
@@ -74,12 +75,12 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
        if (err)
                goto fail_drop;
 
+       set_inode_flag(inode, FI_NEW_INODE);
+
        /* If the directory encrypted, then we should encrypt the inode. */
        if (f2fs_encrypted_inode(dir) && f2fs_may_encrypt(inode))
                f2fs_set_encrypted_inode(inode);
 
-       set_inode_flag(inode, FI_NEW_INODE);
-
        if (f2fs_sb_has_extra_attr(sbi->sb)) {
                set_inode_flag(inode, FI_EXTRA_ATTR);
                F2FS_I(inode)->i_extra_isize = F2FS_TOTAL_EXTRA_ATTR_SIZE;
@@ -240,9 +241,9 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir,
        if (unlikely(f2fs_cp_error(sbi)))
                return -EIO;
 
-       if (f2fs_encrypted_inode(dir) &&
-                       !fscrypt_has_permitted_context(dir, inode))
-               return -EPERM;
+       err = fscrypt_prepare_link(old_dentry, dir, dentry);
+       if (err)
+               return err;
 
        if (is_inode_flag_set(dir, FI_PROJ_INHERIT) &&
                        (!projid_eq(F2FS_I(dir)->i_projid,
@@ -357,20 +358,9 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
 
        trace_f2fs_lookup_start(dir, dentry, flags);
 
-       if (f2fs_encrypted_inode(dir)) {
-               err = fscrypt_get_encryption_info(dir);
-
-               /*
-                * DCACHE_ENCRYPTED_WITH_KEY is set if the dentry is
-                * created while the directory was encrypted and we
-                * don't have access to the key.
-                */
-               if (fscrypt_has_encryption_key(dir))
-                       fscrypt_set_encrypted_dentry(dentry);
-               fscrypt_set_d_op(dentry);
-               if (err && err != -ENOKEY)
-                       goto out;
-       }
+       err = fscrypt_prepare_lookup(dir, dentry, flags);
+       if (err)
+               goto out;
 
        if (dentry->d_name.len > F2FS_NAME_LEN) {
                err = -ENAMETOOLONG;
@@ -541,7 +531,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
                struct qstr istr = QSTR_INIT(symname, len);
                struct fscrypt_str ostr;
 
-               sd = kzalloc(disk_link.len, GFP_NOFS);
+               sd = f2fs_kzalloc(sbi, disk_link.len, GFP_NOFS);
                if (!sd) {
                        err = -ENOMEM;
                        goto err_out;
@@ -797,18 +787,6 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (unlikely(f2fs_cp_error(sbi)))
                return -EIO;
 
-       if ((f2fs_encrypted_inode(old_dir) &&
-                       !fscrypt_has_encryption_key(old_dir)) ||
-                       (f2fs_encrypted_inode(new_dir) &&
-                       !fscrypt_has_encryption_key(new_dir)))
-               return -ENOKEY;
-
-       if ((old_dir != new_dir) && f2fs_encrypted_inode(new_dir) &&
-                       !fscrypt_has_permitted_context(new_dir, old_inode)) {
-               err = -EPERM;
-               goto out;
-       }
-
        if (is_inode_flag_set(new_dir, FI_PROJ_INHERIT) &&
                        (!projid_eq(F2FS_I(new_dir)->i_projid,
                        F2FS_I(old_dentry->d_inode)->i_projid)))
@@ -955,6 +933,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
                }
                f2fs_i_links_write(old_dir, false);
        }
+       add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO);
 
        f2fs_unlock_op(sbi);
 
@@ -999,18 +978,6 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (unlikely(f2fs_cp_error(sbi)))
                return -EIO;
 
-       if ((f2fs_encrypted_inode(old_dir) &&
-                       !fscrypt_has_encryption_key(old_dir)) ||
-                       (f2fs_encrypted_inode(new_dir) &&
-                       !fscrypt_has_encryption_key(new_dir)))
-               return -ENOKEY;
-
-       if ((f2fs_encrypted_inode(old_dir) || f2fs_encrypted_inode(new_dir)) &&
-                       (old_dir != new_dir) &&
-                       (!fscrypt_has_permitted_context(new_dir, old_inode) ||
-                        !fscrypt_has_permitted_context(old_dir, new_inode)))
-               return -EPERM;
-
        if ((is_inode_flag_set(new_dir, FI_PROJ_INHERIT) &&
                        !projid_eq(F2FS_I(new_dir)->i_projid,
                        F2FS_I(old_dentry->d_inode)->i_projid)) ||
@@ -1121,6 +1088,9 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
        }
        f2fs_mark_inode_dirty_sync(new_dir, false);
 
+       add_ino_entry(sbi, old_dir->i_ino, TRANS_DIR_INO);
+       add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO);
+
        f2fs_unlock_op(sbi);
 
        if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir))
@@ -1150,9 +1120,16 @@ static int f2fs_rename2(struct inode *old_dir, struct dentry *old_dentry,
                        struct inode *new_dir, struct dentry *new_dentry,
                        unsigned int flags)
 {
+       int err;
+
        if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
                return -EINVAL;
 
+       err = fscrypt_prepare_rename(old_dir, old_dentry, new_dir, new_dentry,
+                                    flags);
+       if (err)
+               return err;
+
        if (flags & RENAME_EXCHANGE) {
                return f2fs_cross_rename(old_dir, old_dentry,
                                         new_dir, new_dentry);
index 964c996..c294d0f 100644 (file)
@@ -143,11 +143,9 @@ static struct nat_entry *__alloc_nat_entry(nid_t nid, bool no_fail)
        struct nat_entry *new;
 
        if (no_fail)
-               new = f2fs_kmem_cache_alloc(nat_entry_slab,
-                                               GFP_NOFS | __GFP_ZERO);
+               new = f2fs_kmem_cache_alloc(nat_entry_slab, GFP_F2FS_ZERO);
        else
-               new = kmem_cache_alloc(nat_entry_slab,
-                                               GFP_NOFS | __GFP_ZERO);
+               new = kmem_cache_alloc(nat_entry_slab, GFP_F2FS_ZERO);
        if (new) {
                nat_set_nid(new, nid);
                nat_reset_flag(new);
@@ -702,7 +700,6 @@ static void truncate_node(struct dnode_of_data *dn)
        struct node_info ni;
 
        get_node_info(sbi, dn->nid, &ni);
-       f2fs_bug_on(sbi, ni.blk_addr == NULL_ADDR);
 
        /* Deallocate node address */
        invalidate_blocks(sbi, ni.blk_addr);
@@ -1340,14 +1337,19 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted,
                .encrypted_page = NULL,
                .submitted = false,
                .io_type = io_type,
+               .io_wbc = wbc,
        };
 
        trace_f2fs_writepage(page, NODE);
 
+       if (unlikely(f2fs_cp_error(sbi))) {
+               dec_page_count(sbi, F2FS_DIRTY_NODES);
+               unlock_page(page);
+               return 0;
+       }
+
        if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
                goto redirty_out;
-       if (unlikely(f2fs_cp_error(sbi)))
-               goto redirty_out;
 
        /* get old block addr of this node page */
        nid = nid_of_node(page);
@@ -1592,12 +1594,6 @@ next_step:
                        struct page *page = pvec.pages[i];
                        bool submitted = false;
 
-                       if (unlikely(f2fs_cp_error(sbi))) {
-                               pagevec_release(&pvec);
-                               ret = -EIO;
-                               goto out;
-                       }
-
                        /*
                         * flushing sequence with step:
                         * 0. indirect nodes
@@ -1667,9 +1663,12 @@ continue_unlock:
                step++;
                goto next_step;
        }
-out:
+
        if (nwritten)
                f2fs_submit_merged_write(sbi, NODE);
+
+       if (unlikely(f2fs_cp_error(sbi)))
+               return -EIO;
        return ret;
 }
 
@@ -1834,8 +1833,33 @@ static void __move_free_nid(struct f2fs_sb_info *sbi, struct free_nid *i,
        }
 }
 
+static void update_free_nid_bitmap(struct f2fs_sb_info *sbi, nid_t nid,
+                                                       bool set, bool build)
+{
+       struct f2fs_nm_info *nm_i = NM_I(sbi);
+       unsigned int nat_ofs = NAT_BLOCK_OFFSET(nid);
+       unsigned int nid_ofs = nid - START_NID(nid);
+
+       if (!test_bit_le(nat_ofs, nm_i->nat_block_bitmap))
+               return;
+
+       if (set) {
+               if (test_bit_le(nid_ofs, nm_i->free_nid_bitmap[nat_ofs]))
+                       return;
+               __set_bit_le(nid_ofs, nm_i->free_nid_bitmap[nat_ofs]);
+               nm_i->free_nid_count[nat_ofs]++;
+       } else {
+               if (!test_bit_le(nid_ofs, nm_i->free_nid_bitmap[nat_ofs]))
+                       return;
+               __clear_bit_le(nid_ofs, nm_i->free_nid_bitmap[nat_ofs]);
+               if (!build)
+                       nm_i->free_nid_count[nat_ofs]--;
+       }
+}
+
 /* return if the nid is recognized as free */
-static bool add_free_nid(struct f2fs_sb_info *sbi, nid_t nid, bool build)
+static bool add_free_nid(struct f2fs_sb_info *sbi,
+                               nid_t nid, bool build, bool update)
 {
        struct f2fs_nm_info *nm_i = NM_I(sbi);
        struct free_nid *i, *e;
@@ -1851,8 +1875,7 @@ static bool add_free_nid(struct f2fs_sb_info *sbi, nid_t nid, bool build)
        i->nid = nid;
        i->state = FREE_NID;
 
-       if (radix_tree_preload(GFP_NOFS))
-               goto err;
+       radix_tree_preload(GFP_NOFS | __GFP_NOFAIL);
 
        spin_lock(&nm_i->nid_list_lock);
 
@@ -1893,9 +1916,14 @@ static bool add_free_nid(struct f2fs_sb_info *sbi, nid_t nid, bool build)
        ret = true;
        err = __insert_free_nid(sbi, i, FREE_NID);
 err_out:
+       if (update) {
+               update_free_nid_bitmap(sbi, nid, ret, build);
+               if (!build)
+                       nm_i->available_nids++;
+       }
        spin_unlock(&nm_i->nid_list_lock);
        radix_tree_preload_end();
-err:
+
        if (err)
                kmem_cache_free(free_nid_slab, i);
        return ret;
@@ -1919,30 +1947,6 @@ static void remove_free_nid(struct f2fs_sb_info *sbi, nid_t nid)
                kmem_cache_free(free_nid_slab, i);
 }
 
-static void update_free_nid_bitmap(struct f2fs_sb_info *sbi, nid_t nid,
-                                                       bool set, bool build)
-{
-       struct f2fs_nm_info *nm_i = NM_I(sbi);
-       unsigned int nat_ofs = NAT_BLOCK_OFFSET(nid);
-       unsigned int nid_ofs = nid - START_NID(nid);
-
-       if (!test_bit_le(nat_ofs, nm_i->nat_block_bitmap))
-               return;
-
-       if (set) {
-               if (test_bit_le(nid_ofs, nm_i->free_nid_bitmap[nat_ofs]))
-                       return;
-               __set_bit_le(nid_ofs, nm_i->free_nid_bitmap[nat_ofs]);
-               nm_i->free_nid_count[nat_ofs]++;
-       } else {
-               if (!test_bit_le(nid_ofs, nm_i->free_nid_bitmap[nat_ofs]))
-                       return;
-               __clear_bit_le(nid_ofs, nm_i->free_nid_bitmap[nat_ofs]);
-               if (!build)
-                       nm_i->free_nid_count[nat_ofs]--;
-       }
-}
-
 static void scan_nat_page(struct f2fs_sb_info *sbi,
                        struct page *nat_page, nid_t start_nid)
 {
@@ -1952,26 +1956,23 @@ static void scan_nat_page(struct f2fs_sb_info *sbi,
        unsigned int nat_ofs = NAT_BLOCK_OFFSET(start_nid);
        int i;
 
-       if (test_bit_le(nat_ofs, nm_i->nat_block_bitmap))
-               return;
-
        __set_bit_le(nat_ofs, nm_i->nat_block_bitmap);
 
        i = start_nid % NAT_ENTRY_PER_BLOCK;
 
        for (; i < NAT_ENTRY_PER_BLOCK; i++, start_nid++) {
-               bool freed = false;
-
                if (unlikely(start_nid >= nm_i->max_nid))
                        break;
 
                blk_addr = le32_to_cpu(nat_blk->entries[i].block_addr);
                f2fs_bug_on(sbi, blk_addr == NEW_ADDR);
-               if (blk_addr == NULL_ADDR)
-                       freed = add_free_nid(sbi, start_nid, true);
-               spin_lock(&NM_I(sbi)->nid_list_lock);
-               update_free_nid_bitmap(sbi, start_nid, freed, true);
-               spin_unlock(&NM_I(sbi)->nid_list_lock);
+               if (blk_addr == NULL_ADDR) {
+                       add_free_nid(sbi, start_nid, true, true);
+               } else {
+                       spin_lock(&NM_I(sbi)->nid_list_lock);
+                       update_free_nid_bitmap(sbi, start_nid, false, true);
+                       spin_unlock(&NM_I(sbi)->nid_list_lock);
+               }
        }
 }
 
@@ -1989,7 +1990,7 @@ static void scan_curseg_cache(struct f2fs_sb_info *sbi)
                addr = le32_to_cpu(nat_in_journal(journal, i).block_addr);
                nid = le32_to_cpu(nid_in_journal(journal, i));
                if (addr == NULL_ADDR)
-                       add_free_nid(sbi, nid, true);
+                       add_free_nid(sbi, nid, true, false);
                else
                        remove_free_nid(sbi, nid);
        }
@@ -2016,7 +2017,7 @@ static void scan_free_nid_bits(struct f2fs_sb_info *sbi)
                                break;
 
                        nid = i * NAT_ENTRY_PER_BLOCK + idx;
-                       add_free_nid(sbi, nid, true);
+                       add_free_nid(sbi, nid, true, false);
 
                        if (nm_i->nid_cnt[FREE_NID] >= MAX_FREE_NIDS)
                                goto out;
@@ -2059,10 +2060,13 @@ static void __build_free_nids(struct f2fs_sb_info *sbi, bool sync, bool mount)
        down_read(&nm_i->nat_tree_lock);
 
        while (1) {
-               struct page *page = get_current_nat_page(sbi, nid);
+               if (!test_bit_le(NAT_BLOCK_OFFSET(nid),
+                                               nm_i->nat_block_bitmap)) {
+                       struct page *page = get_current_nat_page(sbi, nid);
 
-               scan_nat_page(sbi, page, nid);
-               f2fs_put_page(page, 1);
+                       scan_nat_page(sbi, page, nid);
+                       f2fs_put_page(page, 1);
+               }
 
                nid += (NAT_ENTRY_PER_BLOCK - (nid % NAT_ENTRY_PER_BLOCK));
                if (unlikely(nid >= nm_i->max_nid))
@@ -2225,7 +2229,9 @@ void recover_inline_xattr(struct inode *inode, struct page *page)
        f2fs_bug_on(F2FS_I_SB(inode), IS_ERR(ipage));
 
        ri = F2FS_INODE(page);
-       if (!(ri->i_inline & F2FS_INLINE_XATTR)) {
+       if (ri->i_inline & F2FS_INLINE_XATTR) {
+               set_inode_flag(inode, FI_INLINE_XATTR);
+       } else {
                clear_inode_flag(inode, FI_INLINE_XATTR);
                goto update_inode;
        }
@@ -2241,7 +2247,7 @@ update_inode:
        f2fs_put_page(ipage, 1);
 }
 
-int recover_xattr_data(struct inode *inode, struct page *page, block_t blkaddr)
+int recover_xattr_data(struct inode *inode, struct page *page)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
        nid_t prev_xnid = F2FS_I(inode)->i_xattr_nid;
@@ -2255,7 +2261,6 @@ int recover_xattr_data(struct inode *inode, struct page *page, block_t blkaddr)
 
        /* 1: invalidate the previous xattr nid */
        get_node_info(sbi, prev_xnid, &ni);
-       f2fs_bug_on(sbi, ni.blk_addr == NULL_ADDR);
        invalidate_blocks(sbi, ni.blk_addr);
        dec_valid_node_count(sbi, inode, false);
        set_node_addr(sbi, &ni, NULL_ADDR, false);
@@ -2344,7 +2349,7 @@ retry:
        return 0;
 }
 
-int restore_node_summary(struct f2fs_sb_info *sbi,
+void restore_node_summary(struct f2fs_sb_info *sbi,
                        unsigned int segno, struct f2fs_summary_block *sum)
 {
        struct f2fs_node *rn;
@@ -2377,7 +2382,6 @@ int restore_node_summary(struct f2fs_sb_info *sbi,
                invalidate_mapping_pages(META_MAPPING(sbi), addr,
                                                        addr + nrpages);
        }
-       return 0;
 }
 
 static void remove_nats_in_journal(struct f2fs_sb_info *sbi)
@@ -2519,11 +2523,7 @@ static void __flush_nat_entry_set(struct f2fs_sb_info *sbi,
                nat_reset_flag(ne);
                __clear_nat_cache_dirty(NM_I(sbi), set, ne);
                if (nat_get_blkaddr(ne) == NULL_ADDR) {
-                       add_free_nid(sbi, nid, false);
-                       spin_lock(&NM_I(sbi)->nid_list_lock);
-                       NM_I(sbi)->available_nids++;
-                       update_free_nid_bitmap(sbi, nid, true, false);
-                       spin_unlock(&NM_I(sbi)->nid_list_lock);
+                       add_free_nid(sbi, nid, false, true);
                } else {
                        spin_lock(&NM_I(sbi)->nid_list_lock);
                        update_free_nid_bitmap(sbi, nid, false, false);
@@ -2604,8 +2604,8 @@ static int __get_nat_bitmaps(struct f2fs_sb_info *sbi)
 
        nm_i->nat_bits_blocks = F2FS_BYTES_TO_BLK((nat_bits_bytes << 1) + 8 +
                                                F2FS_BLKSIZE - 1);
-       nm_i->nat_bits = kzalloc(nm_i->nat_bits_blocks << F2FS_BLKSIZE_BITS,
-                                               GFP_KERNEL);
+       nm_i->nat_bits = f2fs_kzalloc(sbi,
+                       nm_i->nat_bits_blocks << F2FS_BLKSIZE_BITS, GFP_KERNEL);
        if (!nm_i->nat_bits)
                return -ENOMEM;
 
@@ -2683,7 +2683,7 @@ static int init_node_manager(struct f2fs_sb_info *sbi)
 
        /* not used nids: 0, node, meta, (and root counted as valid node) */
        nm_i->available_nids = nm_i->max_nid - sbi->total_valid_node_count -
-                                                       F2FS_RESERVED_NODE_NUM;
+                               sbi->nquota_files - F2FS_RESERVED_NODE_NUM;
        nm_i->nid_cnt[FREE_NID] = 0;
        nm_i->nid_cnt[PREALLOC_NID] = 0;
        nm_i->nat_cnt = 0;
@@ -2730,17 +2730,17 @@ static int init_free_nid_cache(struct f2fs_sb_info *sbi)
 {
        struct f2fs_nm_info *nm_i = NM_I(sbi);
 
-       nm_i->free_nid_bitmap = kvzalloc(nm_i->nat_blocks *
+       nm_i->free_nid_bitmap = f2fs_kvzalloc(sbi, nm_i->nat_blocks *
                                        NAT_ENTRY_BITMAP_SIZE, GFP_KERNEL);
        if (!nm_i->free_nid_bitmap)
                return -ENOMEM;
 
-       nm_i->nat_block_bitmap = kvzalloc(nm_i->nat_blocks / 8,
+       nm_i->nat_block_bitmap = f2fs_kvzalloc(sbi, nm_i->nat_blocks / 8,
                                                                GFP_KERNEL);
        if (!nm_i->nat_block_bitmap)
                return -ENOMEM;
 
-       nm_i->free_nid_count = kvzalloc(nm_i->nat_blocks *
+       nm_i->free_nid_count = f2fs_kvzalloc(sbi, nm_i->nat_blocks *
                                        sizeof(unsigned short), GFP_KERNEL);
        if (!nm_i->free_nid_count)
                return -ENOMEM;
@@ -2751,7 +2751,8 @@ int build_node_manager(struct f2fs_sb_info *sbi)
 {
        int err;
 
-       sbi->nm_info = kzalloc(sizeof(struct f2fs_nm_info), GFP_KERNEL);
+       sbi->nm_info = f2fs_kzalloc(sbi, sizeof(struct f2fs_nm_info),
+                                                       GFP_KERNEL);
        if (!sbi->nm_info)
                return -ENOMEM;
 
index 0ee3e5f..081ef0d 100644 (file)
@@ -305,6 +305,10 @@ static inline bool is_recoverable_dnode(struct page *page)
        struct f2fs_checkpoint *ckpt = F2FS_CKPT(F2FS_P_SB(page));
        __u64 cp_ver = cur_cp_version(ckpt);
 
+       /* Don't care crc part, if fsck.f2fs sets it. */
+       if (__is_set_ckpt_flags(ckpt, CP_NOCRC_RECOVERY_FLAG))
+               return (cp_ver << 32) == (cpver_of_node(page) << 32);
+
        if (__is_set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG))
                cp_ver |= (cur_cp_crc(ckpt) << 32);
 
index 92c57ac..b6d1ec6 100644 (file)
@@ -195,6 +195,20 @@ out:
        return err;
 }
 
+static void recover_inline_flags(struct inode *inode, struct f2fs_inode *ri)
+{
+       if (ri->i_inline & F2FS_PIN_FILE)
+               set_inode_flag(inode, FI_PIN_FILE);
+       else
+               clear_inode_flag(inode, FI_PIN_FILE);
+       if (ri->i_inline & F2FS_DATA_EXIST)
+               set_inode_flag(inode, FI_DATA_EXIST);
+       else
+               clear_inode_flag(inode, FI_DATA_EXIST);
+       if (!(ri->i_inline & F2FS_INLINE_DOTS))
+               clear_inode_flag(inode, FI_INLINE_DOTS);
+}
+
 static void recover_inode(struct inode *inode, struct page *page)
 {
        struct f2fs_inode *raw = F2FS_INODE(page);
@@ -211,13 +225,16 @@ static void recover_inode(struct inode *inode, struct page *page)
 
        F2FS_I(inode)->i_advise = raw->i_advise;
 
+       recover_inline_flags(inode, raw);
+
        if (file_enc_name(inode))
                name = "<encrypted>";
        else
                name = F2FS_INODE(page)->i_name;
 
-       f2fs_msg(inode->i_sb, KERN_NOTICE, "recover_inode: ino = %x, name = %s",
-                       ino_of_node(page), name);
+       f2fs_msg(inode->i_sb, KERN_NOTICE,
+               "recover_inode: ino = %x, name = %s, inline = %x",
+                       ino_of_node(page), name, raw->i_inline);
 }
 
 static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head,
@@ -404,7 +421,7 @@ truncate_out:
 }
 
 static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
-                                       struct page *page, block_t blkaddr)
+                                       struct page *page)
 {
        struct dnode_of_data dn;
        struct node_info ni;
@@ -415,7 +432,7 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
        if (IS_INODE(page)) {
                recover_inline_xattr(inode, page);
        } else if (f2fs_has_xattr_block(ofs_of_node(page))) {
-               err = recover_xattr_data(inode, page, blkaddr);
+               err = recover_xattr_data(inode, page);
                if (!err)
                        recovered++;
                goto out;
@@ -568,7 +585,7 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list,
                                break;
                        }
                }
-               err = do_recover_data(sbi, entry->inode, page, blkaddr);
+               err = do_recover_data(sbi, entry->inode, page);
                if (err) {
                        f2fs_put_page(page, 1);
                        break;
index 94939a5..bf98f6f 100644 (file)
@@ -248,7 +248,11 @@ retry:
                                goto next;
                        }
                        get_node_info(sbi, dn.nid, &ni);
-                       f2fs_replace_block(sbi, &dn, dn.data_blkaddr,
+                       if (cur->old_addr == NEW_ADDR) {
+                               invalidate_blocks(sbi, dn.data_blkaddr);
+                               f2fs_update_data_blkaddr(&dn, NEW_ADDR);
+                       } else
+                               f2fs_replace_block(sbi, &dn, dn.data_blkaddr,
                                        cur->old_addr, ni.version, true, true);
                        f2fs_put_dnode(&dn);
                }
@@ -657,7 +661,7 @@ int create_flush_cmd_control(struct f2fs_sb_info *sbi)
                goto init_thread;
        }
 
-       fcc = kzalloc(sizeof(struct flush_cmd_control), GFP_KERNEL);
+       fcc = f2fs_kzalloc(sbi, sizeof(struct flush_cmd_control), GFP_KERNEL);
        if (!fcc)
                return -ENOMEM;
        atomic_set(&fcc->issued_flush, 0);
@@ -965,7 +969,7 @@ static int __blkdev_issue_discard(struct block_device *bdev, sector_t sector,
        return 0;
 }
 
-void __check_sit_bitmap(struct f2fs_sb_info *sbi,
+static void __check_sit_bitmap(struct f2fs_sb_info *sbi,
                                block_t start, block_t end)
 {
 #ifdef CONFIG_F2FS_CHECK_FS
@@ -1284,6 +1288,8 @@ static int __issue_discard_cmd(struct f2fs_sb_info *sbi,
                pend_list = &dcc->pend_list[i];
 
                mutex_lock(&dcc->cmd_lock);
+               if (list_empty(pend_list))
+                       goto next;
                f2fs_bug_on(sbi, !__check_rb_tree_consistence(sbi, &dcc->root));
                blk_start_plug(&plug);
                list_for_each_entry_safe(dc, tmp, pend_list, list) {
@@ -1302,6 +1308,7 @@ skip:
                                break;
                }
                blk_finish_plug(&plug);
+next:
                mutex_unlock(&dcc->cmd_lock);
 
                if (iter >= dpolicy->max_requests)
@@ -1336,6 +1343,11 @@ static bool __drop_discard_cmd(struct f2fs_sb_info *sbi)
        return dropped;
 }
 
+void drop_discard_cmd(struct f2fs_sb_info *sbi)
+{
+       __drop_discard_cmd(sbi);
+}
+
 static unsigned int __wait_one_discard_bio(struct f2fs_sb_info *sbi,
                                                        struct discard_cmd *dc)
 {
@@ -1404,7 +1416,7 @@ static void __wait_all_discard_cmd(struct f2fs_sb_info *sbi,
 }
 
 /* This should be covered by global mutex, &sit_i->sentry_lock */
-void f2fs_wait_discard_bio(struct f2fs_sb_info *sbi, block_t blkaddr)
+static void f2fs_wait_discard_bio(struct f2fs_sb_info *sbi, block_t blkaddr)
 {
        struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
        struct discard_cmd *dc;
@@ -1474,6 +1486,8 @@ static int issue_discard_thread(void *data)
                                msecs_to_jiffies(wait_ms));
                if (try_to_freeze())
                        continue;
+               if (f2fs_readonly(sbi->sb))
+                       continue;
                if (kthread_should_stop())
                        return 0;
 
@@ -1783,25 +1797,20 @@ void init_discard_policy(struct discard_policy *dpolicy,
        dpolicy->sync = true;
        dpolicy->granularity = granularity;
 
+       dpolicy->max_requests = DEF_MAX_DISCARD_REQUEST;
+       dpolicy->io_aware_gran = MAX_PLIST_NUM;
+
        if (discard_type == DPOLICY_BG) {
                dpolicy->min_interval = DEF_MIN_DISCARD_ISSUE_TIME;
                dpolicy->max_interval = DEF_MAX_DISCARD_ISSUE_TIME;
-               dpolicy->max_requests = DEF_MAX_DISCARD_REQUEST;
-               dpolicy->io_aware_gran = MAX_PLIST_NUM;
                dpolicy->io_aware = true;
        } else if (discard_type == DPOLICY_FORCE) {
                dpolicy->min_interval = DEF_MIN_DISCARD_ISSUE_TIME;
                dpolicy->max_interval = DEF_MAX_DISCARD_ISSUE_TIME;
-               dpolicy->max_requests = DEF_MAX_DISCARD_REQUEST;
-               dpolicy->io_aware_gran = MAX_PLIST_NUM;
                dpolicy->io_aware = true;
        } else if (discard_type == DPOLICY_FSTRIM) {
-               dpolicy->max_requests = DEF_MAX_DISCARD_REQUEST;
-               dpolicy->io_aware_gran = MAX_PLIST_NUM;
                dpolicy->io_aware = false;
        } else if (discard_type == DPOLICY_UMOUNT) {
-               dpolicy->max_requests = DEF_MAX_DISCARD_REQUEST;
-               dpolicy->io_aware_gran = MAX_PLIST_NUM;
                dpolicy->io_aware = false;
        }
 }
@@ -1817,7 +1826,7 @@ static int create_discard_cmd_control(struct f2fs_sb_info *sbi)
                goto init_thread;
        }
 
-       dcc = kzalloc(sizeof(struct discard_cmd_control), GFP_KERNEL);
+       dcc = f2fs_kzalloc(sbi, sizeof(struct discard_cmd_control), GFP_KERNEL);
        if (!dcc)
                return -ENOMEM;
 
@@ -2514,7 +2523,6 @@ static bool __has_curseg_space(struct f2fs_sb_info *sbi, int type)
        return false;
 }
 
-#if 0
 int rw_hint_to_seg_type(enum rw_hint hint)
 {
        switch (hint) {
@@ -2526,7 +2534,6 @@ int rw_hint_to_seg_type(enum rw_hint hint)
                return CURSEG_WARM_DATA;
        }
 }
-#endif
 
 static int __get_segment_type_2(struct f2fs_io_info *fio)
 {
@@ -2822,6 +2829,7 @@ void __f2fs_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
                }
        }
 
+       f2fs_bug_on(sbi, !IS_DATASEG(type));
        curseg = CURSEG_I(sbi, type);
 
        mutex_lock(&curseg->curseg_mutex);
@@ -2906,7 +2914,7 @@ void f2fs_wait_on_block_writeback(struct f2fs_sb_info *sbi, block_t blkaddr)
        }
 }
 
-static int read_compacted_summaries(struct f2fs_sb_info *sbi)
+static void read_compacted_summaries(struct f2fs_sb_info *sbi)
 {
        struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
        struct curseg_info *seg_i;
@@ -2963,7 +2971,6 @@ static int read_compacted_summaries(struct f2fs_sb_info *sbi)
                }
        }
        f2fs_put_page(page, 1);
-       return 0;
 }
 
 static int read_normal_summaries(struct f2fs_sb_info *sbi, int type)
@@ -3009,13 +3016,7 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type)
                                ns->ofs_in_node = 0;
                        }
                } else {
-                       int err;
-
-                       err = restore_node_summary(sbi, segno, sum);
-                       if (err) {
-                               f2fs_put_page(new, 1);
-                               return err;
-                       }
+                       restore_node_summary(sbi, segno, sum);
                }
        }
 
@@ -3054,8 +3055,7 @@ static int restore_curseg_summaries(struct f2fs_sb_info *sbi)
                                                        META_CP, true);
 
                /* restore for compacted data summary */
-               if (read_compacted_summaries(sbi))
-                       return -EINVAL;
+               read_compacted_summaries(sbi);
                type = CURSEG_HOT_NODE;
        }
 
@@ -3191,28 +3191,19 @@ static struct page *get_next_sit_page(struct f2fs_sb_info *sbi,
                                        unsigned int start)
 {
        struct sit_info *sit_i = SIT_I(sbi);
-       struct page *src_page, *dst_page;
+       struct page *page;
        pgoff_t src_off, dst_off;
-       void *src_addr, *dst_addr;
 
        src_off = current_sit_addr(sbi, start);
        dst_off = next_sit_addr(sbi, src_off);
 
-       /* get current sit block page without lock */
-       src_page = get_meta_page(sbi, src_off);
-       dst_page = grab_meta_page(sbi, dst_off);
-       f2fs_bug_on(sbi, PageDirty(src_page));
-
-       src_addr = page_address(src_page);
-       dst_addr = page_address(dst_page);
-       memcpy(dst_addr, src_addr, PAGE_SIZE);
-
-       set_page_dirty(dst_page);
-       f2fs_put_page(src_page, 1);
+       page = grab_meta_page(sbi, dst_off);
+       seg_info_to_sit_page(sbi, page, start);
 
+       set_page_dirty(page);
        set_to_next_sit(sit_i, start);
 
-       return dst_page;
+       return page;
 }
 
 static struct sit_entry_set *grab_sit_entry_set(void)
@@ -3421,52 +3412,54 @@ static int build_sit_info(struct f2fs_sb_info *sbi)
        unsigned int bitmap_size;
 
        /* allocate memory for SIT information */
-       sit_i = kzalloc(sizeof(struct sit_info), GFP_KERNEL);
+       sit_i = f2fs_kzalloc(sbi, sizeof(struct sit_info), GFP_KERNEL);
        if (!sit_i)
                return -ENOMEM;
 
        SM_I(sbi)->sit_info = sit_i;
 
-       sit_i->sentries = kvzalloc(MAIN_SEGS(sbi) *
+       sit_i->sentries = f2fs_kvzalloc(sbi, MAIN_SEGS(sbi) *
                                        sizeof(struct seg_entry), GFP_KERNEL);
        if (!sit_i->sentries)
                return -ENOMEM;
 
        bitmap_size = f2fs_bitmap_size(MAIN_SEGS(sbi));
-       sit_i->dirty_sentries_bitmap = kvzalloc(bitmap_size, GFP_KERNEL);
+       sit_i->dirty_sentries_bitmap = f2fs_kvzalloc(sbi, bitmap_size,
+                                                               GFP_KERNEL);
        if (!sit_i->dirty_sentries_bitmap)
                return -ENOMEM;
 
        for (start = 0; start < MAIN_SEGS(sbi); start++) {
                sit_i->sentries[start].cur_valid_map
-                       = kzalloc(SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
+                       = f2fs_kzalloc(sbi, SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
                sit_i->sentries[start].ckpt_valid_map
-                       = kzalloc(SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
+                       = f2fs_kzalloc(sbi, SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
                if (!sit_i->sentries[start].cur_valid_map ||
                                !sit_i->sentries[start].ckpt_valid_map)
                        return -ENOMEM;
 
 #ifdef CONFIG_F2FS_CHECK_FS
                sit_i->sentries[start].cur_valid_map_mir
-                       = kzalloc(SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
+                       = f2fs_kzalloc(sbi, SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
                if (!sit_i->sentries[start].cur_valid_map_mir)
                        return -ENOMEM;
 #endif
 
                if (f2fs_discard_en(sbi)) {
                        sit_i->sentries[start].discard_map
-                               = kzalloc(SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
+                               = f2fs_kzalloc(sbi, SIT_VBLOCK_MAP_SIZE,
+                                                               GFP_KERNEL);
                        if (!sit_i->sentries[start].discard_map)
                                return -ENOMEM;
                }
        }
 
-       sit_i->tmp_map = kzalloc(SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
+       sit_i->tmp_map = f2fs_kzalloc(sbi, SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
        if (!sit_i->tmp_map)
                return -ENOMEM;
 
        if (sbi->segs_per_sec > 1) {
-               sit_i->sec_entries = kvzalloc(MAIN_SECS(sbi) *
+               sit_i->sec_entries = f2fs_kvzalloc(sbi, MAIN_SECS(sbi) *
                                        sizeof(struct sec_entry), GFP_KERNEL);
                if (!sit_i->sec_entries)
                        return -ENOMEM;
@@ -3510,19 +3503,19 @@ static int build_free_segmap(struct f2fs_sb_info *sbi)
        unsigned int bitmap_size, sec_bitmap_size;
 
        /* allocate memory for free segmap information */
-       free_i = kzalloc(sizeof(struct free_segmap_info), GFP_KERNEL);
+       free_i = f2fs_kzalloc(sbi, sizeof(struct free_segmap_info), GFP_KERNEL);
        if (!free_i)
                return -ENOMEM;
 
        SM_I(sbi)->free_info = free_i;
 
        bitmap_size = f2fs_bitmap_size(MAIN_SEGS(sbi));
-       free_i->free_segmap = kvmalloc(bitmap_size, GFP_KERNEL);
+       free_i->free_segmap = f2fs_kvmalloc(sbi, bitmap_size, GFP_KERNEL);
        if (!free_i->free_segmap)
                return -ENOMEM;
 
        sec_bitmap_size = f2fs_bitmap_size(MAIN_SECS(sbi));
-       free_i->free_secmap = kvmalloc(sec_bitmap_size, GFP_KERNEL);
+       free_i->free_secmap = f2fs_kvmalloc(sbi, sec_bitmap_size, GFP_KERNEL);
        if (!free_i->free_secmap)
                return -ENOMEM;
 
@@ -3543,7 +3536,7 @@ static int build_curseg(struct f2fs_sb_info *sbi)
        struct curseg_info *array;
        int i;
 
-       array = kcalloc(NR_CURSEG_TYPE, sizeof(*array), GFP_KERNEL);
+       array = f2fs_kzalloc(sbi, sizeof(*array) * NR_CURSEG_TYPE, GFP_KERNEL);
        if (!array)
                return -ENOMEM;
 
@@ -3551,12 +3544,12 @@ static int build_curseg(struct f2fs_sb_info *sbi)
 
        for (i = 0; i < NR_CURSEG_TYPE; i++) {
                mutex_init(&array[i].curseg_mutex);
-               array[i].sum_blk = kzalloc(PAGE_SIZE, GFP_KERNEL);
+               array[i].sum_blk = f2fs_kzalloc(sbi, PAGE_SIZE, GFP_KERNEL);
                if (!array[i].sum_blk)
                        return -ENOMEM;
                init_rwsem(&array[i].journal_rwsem);
-               array[i].journal = kzalloc(sizeof(struct f2fs_journal),
-                                                       GFP_KERNEL);
+               array[i].journal = f2fs_kzalloc(sbi,
+                               sizeof(struct f2fs_journal), GFP_KERNEL);
                if (!array[i].journal)
                        return -ENOMEM;
                array[i].segno = NULL_SEGNO;
@@ -3565,7 +3558,7 @@ static int build_curseg(struct f2fs_sb_info *sbi)
        return restore_curseg_summaries(sbi);
 }
 
-static void build_sit_entries(struct f2fs_sb_info *sbi)
+static int build_sit_entries(struct f2fs_sb_info *sbi)
 {
        struct sit_info *sit_i = SIT_I(sbi);
        struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA);
@@ -3575,6 +3568,7 @@ static void build_sit_entries(struct f2fs_sb_info *sbi)
        int sit_blk_cnt = SIT_BLK_CNT(sbi);
        unsigned int i, start, end;
        unsigned int readed, start_blk = 0;
+       int err = 0;
 
        do {
                readed = ra_meta_pages(sbi, start_blk, BIO_MAX_PAGES,
@@ -3593,7 +3587,9 @@ static void build_sit_entries(struct f2fs_sb_info *sbi)
                        sit = sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, start)];
                        f2fs_put_page(page, 1);
 
-                       check_block_count(sbi, start, &sit);
+                       err = check_block_count(sbi, start, &sit);
+                       if (err)
+                               return err;
                        seg_info_from_raw_sit(se, &sit);
 
                        /* build discard map only one time */
@@ -3628,7 +3624,9 @@ static void build_sit_entries(struct f2fs_sb_info *sbi)
 
                old_valid_blocks = se->valid_blocks;
 
-               check_block_count(sbi, start, &sit);
+               err = check_block_count(sbi, start, &sit);
+               if (err)
+                       break;
                seg_info_from_raw_sit(se, &sit);
 
                if (f2fs_discard_en(sbi)) {
@@ -3648,6 +3646,7 @@ static void build_sit_entries(struct f2fs_sb_info *sbi)
                                se->valid_blocks - old_valid_blocks;
        }
        up_read(&curseg->journal_rwsem);
+       return err;
 }
 
 static void init_free_segmap(struct f2fs_sb_info *sbi)
@@ -3702,7 +3701,7 @@ static int init_victim_secmap(struct f2fs_sb_info *sbi)
        struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
        unsigned int bitmap_size = f2fs_bitmap_size(MAIN_SECS(sbi));
 
-       dirty_i->victim_secmap = kvzalloc(bitmap_size, GFP_KERNEL);
+       dirty_i->victim_secmap = f2fs_kvzalloc(sbi, bitmap_size, GFP_KERNEL);
        if (!dirty_i->victim_secmap)
                return -ENOMEM;
        return 0;
@@ -3714,7 +3713,8 @@ static int build_dirty_segmap(struct f2fs_sb_info *sbi)
        unsigned int bitmap_size, i;
 
        /* allocate memory for dirty segments list information */
-       dirty_i = kzalloc(sizeof(struct dirty_seglist_info), GFP_KERNEL);
+       dirty_i = f2fs_kzalloc(sbi, sizeof(struct dirty_seglist_info),
+                                                               GFP_KERNEL);
        if (!dirty_i)
                return -ENOMEM;
 
@@ -3724,7 +3724,8 @@ static int build_dirty_segmap(struct f2fs_sb_info *sbi)
        bitmap_size = f2fs_bitmap_size(MAIN_SEGS(sbi));
 
        for (i = 0; i < NR_DIRTY_TYPE; i++) {
-               dirty_i->dirty_segmap[i] = kvzalloc(bitmap_size, GFP_KERNEL);
+               dirty_i->dirty_segmap[i] = f2fs_kvzalloc(sbi, bitmap_size,
+                                                               GFP_KERNEL);
                if (!dirty_i->dirty_segmap[i])
                        return -ENOMEM;
        }
@@ -3768,7 +3769,7 @@ int build_segment_manager(struct f2fs_sb_info *sbi)
        struct f2fs_sm_info *sm_info;
        int err;
 
-       sm_info = kzalloc(sizeof(struct f2fs_sm_info), GFP_KERNEL);
+       sm_info = f2fs_kzalloc(sbi, sizeof(struct f2fs_sm_info), GFP_KERNEL);
        if (!sm_info)
                return -ENOMEM;
 
@@ -3820,7 +3821,9 @@ int build_segment_manager(struct f2fs_sb_info *sbi)
                return err;
 
        /* reinit free segmap based on SIT */
-       build_sit_entries(sbi);
+       err = build_sit_entries(sbi);
+       if (err)
+               return err;
 
        init_free_segmap(sbi);
        err = build_dirty_segmap(sbi);
index 5264b6e..5d6d3e7 100644 (file)
@@ -348,16 +348,41 @@ static inline void seg_info_from_raw_sit(struct seg_entry *se,
        se->mtime = le64_to_cpu(rs->mtime);
 }
 
-static inline void seg_info_to_raw_sit(struct seg_entry *se,
+static inline void __seg_info_to_raw_sit(struct seg_entry *se,
                                        struct f2fs_sit_entry *rs)
 {
        unsigned short raw_vblocks = (se->type << SIT_VBLOCKS_SHIFT) |
                                        se->valid_blocks;
        rs->vblocks = cpu_to_le16(raw_vblocks);
        memcpy(rs->valid_map, se->cur_valid_map, SIT_VBLOCK_MAP_SIZE);
+       rs->mtime = cpu_to_le64(se->mtime);
+}
+
+static inline void seg_info_to_sit_page(struct f2fs_sb_info *sbi,
+                               struct page *page, unsigned int start)
+{
+       struct f2fs_sit_block *raw_sit;
+       struct seg_entry *se;
+       struct f2fs_sit_entry *rs;
+       unsigned int end = min(start + SIT_ENTRY_PER_BLOCK,
+                                       (unsigned long)MAIN_SEGS(sbi));
+       int i;
+
+       raw_sit = (struct f2fs_sit_block *)page_address(page);
+       for (i = 0; i < end - start; i++) {
+               rs = &raw_sit->entries[i];
+               se = get_seg_entry(sbi, start + i);
+               __seg_info_to_raw_sit(se, rs);
+       }
+}
+
+static inline void seg_info_to_raw_sit(struct seg_entry *se,
+                                       struct f2fs_sit_entry *rs)
+{
+       __seg_info_to_raw_sit(se, rs);
+
        memcpy(se->ckpt_valid_map, rs->valid_map, SIT_VBLOCK_MAP_SIZE);
        se->ckpt_valid_blocks = se->valid_blocks;
-       rs->mtime = cpu_to_le64(se->mtime);
 }
 
 static inline unsigned int find_next_inuse(struct free_segmap_info *free_i,
@@ -580,47 +605,6 @@ enum {
        F2FS_IPU_ASYNC,
 };
 
-static inline bool need_inplace_update_policy(struct inode *inode,
-                               struct f2fs_io_info *fio)
-{
-       struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
-       unsigned int policy = SM_I(sbi)->ipu_policy;
-
-       if (test_opt(sbi, LFS))
-               return false;
-
-       /* if this is cold file, we should overwrite to avoid fragmentation */
-       if (file_is_cold(inode))
-               return true;
-
-       if (policy & (0x1 << F2FS_IPU_FORCE))
-               return true;
-       if (policy & (0x1 << F2FS_IPU_SSR) && need_SSR(sbi))
-               return true;
-       if (policy & (0x1 << F2FS_IPU_UTIL) &&
-                       utilization(sbi) > SM_I(sbi)->min_ipu_util)
-               return true;
-       if (policy & (0x1 << F2FS_IPU_SSR_UTIL) && need_SSR(sbi) &&
-                       utilization(sbi) > SM_I(sbi)->min_ipu_util)
-               return true;
-
-       /*
-        * IPU for rewrite async pages
-        */
-       if (policy & (0x1 << F2FS_IPU_ASYNC) &&
-                       fio && fio->op == REQ_OP_WRITE &&
-                       !(fio->op_flags & REQ_SYNC) &&
-                       !f2fs_encrypted_inode(inode))
-               return true;
-
-       /* this is only set during fdatasync */
-       if (policy & (0x1 << F2FS_IPU_FSYNC) &&
-                       is_inode_flag_set(inode, FI_NEED_IPU))
-               return true;
-
-       return false;
-}
-
 static inline unsigned int curseg_segno(struct f2fs_sb_info *sbi,
                int type)
 {
@@ -655,7 +639,7 @@ static inline void verify_block_addr(struct f2fs_sb_info *sbi, block_t blk_addr)
 /*
  * Summary block is always treated as an invalid block
  */
-static inline void check_block_count(struct f2fs_sb_info *sbi,
+static inline int check_block_count(struct f2fs_sb_info *sbi,
                int segno, struct f2fs_sit_entry *raw_sit)
 {
 #ifdef CONFIG_F2FS_CHECK_FS
@@ -677,11 +661,25 @@ static inline void check_block_count(struct f2fs_sb_info *sbi,
                cur_pos = next_pos;
                is_valid = !is_valid;
        } while (cur_pos < sbi->blocks_per_seg);
-       BUG_ON(GET_SIT_VBLOCKS(raw_sit) != valid_blocks);
+
+       if (unlikely(GET_SIT_VBLOCKS(raw_sit) != valid_blocks)) {
+               f2fs_msg(sbi->sb, KERN_ERR,
+                               "Mismatch valid blocks %d vs. %d",
+                                       GET_SIT_VBLOCKS(raw_sit), valid_blocks);
+               set_sbi_flag(sbi, SBI_NEED_FSCK);
+               return -EINVAL;
+       }
 #endif
        /* check segment usage, and check boundary of a given segment number */
-       f2fs_bug_on(sbi, GET_SIT_VBLOCKS(raw_sit) > sbi->blocks_per_seg
-                                       || segno > TOTAL_SEGS(sbi) - 1);
+       if (unlikely(GET_SIT_VBLOCKS(raw_sit) > sbi->blocks_per_seg
+                                       || segno > TOTAL_SEGS(sbi) - 1)) {
+               f2fs_msg(sbi->sb, KERN_ERR,
+                               "Wrong valid blocks %d or segno %u",
+                                       GET_SIT_VBLOCKS(raw_sit), segno);
+               set_sbi_flag(sbi, SBI_NEED_FSCK);
+               return -EINVAL;
+       }
+       return 0;
 }
 
 static inline pgoff_t current_sit_addr(struct f2fs_sb_info *sbi,
index 187cead..aaeba34 100644 (file)
@@ -43,6 +43,7 @@ static struct kmem_cache *f2fs_inode_cachep;
 
 char *fault_name[FAULT_MAX] = {
        [FAULT_KMALLOC]         = "kmalloc",
+       [FAULT_KVMALLOC]        = "kvmalloc",
        [FAULT_PAGE_ALLOC]      = "page alloc",
        [FAULT_PAGE_GET]        = "page get",
        [FAULT_ALLOC_BIO]       = "alloc bio",
@@ -106,6 +107,9 @@ enum {
        Opt_noextent_cache,
        Opt_noinline_data,
        Opt_data_flush,
+       Opt_reserve_root,
+       Opt_resgid,
+       Opt_resuid,
        Opt_mode,
        Opt_io_size_bits,
        Opt_fault_injection,
@@ -156,6 +160,9 @@ static match_table_t f2fs_tokens = {
        {Opt_noextent_cache, "noextent_cache"},
        {Opt_noinline_data, "noinline_data"},
        {Opt_data_flush, "data_flush"},
+       {Opt_reserve_root, "reserve_root=%u"},
+       {Opt_resgid, "resgid=%u"},
+       {Opt_resuid, "resuid=%u"},
        {Opt_mode, "mode=%s"},
        {Opt_io_size_bits, "io_bits=%u"},
        {Opt_fault_injection, "fault_injection=%u"},
@@ -190,6 +197,28 @@ void f2fs_msg(struct super_block *sb, const char *level, const char *fmt, ...)
        va_end(args);
 }
 
+static inline void limit_reserve_root(struct f2fs_sb_info *sbi)
+{
+       block_t limit = (sbi->user_block_count << 1) / 1000;
+
+       /* limit is 0.2% */
+       if (test_opt(sbi, RESERVE_ROOT) && sbi->root_reserved_blocks > limit) {
+               sbi->root_reserved_blocks = limit;
+               f2fs_msg(sbi->sb, KERN_INFO,
+                       "Reduce reserved blocks for root = %u",
+                               sbi->root_reserved_blocks);
+       }
+       if (!test_opt(sbi, RESERVE_ROOT) &&
+               (!uid_eq(sbi->s_resuid,
+                               make_kuid(&init_user_ns, F2FS_DEF_RESUID)) ||
+               !gid_eq(sbi->s_resgid,
+                               make_kgid(&init_user_ns, F2FS_DEF_RESGID))))
+               f2fs_msg(sbi->sb, KERN_INFO,
+                       "Ignore s_resuid=%u, s_resgid=%u w/o reserve_root",
+                               from_kuid_munged(&init_user_ns, sbi->s_resuid),
+                               from_kgid_munged(&init_user_ns, sbi->s_resgid));
+}
+
 static void init_once(void *foo)
 {
        struct f2fs_inode_info *fi = (struct f2fs_inode_info *) foo;
@@ -320,6 +349,8 @@ static int parse_options(struct super_block *sb, char *options)
        substring_t args[MAX_OPT_ARGS];
        char *p, *name;
        int arg = 0;
+       kuid_t uid;
+       kgid_t gid;
 #ifdef CONFIG_QUOTA
        int ret;
 #endif
@@ -487,6 +518,40 @@ static int parse_options(struct super_block *sb, char *options)
                case Opt_data_flush:
                        set_opt(sbi, DATA_FLUSH);
                        break;
+               case Opt_reserve_root:
+                       if (args->from && match_int(args, &arg))
+                               return -EINVAL;
+                       if (test_opt(sbi, RESERVE_ROOT)) {
+                               f2fs_msg(sb, KERN_INFO,
+                                       "Preserve previous reserve_root=%u",
+                                       sbi->root_reserved_blocks);
+                       } else {
+                               sbi->root_reserved_blocks = arg;
+                               set_opt(sbi, RESERVE_ROOT);
+                       }
+                       break;
+               case Opt_resuid:
+                       if (args->from && match_int(args, &arg))
+                               return -EINVAL;
+                       uid = make_kuid(current_user_ns(), arg);
+                       if (!uid_valid(uid)) {
+                               f2fs_msg(sb, KERN_ERR,
+                                       "Invalid uid value %d", arg);
+                               return -EINVAL;
+                       }
+                       sbi->s_resuid = uid;
+                       break;
+               case Opt_resgid:
+                       if (args->from && match_int(args, &arg))
+                               return -EINVAL;
+                       gid = make_kgid(current_user_ns(), arg);
+                       if (!gid_valid(gid)) {
+                               f2fs_msg(sb, KERN_ERR,
+                                       "Invalid gid value %d", arg);
+                               return -EINVAL;
+                       }
+                       sbi->s_resgid = gid;
+                       break;
                case Opt_mode:
                        name = match_strdup(&args[0]);
 
@@ -994,22 +1059,25 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf)
        struct super_block *sb = dentry->d_sb;
        struct f2fs_sb_info *sbi = F2FS_SB(sb);
        u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
-       block_t total_count, user_block_count, start_count, ovp_count;
+       block_t total_count, user_block_count, start_count;
        u64 avail_node_count;
 
        total_count = le64_to_cpu(sbi->raw_super->block_count);
        user_block_count = sbi->user_block_count;
        start_count = le32_to_cpu(sbi->raw_super->segment0_blkaddr);
-       ovp_count = SM_I(sbi)->ovp_segments << sbi->log_blocks_per_seg;
        buf->f_type = F2FS_SUPER_MAGIC;
        buf->f_bsize = sbi->blocksize;
 
        buf->f_blocks = total_count - start_count;
-       buf->f_bfree = user_block_count - valid_user_blocks(sbi) + ovp_count;
-       buf->f_bavail = user_block_count - valid_user_blocks(sbi) -
+       buf->f_bfree = user_block_count - valid_user_blocks(sbi) -
                                                sbi->current_reserved_blocks;
+       if (buf->f_bfree > sbi->root_reserved_blocks)
+               buf->f_bavail = buf->f_bfree - sbi->root_reserved_blocks;
+       else
+               buf->f_bavail = 0;
 
-       avail_node_count = sbi->total_node_count - F2FS_RESERVED_NODE_NUM;
+       avail_node_count = sbi->total_node_count - sbi->nquota_files -
+                                               F2FS_RESERVED_NODE_NUM;
 
        if (avail_node_count > user_block_count) {
                buf->f_files = user_block_count;
@@ -1135,6 +1203,11 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
        else if (test_opt(sbi, LFS))
                seq_puts(seq, "lfs");
        seq_printf(seq, ",active_logs=%u", sbi->active_logs);
+       if (test_opt(sbi, RESERVE_ROOT))
+               seq_printf(seq, ",reserve_root=%u,resuid=%u,resgid=%u",
+                               sbi->root_reserved_blocks,
+                               from_kuid_munged(&init_user_ns, sbi->s_resuid),
+                               from_kgid_munged(&init_user_ns, sbi->s_resgid));
        if (F2FS_IO_SIZE_BITS(sbi))
                seq_printf(seq, ",io_size=%uKB", F2FS_IO_SIZE_KB(sbi));
 #ifdef CONFIG_F2FS_FAULT_INJECTION
@@ -1264,7 +1337,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
                err = dquot_suspend(sb, -1);
                if (err < 0)
                        goto restore_opts;
-       } else {
+       } else if (f2fs_readonly(sb) && !(*flags & MS_RDONLY)) {
                /* dquot_resume needs RW */
                sb->s_flags &= ~MS_RDONLY;
                if (sb_any_quota_suspended(sb)) {
@@ -1333,6 +1406,7 @@ skip:
        sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
                (test_opt(sbi, POSIX_ACL) ? MS_POSIXACL : 0);
 
+       limit_reserve_root(sbi);
        return 0;
 restore_gc:
        if (need_restart_gc) {
@@ -1658,7 +1732,7 @@ void f2fs_quota_off_umount(struct super_block *sb)
 }
 
 #if 0
-int f2fs_get_projid(struct inode *inode, kprojid_t *projid)
+static int f2fs_get_projid(struct inode *inode, kprojid_t *projid)
 {
        *projid = F2FS_I(inode)->i_projid;
        return 0;
@@ -2152,14 +2226,15 @@ static int init_blkz_info(struct f2fs_sb_info *sbi, int devi)
        if (nr_sectors & (bdev_zone_sectors(bdev) - 1))
                FDEV(devi).nr_blkz++;
 
-       FDEV(devi).blkz_type = kmalloc(FDEV(devi).nr_blkz, GFP_KERNEL);
+       FDEV(devi).blkz_type = f2fs_kmalloc(sbi, FDEV(devi).nr_blkz,
+                                                               GFP_KERNEL);
        if (!FDEV(devi).blkz_type)
                return -ENOMEM;
 
 #define F2FS_REPORT_NR_ZONES   4096
 
-       zones = kcalloc(F2FS_REPORT_NR_ZONES, sizeof(struct blk_zone),
-                       GFP_KERNEL);
+       zones = f2fs_kzalloc(sbi, sizeof(struct blk_zone) *
+                               F2FS_REPORT_NR_ZONES, GFP_KERNEL);
        if (!zones)
                return -ENOMEM;
 
@@ -2303,8 +2378,8 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi)
         * Initialize multiple devices information, or single
         * zoned block device information.
         */
-       sbi->devs = kcalloc(max_devices, sizeof(struct f2fs_dev_info),
-                               GFP_KERNEL);
+       sbi->devs = f2fs_kzalloc(sbi, sizeof(struct f2fs_dev_info) *
+                                               max_devices, GFP_KERNEL);
        if (!sbi->devs)
                return -ENOMEM;
 
@@ -2427,6 +2502,9 @@ try_onemore:
        sb->s_fs_info = sbi;
        sbi->raw_super = raw_super;
 
+       sbi->s_resuid = make_kuid(&init_user_ns, F2FS_DEF_RESUID);
+       sbi->s_resgid = make_kgid(&init_user_ns, F2FS_DEF_RESGID);
+
        /* precompute checksum seed for metadata */
        if (f2fs_sb_has_inode_chksum(sb))
                sbi->s_chksum_seed = f2fs_chksum(sbi, ~0, raw_super->uuid,
@@ -2470,6 +2548,13 @@ try_onemore:
        else
                sb->s_qcop = &f2fs_quotactl_ops;
        sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP | QTYPE_MASK_PRJ;
+
+       if (f2fs_sb_has_quota_ino(sbi->sb)) {
+               for (i = 0; i < MAXQUOTAS; i++) {
+                       if (f2fs_qf_ino(sbi->sb, i))
+                               sbi->nquota_files++;
+               }
+       }
 #endif
 
        sb->s_op = &f2fs_sops;
@@ -2483,6 +2568,7 @@ try_onemore:
        sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
                (test_opt(sbi, POSIX_ACL) ? MS_POSIXACL : 0);
        memcpy(sb->s_uuid, raw_super->uuid, sizeof(raw_super->uuid));
+       sb->s_iflags |= SB_I_CGROUPWB;
 
        /* init f2fs-specific super block info */
        sbi->valid_super_block = valid_super_block;
@@ -2503,8 +2589,9 @@ try_onemore:
                int n = (i == META) ? 1: NR_TEMP_TYPE;
                int j;
 
-               sbi->write_io[i] = kmalloc(n * sizeof(struct f2fs_bio_info),
-                                                               GFP_KERNEL);
+               sbi->write_io[i] = f2fs_kmalloc(sbi,
+                                       n * sizeof(struct f2fs_bio_info),
+                                       GFP_KERNEL);
                if (!sbi->write_io[i]) {
                        err = -ENOMEM;
                        goto free_options;
@@ -2525,14 +2612,14 @@ try_onemore:
 
        err = init_percpu_info(sbi);
        if (err)
-               goto free_options;
+               goto free_bio_info;
 
        if (F2FS_IO_SIZE(sbi) > 1) {
                sbi->write_io_dummy =
                        mempool_create_page_pool(2 * (F2FS_IO_SIZE(sbi) - 1), 0);
                if (!sbi->write_io_dummy) {
                        err = -ENOMEM;
-                       goto free_options;
+                       goto free_percpu;
                }
        }
 
@@ -2567,6 +2654,7 @@ try_onemore:
        sbi->last_valid_block_count = sbi->total_valid_block_count;
        sbi->reserved_blocks = 0;
        sbi->current_reserved_blocks = 0;
+       limit_reserve_root(sbi);
 
        for (i = 0; i < NR_INODE_TYPE; i++) {
                INIT_LIST_HEAD(&sbi->inode_list[i]);
@@ -2612,18 +2700,16 @@ try_onemore:
                goto free_nm;
        }
 
-       f2fs_join_shrinker(sbi);
-
        err = f2fs_build_stats(sbi);
        if (err)
-               goto free_nm;
+               goto free_node_inode;
 
        /* read root inode and dentry */
        root = f2fs_iget(sb, F2FS_ROOT_INO(sbi));
        if (IS_ERR(root)) {
                f2fs_msg(sb, KERN_ERR, "Failed to read root inode");
                err = PTR_ERR(root);
-               goto free_node_inode;
+               goto free_stats;
        }
        if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
                iput(root);
@@ -2719,6 +2805,8 @@ skip_recovery:
                        sbi->valid_super_block ? 1 : 2, err);
        }
 
+       f2fs_join_shrinker(sbi);
+
        f2fs_msg(sbi->sb, KERN_NOTICE, "Mounted with checkpoint version = %llx",
                                cur_cp_version(F2FS_CKPT(sbi)));
        f2fs_update_time(sbi, CP_TIME);
@@ -2745,14 +2833,12 @@ free_sysfs:
 free_root_inode:
        dput(sb->s_root);
        sb->s_root = NULL;
+free_stats:
+       f2fs_destroy_stats(sbi);
 free_node_inode:
-       truncate_inode_pages_final(NODE_MAPPING(sbi));
-       mutex_lock(&sbi->umount_mutex);
        release_ino_entry(sbi, true);
-       f2fs_leave_shrinker(sbi);
+       truncate_inode_pages_final(NODE_MAPPING(sbi));
        iput(sbi->node_inode);
-       mutex_unlock(&sbi->umount_mutex);
-       f2fs_destroy_stats(sbi);
 free_nm:
        destroy_node_manager(sbi);
 free_sm:
@@ -2765,10 +2851,12 @@ free_meta_inode:
        iput(sbi->meta_inode);
 free_io_dummy:
        mempool_destroy(sbi->write_io_dummy);
-free_options:
+free_percpu:
+       destroy_percpu_info(sbi);
+free_bio_info:
        for (i = 0; i < NR_PAGE_TYPE; i++)
                kfree(sbi->write_io[i]);
-       destroy_percpu_info(sbi);
+free_options:
 #ifdef CONFIG_QUOTA
        for (i = 0; i < MAXQUOTAS; i++)
                kfree(sbi->s_qf_names[i]);
index 9835348..d978c7b 100644 (file)
@@ -113,6 +113,9 @@ static ssize_t features_show(struct f2fs_attr *a,
        if (f2fs_sb_has_quota_ino(sb))
                len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
                                len ? ", " : "", "quota_ino");
+       if (f2fs_sb_has_inode_crtime(sb))
+               len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
+                               len ? ", " : "", "inode_crtime");
        len += snprintf(buf + len, PAGE_SIZE - len, "\n");
        return len;
 }
@@ -162,7 +165,8 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
 #endif
        if (a->struct_type == RESERVED_BLOCKS) {
                spin_lock(&sbi->stat_lock);
-               if (t > (unsigned long)sbi->user_block_count) {
+               if (t > (unsigned long)(sbi->user_block_count -
+                                       sbi->root_reserved_blocks)) {
                        spin_unlock(&sbi->stat_lock);
                        return -EINVAL;
                }
@@ -231,6 +235,7 @@ enum feat_id {
        FEAT_INODE_CHECKSUM,
        FEAT_FLEXIBLE_INLINE_XATTR,
        FEAT_QUOTA_INO,
+       FEAT_INODE_CRTIME,
 };
 
 static ssize_t f2fs_feature_show(struct f2fs_attr *a,
@@ -245,6 +250,7 @@ static ssize_t f2fs_feature_show(struct f2fs_attr *a,
        case FEAT_INODE_CHECKSUM:
        case FEAT_FLEXIBLE_INLINE_XATTR:
        case FEAT_QUOTA_INO:
+       case FEAT_INODE_CRTIME:
                return snprintf(buf, PAGE_SIZE, "supported\n");
        }
        return 0;
@@ -299,6 +305,8 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, dir_level, dir_level);
 F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, interval_time[CP_TIME]);
 F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, idle_interval, interval_time[REQ_TIME]);
 F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, iostat_enable, iostat_enable);
+F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, readdir_ra, readdir_ra);
+F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_pin_file_thresh, gc_pin_file_threshold);
 #ifdef CONFIG_F2FS_FAULT_INJECTION
 F2FS_RW_ATTR(FAULT_INFO_RATE, f2fs_fault_info, inject_rate, inject_rate);
 F2FS_RW_ATTR(FAULT_INFO_TYPE, f2fs_fault_info, inject_type, inject_type);
@@ -320,6 +328,7 @@ F2FS_FEATURE_RO_ATTR(project_quota, FEAT_PROJECT_QUOTA);
 F2FS_FEATURE_RO_ATTR(inode_checksum, FEAT_INODE_CHECKSUM);
 F2FS_FEATURE_RO_ATTR(flexible_inline_xattr, FEAT_FLEXIBLE_INLINE_XATTR);
 F2FS_FEATURE_RO_ATTR(quota_ino, FEAT_QUOTA_INO);
+F2FS_FEATURE_RO_ATTR(inode_crtime, FEAT_INODE_CRTIME);
 
 #define ATTR_LIST(name) (&f2fs_attr_##name.attr)
 static struct attribute *f2fs_attrs[] = {
@@ -346,6 +355,8 @@ static struct attribute *f2fs_attrs[] = {
        ATTR_LIST(cp_interval),
        ATTR_LIST(idle_interval),
        ATTR_LIST(iostat_enable),
+       ATTR_LIST(readdir_ra),
+       ATTR_LIST(gc_pin_file_thresh),
 #ifdef CONFIG_F2FS_FAULT_INJECTION
        ATTR_LIST(inject_rate),
        ATTR_LIST(inject_type),
@@ -371,6 +382,7 @@ static struct attribute *f2fs_feat_attrs[] = {
        ATTR_LIST(inode_checksum),
        ATTR_LIST(flexible_inline_xattr),
        ATTR_LIST(quota_ino),
+       ATTR_LIST(inode_crtime),
        NULL,
 };
 
index bccbbf2..a1fcd00 100644 (file)
@@ -17,7 +17,7 @@
 #include "trace.h"
 
 static RADIX_TREE(pids, GFP_ATOMIC);
-static spinlock_t pids_lock;
+static struct mutex pids_lock;
 static struct last_io_info last_io;
 
 static inline void __print_last_io(void)
@@ -64,7 +64,7 @@ void f2fs_trace_pid(struct page *page)
        if (radix_tree_preload(GFP_NOFS))
                return;
 
-       spin_lock(&pids_lock);
+       mutex_lock(&pids_lock);
        p = radix_tree_lookup(&pids, pid);
        if (p == current)
                goto out;
@@ -77,7 +77,7 @@ void f2fs_trace_pid(struct page *page)
                        MAJOR(inode->i_sb->s_dev), MINOR(inode->i_sb->s_dev),
                        pid, current->comm);
 out:
-       spin_unlock(&pids_lock);
+       mutex_unlock(&pids_lock);
        radix_tree_preload_end();
 }
 
@@ -122,7 +122,7 @@ void f2fs_trace_ios(struct f2fs_io_info *fio, int flush)
 
 void f2fs_build_trace_ios(void)
 {
-       spin_lock_init(&pids_lock);
+       mutex_init(&pids_lock);
 }
 
 #define PIDVEC_SIZE    128
@@ -150,7 +150,7 @@ void f2fs_destroy_trace_ios(void)
        pid_t next_pid = 0;
        unsigned int found;
 
-       spin_lock(&pids_lock);
+       mutex_lock(&pids_lock);
        while ((found = gang_lookup_pids(pid, next_pid, PIDVEC_SIZE))) {
                unsigned idx;
 
@@ -158,5 +158,5 @@ void f2fs_destroy_trace_ios(void)
                for (idx = 0; idx < found; idx++)
                        radix_tree_delete(&pids, pid[idx]);
        }
-       spin_unlock(&pids_lock);
+       mutex_unlock(&pids_lock);
 }
index 7acf56e..116be97 100644 (file)
@@ -345,8 +345,8 @@ static int lookup_all_xattrs(struct inode *inode, struct page *ipage,
        if (!size && !inline_size)
                return -ENODATA;
 
-       txattr_addr = kzalloc(inline_size + size + XATTR_PADDING_SIZE,
-                                                       GFP_F2FS_ZERO);
+       txattr_addr = f2fs_kzalloc(F2FS_I_SB(inode),
+                       inline_size + size + XATTR_PADDING_SIZE, GFP_NOFS);
        if (!txattr_addr)
                return -ENOMEM;
 
@@ -398,8 +398,8 @@ static int read_all_xattrs(struct inode *inode, struct page *ipage,
        void *txattr_addr;
        int err;
 
-       txattr_addr = kzalloc(inline_size + size + XATTR_PADDING_SIZE,
-                                                       GFP_F2FS_ZERO);
+       txattr_addr = f2fs_kzalloc(F2FS_I_SB(inode),
+                       inline_size + size + XATTR_PADDING_SIZE, GFP_NOFS);
        if (!txattr_addr)
                return -ENOMEM;
 
@@ -480,6 +480,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
        if (F2FS_I(inode)->i_xattr_nid) {
                xpage = get_node_page(sbi, F2FS_I(inode)->i_xattr_nid);
                if (IS_ERR(xpage)) {
+                       err = PTR_ERR(xpage);
                        alloc_nid_failed(sbi, new_nid);
                        goto in_page_out;
                }
@@ -490,6 +491,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
                set_new_dnode(&dn, inode, NULL, NULL, new_nid);
                xpage = new_node_page(&dn, XATTR_NODE_OFFSET);
                if (IS_ERR(xpage)) {
+                       err = PTR_ERR(xpage);
                        alloc_nid_failed(sbi, new_nid);
                        goto in_page_out;
                }
@@ -638,7 +640,7 @@ static int __f2fs_setxattr(struct inode *inode, int index,
                        goto exit;
                }
 
-               if (f2fs_xattr_value_same(here, value, size))
+               if (value && f2fs_xattr_value_same(here, value, size))
                        goto exit;
        } else if ((flags & XATTR_REPLACE)) {
                error = -ENODATA;
index 6a7234f..bd16497 100644 (file)
@@ -2034,3 +2034,9 @@ void inode_set_flags(struct inode *inode, unsigned int flags,
                                  new_flags) != old_flags));
 }
 EXPORT_SYMBOL(inode_set_flags);
+
+void inode_nohighmem(struct inode *inode)
+{
+       mapping_set_gfp_mask(inode->i_mapping, GFP_USER);
+}
+EXPORT_SYMBOL(inode_nohighmem);
index 6e9a912..6875bd5 100644 (file)
@@ -272,7 +272,7 @@ static ssize_t kernfs_fop_write(struct file *file, const char __user *user_buf,
 {
        struct kernfs_open_file *of = kernfs_of(file);
        const struct kernfs_ops *ops;
-       size_t len;
+       ssize_t len;
        char *buf;
 
        if (of->atomic_write_len) {
index 3b2b5c8..1f2e81c 100644 (file)
@@ -2015,6 +2015,9 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
        int retval = 0;
        const char *s = nd->name->name;
 
+       if (!*s)
+               flags &= ~LOOKUP_RCU;
+
        nd->last_type = LAST_ROOT; /* if there are only slashes... */
        nd->flags = flags | LOOKUP_JUMPED | LOOKUP_PARENT;
        nd->depth = 0;
index 03446c5..4e11445 100644 (file)
@@ -133,12 +133,11 @@ ncp_hash_dentry(const struct dentry *dentry, struct qstr *this)
                return 0;
 
        if (!ncp_case_sensitive(inode)) {
-               struct super_block *sb = dentry->d_sb;
                struct nls_table *t;
                unsigned long hash;
                int i;
 
-               t = NCP_IO_TABLE(sb);
+               t = NCP_IO_TABLE(dentry->d_sb);
                hash = init_name_hash();
                for (i=0; i<this->len ; i++)
                        hash = partial_name_hash(ncp_tolower(t, this->name[i]),
index 4b1d08f..5fd3cf5 100644 (file)
@@ -787,10 +787,8 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr)
 
        spin_lock(&dreq->lock);
 
-       if (test_bit(NFS_IOHDR_ERROR, &hdr->flags)) {
-               dreq->flags = 0;
+       if (test_bit(NFS_IOHDR_ERROR, &hdr->flags))
                dreq->error = hdr->error;
-       }
        if (dreq->error == 0) {
                nfs_direct_good_bytes(dreq, hdr);
                if (nfs_write_need_commit(hdr)) {
index 5ba22c6..1ee62e6 100644 (file)
@@ -567,9 +567,13 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons,
        struct idmap_msg *im;
        struct idmap *idmap = (struct idmap *)aux;
        struct key *key = cons->key;
-       int ret = -ENOMEM;
+       int ret = -ENOKEY;
+
+       if (!aux)
+               goto out1;
 
        /* msg and im are freed in idmap_pipe_destroy_msg */
+       ret = -ENOMEM;
        data = kzalloc(sizeof(*data), GFP_KERNEL);
        if (!data)
                goto out1;
index 7af7bed..c8e75e5 100644 (file)
@@ -1943,7 +1943,7 @@ pnfs_write_through_mds(struct nfs_pageio_descriptor *desc,
                nfs_pageio_reset_write_mds(desc);
                mirror->pg_recoalesce = 1;
        }
-       hdr->release(hdr);
+       hdr->completion_ops->completion(hdr);
 }
 
 static enum pnfs_try_status
@@ -2058,7 +2058,7 @@ pnfs_read_through_mds(struct nfs_pageio_descriptor *desc,
                nfs_pageio_reset_read_mds(desc);
                mirror->pg_recoalesce = 1;
        }
-       hdr->release(hdr);
+       hdr->completion_ops->completion(hdr);
 }
 
 /*
index 7a9b6e3..6e81a5b 100644 (file)
@@ -1746,6 +1746,8 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data)
                set_bit(NFS_CONTEXT_RESEND_WRITES, &req->wb_context->flags);
        next:
                nfs_unlock_and_release_request(req);
+               /* Latency breaker */
+               cond_resched();
        }
        nfss = NFS_SERVER(data->inode);
        if (atomic_long_read(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH)
index 8f20d60..914ca6b 100644 (file)
--- a/fs/nsfs.c
+++ b/fs/nsfs.c
@@ -95,6 +95,7 @@ slow:
                return ERR_PTR(-ENOMEM);
        }
        d_instantiate(dentry, inode);
+       dentry->d_flags |= DCACHE_RCUACCESS;
        dentry->d_fsdata = (void *)ns_ops;
        d = atomic_long_cmpxchg(&ns->stashed, 0, (unsigned long)dentry);
        if (d) {
index adcb139..299a6e1 100644 (file)
@@ -441,10 +441,14 @@ static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end,
        struct dentry *dentry = file->f_path.dentry;
        struct file *realfile = od->realfile;
 
+       /* Nothing to sync for lower */
+       if (!OVL_TYPE_UPPER(ovl_path_type(dentry)))
+               return 0;
+
        /*
         * Need to check if we started out being a lower dir, but got copied up
         */
-       if (!od->is_upper && OVL_TYPE_UPPER(ovl_path_type(dentry))) {
+       if (!od->is_upper) {
                struct inode *inode = file_inode(file);
 
                realfile = lockless_dereference(od->upperfile);
index 249594a..f5cebd7 100644 (file)
@@ -475,7 +475,7 @@ static void leaf_item_bottle(struct buffer_info *dest_bi,
                         * 'cpy_bytes'; create new item header;
                         * n_ih = new item_header;
                         */
-                       memcpy(&n_ih, ih, SHORT_KEY_SIZE);
+                       memcpy(&n_ih.ih_key, &ih->ih_key, KEY_SIZE);
 
                        /* Endian safe, both le */
                        n_ih.ih_version = ih->ih_version;
index 2adcde1..5dcf3ab 100644 (file)
@@ -1326,7 +1326,6 @@ struct cpu_key {
 #define KEY_NOT_FOUND 0
 
 #define KEY_SIZE (sizeof(struct reiserfs_key))
-#define SHORT_KEY_SIZE (sizeof (__u32) + sizeof (__u32))
 
 /* return values for search_by_key and clones */
 #define ITEM_FOUND 1
index 5ac0b0b..2879d12 100644 (file)
@@ -62,6 +62,7 @@ static ssize_t sdcardfs_write(struct file *file, const char __user *buf,
        int err;
        struct file *lower_file;
        struct dentry *dentry = file->f_path.dentry;
+       struct inode *inode = d_inode(dentry);
 
        /* check disk space */
        if (!check_min_free_space(dentry, count, 0)) {
@@ -73,10 +74,12 @@ static ssize_t sdcardfs_write(struct file *file, const char __user *buf,
        err = vfs_write(lower_file, buf, count, ppos);
        /* update our inode times+sizes upon a successful lower write */
        if (err >= 0) {
-               fsstack_copy_inode_size(d_inode(dentry),
-                                       file_inode(lower_file));
-               fsstack_copy_attr_times(d_inode(dentry),
-                                       file_inode(lower_file));
+               if (sizeof(loff_t) > sizeof(long))
+                       inode_lock(inode);
+               fsstack_copy_inode_size(inode, file_inode(lower_file));
+               fsstack_copy_attr_times(inode, file_inode(lower_file));
+               if (sizeof(loff_t) > sizeof(long))
+                       inode_unlock(inode);
        }
 
        return err;
@@ -391,6 +394,7 @@ ssize_t sdcardfs_write_iter(struct kiocb *iocb, struct iov_iter *iter)
 {
        int err;
        struct file *file = iocb->ki_filp, *lower_file;
+       struct inode *inode = file->f_path.dentry->d_inode;
 
        lower_file = sdcardfs_lower_file(file);
        if (!lower_file->f_op->write_iter) {
@@ -405,10 +409,12 @@ ssize_t sdcardfs_write_iter(struct kiocb *iocb, struct iov_iter *iter)
        fput(lower_file);
        /* update upper inode times/sizes as needed */
        if (err >= 0 || err == -EIOCBQUEUED) {
-               fsstack_copy_inode_size(file->f_path.dentry->d_inode,
-                                       file_inode(lower_file));
-               fsstack_copy_attr_times(file->f_path.dentry->d_inode,
-                                       file_inode(lower_file));
+               if (sizeof(loff_t) > sizeof(long))
+                       inode_lock(inode);
+               fsstack_copy_inode_size(inode, file_inode(lower_file));
+               fsstack_copy_attr_times(inode, file_inode(lower_file));
+               if (sizeof(loff_t) > sizeof(long))
+                       inode_lock(inode);
        }
 out:
        return err;
index 0ebdb4f..90aa5cb 100644 (file)
@@ -91,6 +91,8 @@ static inline bool crypto_shash_alg_has_setkey(struct shash_alg *alg)
        return alg->setkey != shash_no_setkey;
 }
 
+bool crypto_hash_alg_has_setkey(struct hash_alg_common *halg);
+
 int crypto_init_ahash_spawn(struct crypto_ahash_spawn *spawn,
                            struct hash_alg_common *alg,
                            struct crypto_instance *inst);
index 894df59..d586f74 100644 (file)
@@ -30,8 +30,6 @@ struct poly1305_desc_ctx {
 };
 
 int crypto_poly1305_init(struct shash_desc *desc);
-int crypto_poly1305_setkey(struct crypto_shash *tfm,
-                          const u8 *key, unsigned int keylen);
 unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx,
                                        const u8 *src, unsigned int srclen);
 int crypto_poly1305_update(struct shash_desc *desc,
diff --git a/include/crypto/speck.h b/include/crypto/speck.h
new file mode 100644 (file)
index 0000000..73cfc95
--- /dev/null
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Common values for the Speck algorithm
+ */
+
+#ifndef _CRYPTO_SPECK_H
+#define _CRYPTO_SPECK_H
+
+#include <linux/types.h>
+
+/* Speck128 */
+
+#define SPECK128_BLOCK_SIZE    16
+
+#define SPECK128_128_KEY_SIZE  16
+#define SPECK128_128_NROUNDS   32
+
+#define SPECK128_192_KEY_SIZE  24
+#define SPECK128_192_NROUNDS   33
+
+#define SPECK128_256_KEY_SIZE  32
+#define SPECK128_256_NROUNDS   34
+
+struct speck128_tfm_ctx {
+       u64 round_keys[SPECK128_256_NROUNDS];
+       int nrounds;
+};
+
+void crypto_speck128_encrypt(const struct speck128_tfm_ctx *ctx,
+                            u8 *out, const u8 *in);
+
+void crypto_speck128_decrypt(const struct speck128_tfm_ctx *ctx,
+                            u8 *out, const u8 *in);
+
+int crypto_speck128_setkey(struct speck128_tfm_ctx *ctx, const u8 *key,
+                          unsigned int keysize);
+
+/* Speck64 */
+
+#define SPECK64_BLOCK_SIZE     8
+
+#define SPECK64_96_KEY_SIZE    12
+#define SPECK64_96_NROUNDS     26
+
+#define SPECK64_128_KEY_SIZE   16
+#define SPECK64_128_NROUNDS    27
+
+struct speck64_tfm_ctx {
+       u32 round_keys[SPECK64_128_NROUNDS];
+       int nrounds;
+};
+
+void crypto_speck64_encrypt(const struct speck64_tfm_ctx *ctx,
+                           u8 *out, const u8 *in);
+
+void crypto_speck64_decrypt(const struct speck64_tfm_ctx *ctx,
+                           u8 *out, const u8 *in);
+
+int crypto_speck64_setkey(struct speck64_tfm_ctx *ctx, const u8 *key,
+                         unsigned int keysize);
+
+#endif /* _CRYPTO_SPECK_H */
index 30c52d7..4d67d85 100644 (file)
@@ -1286,8 +1286,11 @@ do {                                                                     \
                dev_printk(KERN_DEBUG, dev, fmt, ##__VA_ARGS__);        \
 } while (0)
 #else
-#define dev_dbg_ratelimited(dev, fmt, ...)                     \
-       no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
+#define dev_dbg_ratelimited(dev, fmt, ...)                             \
+do {                                                                   \
+       if (0)                                                          \
+               dev_printk(KERN_DEBUG, dev, fmt, ##__VA_ARGS__);        \
+} while (0)
 #endif
 
 #ifdef VERBOSE_DEBUG
index fef1cae..c82ae65 100644 (file)
@@ -117,6 +117,7 @@ struct f2fs_super_block {
 /*
  * For checkpoint
  */
+#define CP_NOCRC_RECOVERY_FLAG 0x00000200
 #define CP_TRIMMED_FLAG                0x00000100
 #define CP_NAT_BITS_FLAG       0x00000080
 #define CP_CRC_RECOVERY_FLAG   0x00000040
@@ -212,6 +213,7 @@ struct f2fs_extent {
 #define F2FS_DATA_EXIST                0x08    /* file inline data exist flag */
 #define F2FS_INLINE_DOTS       0x10    /* file having implicit dot dentries */
 #define F2FS_EXTRA_ATTR                0x20    /* file having extra attribute */
+#define F2FS_PIN_FILE          0x40    /* file should not be gced */
 
 struct f2fs_inode {
        __le16 i_mode;                  /* file mode */
@@ -229,7 +231,13 @@ struct f2fs_inode {
        __le32 i_ctime_nsec;            /* change time in nano scale */
        __le32 i_mtime_nsec;            /* modification time in nano scale */
        __le32 i_generation;            /* file version (for NFS) */
-       __le32 i_current_depth;         /* only for directory depth */
+       union {
+               __le32 i_current_depth; /* only for directory depth */
+               __le16 i_gc_failures;   /*
+                                        * # of gc failures on pinned file.
+                                        * only for regular files.
+                                        */
+       };
        __le32 i_xattr_nid;             /* nid to save xattr */
        __le32 i_flags;                 /* file attributes */
        __le32 i_pino;                  /* parent inode number */
@@ -245,8 +253,10 @@ struct f2fs_inode {
                        __le16 i_inline_xattr_size;     /* inline xattr size, unit: 4 bytes */
                        __le32 i_projid;        /* project id */
                        __le32 i_inode_checksum;/* inode meta checksum */
+                       __le64 i_crtime;        /* creation time */
+                       __le32 i_crtime_nsec;   /* creation time in nano scale */
                        __le32 i_extra_end[0];  /* for attribute size calculation */
-               };
+               } __packed;
                __le32 i_addr[DEF_ADDRS_PER_INODE];     /* Pointers to data blocks */
        };
        __le32 i_nid[DEF_NIDS_PER_INODE];       /* direct(2), indirect(2),
index 5295535..a7b7a05 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/compiler.h>
 #include <linux/spinlock.h>
 #include <linux/rcupdate.h>
+#include <linux/nospec.h>
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/fs.h>
@@ -81,8 +82,10 @@ static inline struct file *__fcheck_files(struct files_struct *files, unsigned i
 {
        struct fdtable *fdt = rcu_dereference_raw(files->fdt);
 
-       if (fd < fdt->max_fds)
+       if (fd < fdt->max_fds) {
+               fd = array_index_nospec(fd, fdt->max_fds);
                return rcu_dereference_raw(fdt->fd[fd]);
+       }
        return NULL;
 }
 
index 3c4dd62..f896545 100644 (file)
@@ -3114,5 +3114,6 @@ static inline bool dir_relax(struct inode *inode)
 }
 
 extern bool path_noexec(const struct path *path);
+extern void inode_nohighmem(struct inode *inode);
 
 #endif /* _LINUX_FS_H */
index 3ba9289..26cd526 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015,2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2015,2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -201,7 +201,6 @@ enum i2c_msm_power_state {
 #define I2C_MSM_MAX_POLL_MSEC           (100)
 #define I2C_MSM_TIMEOUT_SAFTY_COEF      (10)
 #define I2C_MSM_TIMEOUT_MIN_USEC        (500000)
-#define I2C_QUP_MAX_BUS_RECOVERY_RETRY  (10)
 
 /* QUP v2 tags */
 #define QUP_TAG2_DATA_WRITE        (0x82ULL)
index aedb254..3561ea3 100644 (file)
@@ -4,6 +4,13 @@
 #include <linux/compiler.h>
 #include <linux/types.h>
 
+/* Built-in __init functions needn't be compiled with retpoline */
+#if defined(RETPOLINE) && !defined(MODULE)
+#define __noretpoline __attribute__((indirect_branch("keep")))
+#else
+#define __noretpoline
+#endif
+
 /* These macros are used to mark some functions or 
  * initialized data (doesn't apply to uninitialized data)
  * as `initialization' functions. The kernel can take this
@@ -39,7 +46,7 @@
 
 /* These are for everybody (although not all archs will actually
    discard it in modules) */
-#define __init         __section(.init.text) __cold notrace
+#define __init         __section(.init.text) __cold notrace __noretpoline
 #define __initdata     __section(.init.data)
 #define __initconst    __constsection(.init.rodata)
 #define __exitdata     __section(.exit.data)
index ce824db..d5d82c7 100644 (file)
 #define GIC_VPE_SWINT0_MAP_OFS         0x0054
 #define GIC_VPE_SWINT1_MAP_OFS         0x0058
 #define GIC_VPE_OTHER_ADDR_OFS         0x0080
+#define GIC_VP_IDENT_OFS               0x0088
 #define GIC_VPE_WD_CONFIG0_OFS         0x0090
 #define GIC_VPE_WD_COUNT0_OFS          0x0094
 #define GIC_VPE_WD_INITIAL0_OFS                0x0098
 #define GIC_VPE_SMASK_FDC_SHF          6
 #define GIC_VPE_SMASK_FDC_MSK          (MSK(1) << GIC_VPE_SMASK_FDC_SHF)
 
+/* GIC_VP_IDENT fields */
+#define GIC_VP_IDENT_VCNUM_SHF         0
+#define GIC_VP_IDENT_VCNUM_MSK         (MSK(6) << GIC_VP_IDENT_VCNUM_SHF)
+
 /* GIC nomenclature for Core Interrupt Pins. */
 #define GIC_CPU_INT0           0 /* Core Interrupt 2 */
 #define GIC_CPU_INT1           1 /* .                */
@@ -281,4 +286,16 @@ static inline int gic_get_usm_range(struct resource *gic_usm_res)
 
 #endif /* CONFIG_MIPS_GIC */
 
+/**
+ * gic_read_local_vp_id() - read the local VPs VCNUM
+ *
+ * Read the VCNUM of the local VP from the GIC_VP_IDENT register and
+ * return it to the caller. This ID should be used to refer to the VP
+ * via the GICs VP-other region, or when calculating an offset to a
+ * bit representing the VP in interrupt masks.
+ *
+ * Return: The VCNUM value for the local VP.
+ */
+extern unsigned gic_read_local_vp_id(void);
+
 #endif /* __LINUX_IRQCHIP_MIPS_GIC_H */
index 58c55b1..b56c190 100644 (file)
@@ -32,7 +32,7 @@ static inline void kaiser_init(void)
 {
 }
 static inline int kaiser_add_mapping(unsigned long addr,
-                                    unsigned long size, unsigned long flags)
+                                    unsigned long size, u64 flags)
 {
        return 0;
 }
index ae8d475..43d5deb 100644 (file)
@@ -37,7 +37,7 @@ extern int migrate_page(struct address_space *,
                        struct page *, struct page *, enum migrate_mode);
 extern int migrate_pages(struct list_head *l, new_page_t new, free_page_t free,
                unsigned long private, enum migrate_mode mode, int reason);
-extern bool isolate_movable_page(struct page *page, isolate_mode_t mode);
+extern int isolate_movable_page(struct page *page, isolate_mode_t mode);
 extern void putback_movable_page(struct page *page);
 
 extern int migrate_prep(void);
index e232465..dfe5c2e 100644 (file)
@@ -789,6 +789,15 @@ static inline void module_bug_finalize(const Elf_Ehdr *hdr,
 static inline void module_bug_cleanup(struct module *mod) {}
 #endif /* CONFIG_GENERIC_BUG */
 
+#ifdef RETPOLINE
+extern bool retpoline_module_ok(bool has_retpoline);
+#else
+static inline bool retpoline_module_ok(bool has_retpoline)
+{
+       return true;
+}
+#endif
+
 #ifdef CONFIG_MODULE_SIG
 static inline bool module_sig_ok(struct module *module)
 {
index f0f43ec..d0d50cf 100644 (file)
@@ -17,7 +17,13 @@ struct msi_desc;
 struct pci_dev;
 struct platform_msi_priv_data;
 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)
+{
+}
+#endif
 
 typedef void (*irq_write_msi_msg_t)(struct msi_desc *desc,
                                    struct msi_msg *msg);
@@ -105,18 +111,21 @@ struct msi_desc {
 
 struct pci_dev *msi_desc_to_pci_dev(struct msi_desc *desc);
 void *msi_desc_to_pci_sysdata(struct msi_desc *desc);
+void pci_write_msi_msg(unsigned int irq, struct msi_msg *msg);
 #else /* CONFIG_PCI_MSI */
 static inline void *msi_desc_to_pci_sysdata(struct msi_desc *desc)
 {
        return NULL;
 }
+static inline void pci_write_msi_msg(unsigned int irq, struct msi_msg *msg)
+{
+}
 #endif /* CONFIG_PCI_MSI */
 
 struct msi_desc *alloc_msi_entry(struct device *dev);
 void free_msi_entry(struct msi_desc *entry);
 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_write_msi_msg(unsigned int irq, struct msi_msg *msg);
 
 u32 __pci_msix_desc_mask_irq(struct msi_desc *desc, u32 flag);
 u32 __pci_msi_desc_mask_irq(struct msi_desc *desc, u32 mask, u32 flag);
index 806d0ab..676d3d2 100644 (file)
@@ -265,75 +265,67 @@ void map_destroy(struct mtd_info *mtd);
 #define INVALIDATE_CACHED_RANGE(map, from, size) \
        do { if (map->inval_cache) map->inval_cache(map, from, size); } while (0)
 
-
-static inline int map_word_equal(struct map_info *map, map_word val1, map_word val2)
-{
-       int i;
-
-       for (i = 0; i < map_words(map); i++) {
-               if (val1.x[i] != val2.x[i])
-                       return 0;
-       }
-
-       return 1;
-}
-
-static inline map_word map_word_and(struct map_info *map, map_word val1, map_word val2)
-{
-       map_word r;
-       int i;
-
-       for (i = 0; i < map_words(map); i++)
-               r.x[i] = val1.x[i] & val2.x[i];
-
-       return r;
-}
-
-static inline map_word map_word_clr(struct map_info *map, map_word val1, map_word val2)
-{
-       map_word r;
-       int i;
-
-       for (i = 0; i < map_words(map); i++)
-               r.x[i] = val1.x[i] & ~val2.x[i];
-
-       return r;
-}
-
-static inline map_word map_word_or(struct map_info *map, map_word val1, map_word val2)
-{
-       map_word r;
-       int i;
-
-       for (i = 0; i < map_words(map); i++)
-               r.x[i] = val1.x[i] | val2.x[i];
-
-       return r;
-}
-
-static inline int map_word_andequal(struct map_info *map, map_word val1, map_word val2, map_word val3)
-{
-       int i;
-
-       for (i = 0; i < map_words(map); i++) {
-               if ((val1.x[i] & val2.x[i]) != val3.x[i])
-                       return 0;
-       }
-
-       return 1;
-}
-
-static inline int map_word_bitsset(struct map_info *map, map_word val1, map_word val2)
-{
-       int i;
-
-       for (i = 0; i < map_words(map); i++) {
-               if (val1.x[i] & val2.x[i])
-                       return 1;
-       }
-
-       return 0;
-}
+#define map_word_equal(map, val1, val2)                                        \
+({                                                                     \
+       int i, ret = 1;                                                 \
+       for (i = 0; i < map_words(map); i++)                            \
+               if ((val1).x[i] != (val2).x[i]) {                       \
+                       ret = 0;                                        \
+                       break;                                          \
+               }                                                       \
+       ret;                                                            \
+})
+
+#define map_word_and(map, val1, val2)                                  \
+({                                                                     \
+       map_word r;                                                     \
+       int i;                                                          \
+       for (i = 0; i < map_words(map); i++)                            \
+               r.x[i] = (val1).x[i] & (val2).x[i];                     \
+       r;                                                              \
+})
+
+#define map_word_clr(map, val1, val2)                                  \
+({                                                                     \
+       map_word r;                                                     \
+       int i;                                                          \
+       for (i = 0; i < map_words(map); i++)                            \
+               r.x[i] = (val1).x[i] & ~(val2).x[i];                    \
+       r;                                                              \
+})
+
+#define map_word_or(map, val1, val2)                                   \
+({                                                                     \
+       map_word r;                                                     \
+       int i;                                                          \
+       for (i = 0; i < map_words(map); i++)                            \
+               r.x[i] = (val1).x[i] | (val2).x[i];                     \
+       r;                                                              \
+})
+
+#define map_word_andequal(map, val1, val2, val3)                       \
+({                                                                     \
+       int i, ret = 1;                                                 \
+       for (i = 0; i < map_words(map); i++) {                          \
+               if (((val1).x[i] & (val2).x[i]) != (val2).x[i]) {       \
+                       ret = 0;                                        \
+                       break;                                          \
+               }                                                       \
+       }                                                               \
+       ret;                                                            \
+})
+
+#define map_word_bitsset(map, val1, val2)                              \
+({                                                                     \
+       int i, ret = 0;                                                 \
+       for (i = 0; i < map_words(map); i++) {                          \
+               if ((val1).x[i] & (val2).x[i]) {                        \
+                       ret = 1;                                        \
+                       break;                                          \
+               }                                                       \
+       }                                                               \
+       ret;                                                            \
+})
 
 static inline map_word map_word_load(struct map_info *map, const void *ptr)
 {
index 1c28f88..067b37a 100644 (file)
@@ -148,6 +148,7 @@ struct sh_flctl {
        struct platform_device  *pdev;
        struct dev_pm_qos_request pm_qos;
        void __iomem            *reg;
+       resource_size_t         fifo;
 
        uint8_t done_buff[2048 + 64];   /* max size 2048 + 64 */
        int     read_bytes;
diff --git a/include/linux/nospec.h b/include/linux/nospec.h
new file mode 100644 (file)
index 0000000..b99bced
--- /dev/null
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2018 Linus Torvalds. All rights reserved.
+// Copyright(c) 2018 Alexei Starovoitov. All rights reserved.
+// Copyright(c) 2018 Intel Corporation. All rights reserved.
+
+#ifndef _LINUX_NOSPEC_H
+#define _LINUX_NOSPEC_H
+
+/**
+ * array_index_mask_nospec() - generate a ~0 mask when index < size, 0 otherwise
+ * @index: array element index
+ * @size: number of elements in array
+ *
+ * When @index is out of bounds (@index >= @size), the sign bit will be
+ * set.  Extend the sign bit to all bits and invert, giving a result of
+ * zero for an out of bounds index, or ~0 if within bounds [0, @size).
+ */
+#ifndef array_index_mask_nospec
+static inline unsigned long array_index_mask_nospec(unsigned long index,
+                                                   unsigned long size)
+{
+       /*
+        * Warn developers about inappropriate array_index_nospec() usage.
+        *
+        * Even if the CPU speculates past the WARN_ONCE branch, the
+        * sign bit of @index is taken into account when generating the
+        * mask.
+        *
+        * This warning is compiled out when the compiler can infer that
+        * @index and @size are less than LONG_MAX.
+        */
+       if (WARN_ONCE(index > LONG_MAX || size > LONG_MAX,
+                       "array_index_nospec() limited to range of [0, LONG_MAX]\n"))
+               return 0;
+
+       /*
+        * Always calculate and emit the mask even if the compiler
+        * thinks the mask is not needed. The compiler does not take
+        * into account the value of @index under speculation.
+        */
+       OPTIMIZER_HIDE_VAR(index);
+       return ~(long)(index | (size - 1UL - index)) >> (BITS_PER_LONG - 1);
+}
+#endif
+
+/*
+ * array_index_nospec - sanitize an array index after a bounds check
+ *
+ * For a code sequence like:
+ *
+ *     if (index < size) {
+ *         index = array_index_nospec(index, size);
+ *         val = array[index];
+ *     }
+ *
+ * ...if the CPU speculates past the bounds check then
+ * array_index_nospec() will clamp the index within the range of [0,
+ * size).
+ */
+#define array_index_nospec(index, size)                                        \
+({                                                                     \
+       typeof(index) _i = (index);                                     \
+       typeof(size) _s = (size);                                       \
+       unsigned long _mask = array_index_mask_nospec(_i, _s);          \
+                                                                       \
+       BUILD_BUG_ON(sizeof(_i) > sizeof(long));                        \
+       BUILD_BUG_ON(sizeof(_s) > sizeof(long));                        \
+                                                                       \
+       _i &= _mask;                                                    \
+       _i;                                                             \
+})
+#endif /* _LINUX_NOSPEC_H */
index 92b59a1..fcfed59 100644 (file)
@@ -182,6 +182,7 @@ extern void sched_update_nr_prod(int cpu, long delta, bool inc);
 extern void sched_get_nr_running_avg(int *avg, int *iowait_avg, int *big_avg,
                                     unsigned int *max_nr,
                                     unsigned int *big_max_nr);
+extern u64 sched_get_cpu_last_busy_time(int cpu);
 
 extern void calc_global_load(unsigned long ticks);
 
@@ -3021,7 +3022,14 @@ static inline int copy_thread_tls(
 }
 #endif
 extern void flush_thread(void);
-extern void exit_thread(void);
+
+#ifdef CONFIG_HAVE_EXIT_THREAD
+extern void exit_thread(struct task_struct *tsk);
+#else
+static inline void exit_thread(struct task_struct *tsk)
+{
+}
+#endif
 
 extern void exit_files(struct task_struct *);
 extern void __cleanup_sighand(struct sighand_struct *);
index aa30789..98bb781 100644 (file)
@@ -122,6 +122,7 @@ extern char *kstrdup(const char *s, gfp_t gfp);
 extern const char *kstrdup_const(const char *s, gfp_t gfp);
 extern char *kstrndup(const char *s, size_t len, gfp_t gfp);
 extern void *kmemdup(const void *src, size_t len, gfp_t gfp);
+extern char *kmemdup_nul(const char *s, size_t len, gfp_t gfp);
 
 extern char **argv_split(gfp_t gfp, const char *str, int *argcp);
 extern void argv_free(char **argv);
index cb889af..a2b3dfc 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/types.h>
 #include <linux/idr.h>
+#include <linux/kref.h>
 #include <linux/list.h>
 #include <linux/tee.h>
 
  * specific TEE driver.
  */
 
-#define TEE_SHM_MAPPED         0x1     /* Memory mapped by the kernel */
-#define TEE_SHM_DMA_BUF                0x2     /* Memory with dma-buf handle */
+#define TEE_SHM_MAPPED         BIT(0)  /* Memory mapped by the kernel */
+#define TEE_SHM_DMA_BUF                BIT(1)  /* Memory with dma-buf handle */
+#define TEE_SHM_EXT_DMA_BUF    BIT(2)  /* Memory with dma-buf handle */
+#define TEE_SHM_REGISTER       BIT(3)  /* Memory registered in secure world */
+#define TEE_SHM_USER_MAPPED    BIT(4)  /* Memory mapped in user space */
+#define TEE_SHM_POOL           BIT(5)  /* Memory allocated from pool */
 
 struct device;
 struct tee_device;
@@ -38,11 +43,17 @@ struct tee_shm_pool;
  * @teedev:    pointer to this drivers struct tee_device
  * @list_shm:  List of shared memory object owned by this context
  * @data:      driver specific context data, managed by the driver
+ * @refcount:  reference counter for this structure
+ * @releasing:  flag that indicates if context is being released right now.
+ *             It is needed to break circular dependency on context during
+ *              shared memory release.
  */
 struct tee_context {
        struct tee_device *teedev;
        struct list_head list_shm;
        void *data;
+       struct kref refcount;
+       bool releasing;
 };
 
 struct tee_param_memref {
@@ -76,6 +87,8 @@ struct tee_param {
  * @cancel_req:                request cancel of an ongoing invoke or open
  * @supp_revc:         called for supplicant to get a command
  * @supp_send:         called for supplicant to send a response
+ * @shm_register:      register shared memory buffer in TEE
+ * @shm_unregister:    unregister shared memory buffer in TEE
  */
 struct tee_driver_ops {
        void (*get_version)(struct tee_device *teedev,
@@ -94,6 +107,10 @@ struct tee_driver_ops {
                         struct tee_param *param);
        int (*supp_send)(struct tee_context *ctx, u32 ret, u32 num_params,
                         struct tee_param *param);
+       int (*shm_register)(struct tee_context *ctx, struct tee_shm *shm,
+                           struct page **pages, size_t num_pages,
+                           unsigned long start);
+       int (*shm_unregister)(struct tee_context *ctx, struct tee_shm *shm);
 };
 
 /**
@@ -150,6 +167,97 @@ int tee_device_register(struct tee_device *teedev);
 void tee_device_unregister(struct tee_device *teedev);
 
 /**
+ * struct tee_shm - shared memory object
+ * @teedev:    device used to allocate the object
+ * @ctx:       context using the object, if NULL the context is gone
+ * @link       link element
+ * @paddr:     physical address of the shared memory
+ * @kaddr:     virtual address of the shared memory
+ * @size:      size of shared memory
+ * @offset:    offset of buffer in user space
+ * @pages:     locked pages from userspace
+ * @num_pages: number of locked pages
+ * @dmabuf:    dmabuf used to for exporting to user space
+ * @flags:     defined by TEE_SHM_* in tee_drv.h
+ * @id:                unique id of a shared memory object on this device
+ *
+ * This pool is only supposed to be accessed directly from the TEE
+ * subsystem and from drivers that implements their own shm pool manager.
+ */
+struct tee_shm {
+       struct tee_device *teedev;
+       struct tee_context *ctx;
+       struct list_head link;
+       phys_addr_t paddr;
+       void *kaddr;
+       size_t size;
+       unsigned int offset;
+       struct page **pages;
+       size_t num_pages;
+       struct dma_buf *dmabuf;
+       u32 flags;
+       int id;
+};
+
+/**
+ * struct tee_shm_pool_mgr - shared memory manager
+ * @ops:               operations
+ * @private_data:      private data for the shared memory manager
+ */
+struct tee_shm_pool_mgr {
+       const struct tee_shm_pool_mgr_ops *ops;
+       void *private_data;
+};
+
+/**
+ * struct tee_shm_pool_mgr_ops - shared memory pool manager operations
+ * @alloc:             called when allocating shared memory
+ * @free:              called when freeing shared memory
+ * @destroy_poolmgr:   called when destroying the pool manager
+ */
+struct tee_shm_pool_mgr_ops {
+       int (*alloc)(struct tee_shm_pool_mgr *poolmgr, struct tee_shm *shm,
+                    size_t size);
+       void (*free)(struct tee_shm_pool_mgr *poolmgr, struct tee_shm *shm);
+       void (*destroy_poolmgr)(struct tee_shm_pool_mgr *poolmgr);
+};
+
+/**
+ * tee_shm_pool_alloc() - Create a shared memory pool from shm managers
+ * @priv_mgr:  manager for driver private shared memory allocations
+ * @dmabuf_mgr:        manager for dma-buf shared memory allocations
+ *
+ * Allocation with the flag TEE_SHM_DMA_BUF set will use the range supplied
+ * in @dmabuf, others will use the range provided by @priv.
+ *
+ * @returns pointer to a 'struct tee_shm_pool' or an ERR_PTR on failure.
+ */
+struct tee_shm_pool *tee_shm_pool_alloc(struct tee_shm_pool_mgr *priv_mgr,
+                                       struct tee_shm_pool_mgr *dmabuf_mgr);
+
+/*
+ * tee_shm_pool_mgr_alloc_res_mem() - Create a shm manager for reserved
+ * memory
+ * @vaddr:     Virtual address of start of pool
+ * @paddr:     Physical address of start of pool
+ * @size:      Size in bytes of the pool
+ *
+ * @returns pointer to a 'struct tee_shm_pool_mgr' or an ERR_PTR on failure.
+ */
+struct tee_shm_pool_mgr *tee_shm_pool_mgr_alloc_res_mem(unsigned long vaddr,
+                                                       phys_addr_t paddr,
+                                                       size_t size,
+                                                       int min_alloc_order);
+
+/**
+ * tee_shm_pool_mgr_destroy() - Free a shared memory manager
+ */
+static inline void tee_shm_pool_mgr_destroy(struct tee_shm_pool_mgr *poolm)
+{
+       poolm->ops->destroy_poolmgr(poolm);
+}
+
+/**
  * struct tee_shm_pool_mem_info - holds information needed to create a shared
  * memory pool
  * @vaddr:     Virtual address of start of pool
@@ -211,6 +319,40 @@ void *tee_get_drvdata(struct tee_device *teedev);
 struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags);
 
 /**
+ * tee_shm_priv_alloc() - Allocate shared memory privately
+ * @dev:       Device that allocates the shared memory
+ * @size:      Requested size of shared memory
+ *
+ * Allocates shared memory buffer that is not associated with any client
+ * context. Such buffers are owned by TEE driver and used for internal calls.
+ *
+ * @returns a pointer to 'struct tee_shm'
+ */
+struct tee_shm *tee_shm_priv_alloc(struct tee_device *teedev, size_t size);
+
+/**
+ * tee_shm_register() - Register shared memory buffer
+ * @ctx:       Context that registers the shared memory
+ * @addr:      Address is userspace of the shared buffer
+ * @length:    Length of the shared buffer
+ * @flags:     Flags setting properties for the requested shared memory.
+ *
+ * @returns a pointer to 'struct tee_shm'
+ */
+struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr,
+                                size_t length, u32 flags);
+
+/**
+ * tee_shm_is_registered() - Check if shared memory object in registered in TEE
+ * @shm:       Shared memory handle
+ * @returns true if object is registered in TEE
+ */
+static inline bool tee_shm_is_registered(struct tee_shm *shm)
+{
+       return shm && (shm->flags & TEE_SHM_REGISTER);
+}
+
+/**
  * tee_shm_free() - Free shared memory
  * @shm:       Handle to shared memory to free
  */
@@ -260,11 +402,47 @@ void *tee_shm_get_va(struct tee_shm *shm, size_t offs);
 int tee_shm_get_pa(struct tee_shm *shm, size_t offs, phys_addr_t *pa);
 
 /**
+ * tee_shm_get_size() - Get size of shared memory buffer
+ * @shm:       Shared memory handle
+ * @returns size of shared memory
+ */
+static inline size_t tee_shm_get_size(struct tee_shm *shm)
+{
+       return shm->size;
+}
+
+/**
+ * tee_shm_get_pages() - Get list of pages that hold shared buffer
+ * @shm:       Shared memory handle
+ * @num_pages: Number of pages will be stored there
+ * @returns pointer to pages array
+ */
+static inline struct page **tee_shm_get_pages(struct tee_shm *shm,
+                                             size_t *num_pages)
+{
+       *num_pages = shm->num_pages;
+       return shm->pages;
+}
+
+/**
+ * tee_shm_get_page_offset() - Get shared buffer offset from page start
+ * @shm:       Shared memory handle
+ * @returns page offset of shared buffer
+ */
+static inline size_t tee_shm_get_page_offset(struct tee_shm *shm)
+{
+       return shm->offset;
+}
+
+/**
  * tee_shm_get_id() - Get id of a shared memory object
  * @shm:       Shared memory handle
  * @returns id
  */
-int tee_shm_get_id(struct tee_shm *shm);
+static inline int tee_shm_get_id(struct tee_shm *shm)
+{
+       return shm->id;
+}
 
 /**
  * tee_shm_get_from_id() - Find shared memory object and increase reference
@@ -275,4 +453,16 @@ int tee_shm_get_id(struct tee_shm *shm);
  */
 struct tee_shm *tee_shm_get_from_id(struct tee_context *ctx, int id);
 
+static inline bool tee_param_is_memref(struct tee_param *param)
+{
+       switch (param->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
+       case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:
+       case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
+       case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
+               return true;
+       default:
+               return false;
+       }
+}
+
 #endif /*__TEE_DRV_H*/
diff --git a/include/net/dst_cache.h b/include/net/dst_cache.h
new file mode 100644 (file)
index 0000000..151acca
--- /dev/null
@@ -0,0 +1,97 @@
+#ifndef _NET_DST_CACHE_H
+#define _NET_DST_CACHE_H
+
+#include <linux/jiffies.h>
+#include <net/dst.h>
+#if IS_ENABLED(CONFIG_IPV6)
+#include <net/ip6_fib.h>
+#endif
+
+struct dst_cache {
+       struct dst_cache_pcpu __percpu *cache;
+       unsigned long reset_ts;
+};
+
+/**
+ *     dst_cache_get - perform cache lookup
+ *     @dst_cache: the cache
+ *
+ *     The caller should use dst_cache_get_ip4() if it need to retrieve the
+ *     source address to be used when xmitting to the cached dst.
+ *     local BH must be disabled.
+ */
+struct dst_entry *dst_cache_get(struct dst_cache *dst_cache);
+
+/**
+ *     dst_cache_get_ip4 - perform cache lookup and fetch ipv4 source address
+ *     @dst_cache: the cache
+ *     @saddr: return value for the retrieved source address
+ *
+ *     local BH must be disabled.
+ */
+struct rtable *dst_cache_get_ip4(struct dst_cache *dst_cache, __be32 *saddr);
+
+/**
+ *     dst_cache_set_ip4 - store the ipv4 dst into the cache
+ *     @dst_cache: the cache
+ *     @dst: the entry to be cached
+ *     @saddr: the source address to be stored inside the cache
+ *
+ *     local BH must be disabled.
+ */
+void dst_cache_set_ip4(struct dst_cache *dst_cache, struct dst_entry *dst,
+                      __be32 saddr);
+
+#if IS_ENABLED(CONFIG_IPV6)
+
+/**
+ *     dst_cache_set_ip6 - store the ipv6 dst into the cache
+ *     @dst_cache: the cache
+ *     @dst: the entry to be cached
+ *     @saddr: the source address to be stored inside the cache
+ *
+ *     local BH must be disabled.
+ */
+void dst_cache_set_ip6(struct dst_cache *dst_cache, struct dst_entry *dst,
+                      const struct in6_addr *addr);
+
+/**
+ *     dst_cache_get_ip6 - perform cache lookup and fetch ipv6 source address
+ *     @dst_cache: the cache
+ *     @saddr: return value for the retrieved source address
+ *
+ *     local BH must be disabled.
+ */
+struct dst_entry *dst_cache_get_ip6(struct dst_cache *dst_cache,
+                                   struct in6_addr *saddr);
+#endif
+
+/**
+ *     dst_cache_reset - invalidate the cache contents
+ *     @dst_cache: the cache
+ *
+ *     This do not free the cached dst to avoid races and contentions.
+ *     the dst will be freed on later cache lookup.
+ */
+static inline void dst_cache_reset(struct dst_cache *dst_cache)
+{
+       dst_cache->reset_ts = jiffies;
+}
+
+/**
+ *     dst_cache_init - initialize the cache, allocating the required storage
+ *     @dst_cache: the cache
+ *     @gfp: allocation flags
+ */
+int dst_cache_init(struct dst_cache *dst_cache, gfp_t gfp);
+
+/**
+ *     dst_cache_destroy - empty the cache and free the allocated storage
+ *     @dst_cache: the cache
+ *
+ *     No synchronization is enforced: it must be called only when the cache
+ *     is unsed.
+ */
+void dst_cache_destroy(struct dst_cache *dst_cache);
+
+#endif
index 9c2c044..d143c84 100644 (file)
@@ -5,6 +5,8 @@
 #include <linux/netdevice.h>
 #include <linux/if_tunnel.h>
 #include <linux/ip6_tunnel.h>
+#include <net/ip_tunnels.h>
+#include <net/dst_cache.h>
 
 #define IP6TUNNEL_ERR_TIMEO (30*HZ)
 
@@ -32,12 +34,6 @@ struct __ip6_tnl_parm {
        __be32                  o_key;
 };
 
-struct ip6_tnl_dst {
-       seqlock_t lock;
-       struct dst_entry __rcu *dst;
-       u32 cookie;
-};
-
 /* IPv6 tunnel */
 struct ip6_tnl {
        struct ip6_tnl __rcu *next;     /* next tunnel in list */
@@ -45,7 +41,7 @@ struct ip6_tnl {
        struct net *net;        /* netns for packet i/o */
        struct __ip6_tnl_parm parms;    /* tunnel configuration parameters */
        struct flowi fl;        /* flowi template for xmit */
-       struct ip6_tnl_dst __percpu *dst_cache; /* cached dst */
+       struct dst_cache dst_cache;     /* cached dst */
 
        int err_count;
        unsigned long err_time;
@@ -65,11 +61,6 @@ struct ipv6_tlv_tnl_enc_lim {
        __u8 encap_limit;       /* tunnel encapsulation limit   */
 } __packed;
 
-struct dst_entry *ip6_tnl_dst_get(struct ip6_tnl *t);
-int ip6_tnl_dst_init(struct ip6_tnl *t);
-void ip6_tnl_dst_destroy(struct ip6_tnl *t);
-void ip6_tnl_dst_reset(struct ip6_tnl *t);
-void ip6_tnl_dst_set(struct ip6_tnl *t, struct dst_entry *dst);
 int ip6_tnl_rcv_ctl(struct ip6_tnl *t, const struct in6_addr *laddr,
                const struct in6_addr *raddr);
 int ip6_tnl_xmit_ctl(struct ip6_tnl *t, const struct in6_addr *laddr,
index 9c5638a..0dbce55 100644 (file)
@@ -28,8 +28,8 @@ struct nf_queue_handler {
                                                struct nf_hook_ops *ops);
 };
 
-void nf_register_queue_handler(const struct nf_queue_handler *qh);
-void nf_unregister_queue_handler(void);
+void nf_register_queue_handler(struct net *net, const struct nf_queue_handler *qh);
+void nf_unregister_queue_handler(struct net *net);
 void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict);
 
 void nf_queue_entry_get_refs(struct nf_queue_entry *entry);
index 0e31727..5ffaea4 100644 (file)
@@ -745,7 +745,10 @@ static inline int nla_parse_nested(struct nlattr *tb[], int maxtype,
  */
 static inline int nla_put_u8(struct sk_buff *skb, int attrtype, u8 value)
 {
-       return nla_put(skb, attrtype, sizeof(u8), &value);
+       /* temporary variables to work around GCC PR81715 with asan-stack=1 */
+       u8 tmp = value;
+
+       return nla_put(skb, attrtype, sizeof(u8), &tmp);
 }
 
 /**
@@ -756,7 +759,9 @@ static inline int nla_put_u8(struct sk_buff *skb, int attrtype, u8 value)
  */
 static inline int nla_put_u16(struct sk_buff *skb, int attrtype, u16 value)
 {
-       return nla_put(skb, attrtype, sizeof(u16), &value);
+       u16 tmp = value;
+
+       return nla_put(skb, attrtype, sizeof(u16), &tmp);
 }
 
 /**
@@ -767,7 +772,9 @@ static inline int nla_put_u16(struct sk_buff *skb, int attrtype, u16 value)
  */
 static inline int nla_put_be16(struct sk_buff *skb, int attrtype, __be16 value)
 {
-       return nla_put(skb, attrtype, sizeof(__be16), &value);
+       __be16 tmp = value;
+
+       return nla_put(skb, attrtype, sizeof(__be16), &tmp);
 }
 
 /**
@@ -778,7 +785,9 @@ static inline int nla_put_be16(struct sk_buff *skb, int attrtype, __be16 value)
  */
 static inline int nla_put_net16(struct sk_buff *skb, int attrtype, __be16 value)
 {
-       return nla_put_be16(skb, attrtype | NLA_F_NET_BYTEORDER, value);
+       __be16 tmp = value;
+
+       return nla_put_be16(skb, attrtype | NLA_F_NET_BYTEORDER, tmp);
 }
 
 /**
@@ -789,7 +798,9 @@ static inline int nla_put_net16(struct sk_buff *skb, int attrtype, __be16 value)
  */
 static inline int nla_put_le16(struct sk_buff *skb, int attrtype, __le16 value)
 {
-       return nla_put(skb, attrtype, sizeof(__le16), &value);
+       __le16 tmp = value;
+
+       return nla_put(skb, attrtype, sizeof(__le16), &tmp);
 }
 
 /**
@@ -800,7 +811,9 @@ static inline int nla_put_le16(struct sk_buff *skb, int attrtype, __le16 value)
  */
 static inline int nla_put_u32(struct sk_buff *skb, int attrtype, u32 value)
 {
-       return nla_put(skb, attrtype, sizeof(u32), &value);
+       u32 tmp = value;
+
+       return nla_put(skb, attrtype, sizeof(u32), &tmp);
 }
 
 /**
@@ -811,7 +824,9 @@ static inline int nla_put_u32(struct sk_buff *skb, int attrtype, u32 value)
  */
 static inline int nla_put_be32(struct sk_buff *skb, int attrtype, __be32 value)
 {
-       return nla_put(skb, attrtype, sizeof(__be32), &value);
+       __be32 tmp = value;
+
+       return nla_put(skb, attrtype, sizeof(__be32), &tmp);
 }
 
 /**
@@ -822,7 +837,9 @@ static inline int nla_put_be32(struct sk_buff *skb, int attrtype, __be32 value)
  */
 static inline int nla_put_net32(struct sk_buff *skb, int attrtype, __be32 value)
 {
-       return nla_put_be32(skb, attrtype | NLA_F_NET_BYTEORDER, value);
+       __be32 tmp = value;
+
+       return nla_put_be32(skb, attrtype | NLA_F_NET_BYTEORDER, tmp);
 }
 
 /**
@@ -833,7 +850,9 @@ static inline int nla_put_net32(struct sk_buff *skb, int attrtype, __be32 value)
  */
 static inline int nla_put_le32(struct sk_buff *skb, int attrtype, __le32 value)
 {
-       return nla_put(skb, attrtype, sizeof(__le32), &value);
+       __le32 tmp = value;
+
+       return nla_put(skb, attrtype, sizeof(__le32), &tmp);
 }
 
 /**
@@ -844,7 +863,9 @@ static inline int nla_put_le32(struct sk_buff *skb, int attrtype, __le32 value)
  */
 static inline int nla_put_u64(struct sk_buff *skb, int attrtype, u64 value)
 {
-       return nla_put(skb, attrtype, sizeof(u64), &value);
+       u64 tmp = value;
+
+       return nla_put(skb, attrtype, sizeof(u64), &tmp);
 }
 
 /**
@@ -855,7 +876,9 @@ static inline int nla_put_u64(struct sk_buff *skb, int attrtype, u64 value)
  */
 static inline int nla_put_be64(struct sk_buff *skb, int attrtype, __be64 value)
 {
-       return nla_put(skb, attrtype, sizeof(__be64), &value);
+       __be64 tmp = value;
+
+       return nla_put(skb, attrtype, sizeof(__be64), &tmp);
 }
 
 /**
@@ -866,7 +889,9 @@ static inline int nla_put_be64(struct sk_buff *skb, int attrtype, __be64 value)
  */
 static inline int nla_put_net64(struct sk_buff *skb, int attrtype, __be64 value)
 {
-       return nla_put_be64(skb, attrtype | NLA_F_NET_BYTEORDER, value);
+       __be64 tmp = value;
+
+       return nla_put_be64(skb, attrtype | NLA_F_NET_BYTEORDER, tmp);
 }
 
 /**
@@ -877,7 +902,9 @@ static inline int nla_put_net64(struct sk_buff *skb, int attrtype, __be64 value)
  */
 static inline int nla_put_le64(struct sk_buff *skb, int attrtype, __le64 value)
 {
-       return nla_put(skb, attrtype, sizeof(__le64), &value);
+       __le64 tmp = value;
+
+       return nla_put(skb, attrtype, sizeof(__le64), &tmp);
 }
 
 /**
@@ -888,7 +915,9 @@ static inline int nla_put_le64(struct sk_buff *skb, int attrtype, __le64 value)
  */
 static inline int nla_put_s8(struct sk_buff *skb, int attrtype, s8 value)
 {
-       return nla_put(skb, attrtype, sizeof(s8), &value);
+       s8 tmp = value;
+
+       return nla_put(skb, attrtype, sizeof(s8), &tmp);
 }
 
 /**
@@ -899,7 +928,9 @@ static inline int nla_put_s8(struct sk_buff *skb, int attrtype, s8 value)
  */
 static inline int nla_put_s16(struct sk_buff *skb, int attrtype, s16 value)
 {
-       return nla_put(skb, attrtype, sizeof(s16), &value);
+       s16 tmp = value;
+
+       return nla_put(skb, attrtype, sizeof(s16), &tmp);
 }
 
 /**
@@ -910,7 +941,9 @@ static inline int nla_put_s16(struct sk_buff *skb, int attrtype, s16 value)
  */
 static inline int nla_put_s32(struct sk_buff *skb, int attrtype, s32 value)
 {
-       return nla_put(skb, attrtype, sizeof(s32), &value);
+       s32 tmp = value;
+
+       return nla_put(skb, attrtype, sizeof(s32), &tmp);
 }
 
 /**
@@ -921,7 +954,9 @@ static inline int nla_put_s32(struct sk_buff *skb, int attrtype, s32 value)
  */
 static inline int nla_put_s64(struct sk_buff *skb, int attrtype, s64 value)
 {
-       return nla_put(skb, attrtype, sizeof(s64), &value);
+       s64 tmp = value;
+
+       return nla_put(skb, attrtype, sizeof(s64), &tmp);
 }
 
 /**
@@ -969,7 +1004,9 @@ static inline int nla_put_msecs(struct sk_buff *skb, int attrtype,
 static inline int nla_put_in_addr(struct sk_buff *skb, int attrtype,
                                  __be32 addr)
 {
-       return nla_put_be32(skb, attrtype, addr);
+       __be32 tmp = addr;
+
+       return nla_put_be32(skb, attrtype, tmp);
 }
 
 /**
index 38aa498..36d7235 100644 (file)
@@ -5,11 +5,13 @@
 
 struct proc_dir_entry;
 struct nf_logger;
+struct nf_queue_handler;
 
 struct netns_nf {
 #if defined CONFIG_PROC_FS
        struct proc_dir_entry *proc_netfilter;
 #endif
+       const struct nf_queue_handler __rcu *queue_handler;
        const struct nf_logger __rcu *nf_loggers[NFPROTO_NUMPROTO];
 #ifdef CONFIG_SYSCTL
        struct ctl_table_header *nf_log_dir_header;
index 76e0b5f..3618cdf 100644 (file)
@@ -167,6 +167,17 @@ static inline void red_set_vars(struct red_vars *v)
        v->qcount       = -1;
 }
 
+static inline bool red_check_params(u32 qth_min, u32 qth_max, u8 Wlog)
+{
+       if (fls(qth_min) + Wlog > 32)
+               return false;
+       if (fls(qth_max) + Wlog > 32)
+               return false;
+       if (qth_max < qth_min)
+               return false;
+       return true;
+}
+
 static inline void red_set_parms(struct red_parms *p,
                                 u32 qth_min, u32 qth_max, u8 Wlog, u8 Plog,
                                 u8 Scell_log, u8 *stab, u32 max_P)
@@ -178,7 +189,7 @@ static inline void red_set_parms(struct red_parms *p,
        p->qth_max      = qth_max << Wlog;
        p->Wlog         = Wlog;
        p->Plog         = Plog;
-       if (delta < 0)
+       if (delta <= 0)
                delta = 1;
        p->qth_delta    = delta;
        if (!max_P) {
index cd85a4a..65316c6 100644 (file)
@@ -132,6 +132,9 @@ struct module_instance_info {
 /* Begin service specific definitions and structures */
 
 #define ADSP_ADM_VERSION    0x00070000
+#define ADSP_ASM_API_VERSION_V2   2
+#define ADSP_ADM_API_VERSION_V3  3
+#define ADSP_AFE_API_VERSION_V3  3
 
 #define ADM_CMD_SHARED_MEM_MAP_REGIONS    0x00010322
 #define ADM_CMDRSP_SHARED_MEM_MAP_REGIONS 0x00010323
index 84087de..e3cfb10 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -87,6 +87,11 @@ struct msm_pcm_channel_mixer {
        bool enable;
        int rule;
        int channel_weight[ADM_MAX_CHANNELS][ADM_MAX_CHANNELS];
+       int port_idx;
+       int input_channel;
+       uint16_t in_ch_map[ADM_MAX_CHANNELS];
+       uint16_t out_ch_map[ADM_MAX_CHANNELS];
+       int override_cfg;
 };
 
 int srs_trumedia_open(int port_id, int copp_idx, __s32 srs_tech_id,
@@ -162,7 +167,8 @@ int adm_get_indexes_from_copp_id(int copp_id, int *port_idx, int *copp_idx);
 
 int adm_set_pspd_matrix_params(int port_id, int copp_idx,
                                unsigned int session_id,
-                               char *params, uint32_t params_length);
+                               char *params, uint32_t params_length,
+                               int session_type);
 
 int adm_set_downmix_params(int port_id, int copp_idx,
                                unsigned int session_id, char *params,
index b1c3b0b..5031e62 100644 (file)
@@ -368,4 +368,5 @@ int afe_tdm_port_start(u16 port_id, struct afe_tdm_port_config *tdm_port,
 void afe_set_routing_callback(routing_cb);
 int afe_get_av_dev_drift(struct afe_param_id_dev_timing_stats *timing_stats,
                u16 port);
+int afe_get_svc_version(uint32_t service_id);
 #endif /* __Q6AFE_V2_H__ */
index ad19e73..cd9c6db 100644 (file)
@@ -134,12 +134,12 @@ DECLARE_EVENT_CLASS(clk_parent,
 
        TP_STRUCT__entry(
                __string(        name,           core->name                )
-               __string(        pname,          parent->name              )
+               __string(        pname, parent ? parent->name : "none"     )
        ),
 
        TP_fast_assign(
                __assign_str(name, core->name);
-               __assign_str(pname, parent->name);
+               __assign_str(pname, parent ? parent->name : "none");
        ),
 
        TP_printk("%s %s", __get_str(name), __get_str(pname))
index 589df6f..0cdf6cc 100644 (file)
@@ -138,7 +138,8 @@ TRACE_DEFINE_ENUM(CP_TRIMMED);
                { CP_NO_SPC_ROLL,       "no space roll forward" },      \
                { CP_NODE_NEED_CP,      "node needs cp" },              \
                { CP_FASTBOOT_MODE,     "fastboot mode" },              \
-               { CP_SPEC_LOG_NUM,      "log type is 2" })
+               { CP_SPEC_LOG_NUM,      "log type is 2" },              \
+               { CP_RECOVER_DIR,       "dir needs recovery" })
 
 struct victim_sel_policy;
 struct f2fs_map_blocks;
index 688782e..4b9eb06 100644 (file)
@@ -50,6 +50,7 @@
 
 #define TEE_GEN_CAP_GP         (1 << 0)/* GlobalPlatform compliant TEE */
 #define TEE_GEN_CAP_PRIVILEGED (1 << 1)/* Privileged device (for supplicant) */
+#define TEE_GEN_CAP_REG_MEM    (1 << 2)/* Supports registering shared memory */
 
 /*
  * TEE Implementation ID
@@ -154,6 +155,13 @@ struct tee_ioctl_buf_data {
  */
 #define TEE_IOCTL_PARAM_ATTR_TYPE_MASK         0xff
 
+/* Meta parameter carrying extra information about the message. */
+#define TEE_IOCTL_PARAM_ATTR_META              0x100
+
+/* Mask of all known attr bits */
+#define TEE_IOCTL_PARAM_ATTR_MASK \
+       (TEE_IOCTL_PARAM_ATTR_TYPE_MASK | TEE_IOCTL_PARAM_ATTR_META)
+
 /*
  * Matches TEEC_LOGIN_* in GP TEE Client API
  * Are only defined for GP compliant TEEs
@@ -332,6 +340,35 @@ struct tee_iocl_supp_send_arg {
 #define TEE_IOC_SUPPL_SEND     _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 7, \
                                     struct tee_ioctl_buf_data)
 
+/**
+ * struct tee_ioctl_shm_register_data - Shared memory register argument
+ * @addr:      [in] Start address of shared memory to register
+ * @length:    [in/out] Length of shared memory to register
+ * @flags:     [in/out] Flags to/from registration.
+ * @id:                [out] Identifier of the shared memory
+ *
+ * The flags field should currently be zero as input. Updated by the call
+ * with actual flags as defined by TEE_IOCTL_SHM_* above.
+ * This structure is used as argument for TEE_IOC_SHM_REGISTER below.
+ */
+struct tee_ioctl_shm_register_data {
+       __u64 addr;
+       __u64 length;
+       __u32 flags;
+       __s32 id;
+};
+
+/**
+ * TEE_IOC_SHM_REGISTER - Register shared memory argument
+ *
+ * Registers shared memory between the user space process and secure OS.
+ *
+ * Returns a file descriptor on success or < 0 on failure
+ *
+ * The shared memory is unregisterred when the descriptor is closed.
+ */
+#define TEE_IOC_SHM_REGISTER   _IOWR(TEE_IOC_MAGIC, TEE_IOC_BASE + 9, \
+                                    struct tee_ioctl_shm_register_data)
 /*
  * Five syscalls are used when communicating with the TEE driver.
  * open(): opens the device associated with the driver
index 4c3773c..f1fd155 100644 (file)
@@ -84,20 +84,24 @@ static atomic_t entry_count;
 
 static async_cookie_t lowest_in_progress(struct async_domain *domain)
 {
-       struct list_head *pending;
+       struct async_entry *first = NULL;
        async_cookie_t ret = ASYNC_COOKIE_MAX;
        unsigned long flags;
 
        spin_lock_irqsave(&async_lock, flags);
 
-       if (domain)
-               pending = &domain->pending;
-       else
-               pending = &async_global_pending;
+       if (domain) {
+               if (!list_empty(&domain->pending))
+                       first = list_first_entry(&domain->pending,
+                                       struct async_entry, domain_list);
+       } else {
+               if (!list_empty(&async_global_pending))
+                       first = list_first_entry(&async_global_pending,
+                                       struct async_entry, global_list);
+       }
 
-       if (!list_empty(pending))
-               ret = list_first_entry(pending, struct async_entry,
-                                      domain_list)->cookie;
+       if (first)
+               ret = first->cookie;
 
        spin_unlock_irqrestore(&async_lock, flags);
        return ret;
diff --git a/kernel/configs/android-base.config b/kernel/configs/android-base.config
new file mode 100644 (file)
index 0000000..d708290
--- /dev/null
@@ -0,0 +1,160 @@
+#  KEEP ALPHABETICALLY SORTED
+# CONFIG_DEVKMEM is not set
+# CONFIG_DEVMEM is not set
+# CONFIG_FHANDLE is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_NFSD is not set
+# CONFIG_NFS_FS is not set
+# CONFIG_OABI_COMPAT is not set
+# CONFIG_SYSVIPC is not set
+# CONFIG_USELIB is not set
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_ARMV8_DEPRECATED=y
+CONFIG_ASHMEM=y
+CONFIG_AUDIT=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_BPF=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_CP15_BARRIER_EMULATION=y
+CONFIG_DEFAULT_SECURITY_SELINUX=y
+CONFIG_EMBEDDED=y
+CONFIG_FB=y
+CONFIG_HARDENED_USERCOPY=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_INET=y
+CONFIG_INET_DIAG_DESTROY=y
+CONFIG_INET_ESP=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IPV6=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_SECURITY=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_NET=y
+CONFIG_NETDEVICES=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
+CONFIG_NETFILTER_XT_TARGET_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_TRACE=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_CLS_U32=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_KEY=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_NAT=y
+CONFIG_NO_HZ=y
+CONFIG_PACKET=y
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_MPPE=y
+CONFIG_PREEMPT=y
+CONFIG_QUOTA=y
+CONFIG_RANDOMIZE_BASE=y
+CONFIG_RTC_CLASS=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_SECCOMP=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SETEND_EMULATION=y
+CONFIG_STAGING=y
+CONFIG_SWP_EMULATION=y
+CONFIG_SYNC=y
+CONFIG_TUN=y
+CONFIG_UNIX=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_MIDI=y
+CONFIG_USB_OTG_WAKELOCK=y
+CONFIG_XFRM_USER=y
diff --git a/kernel/configs/android-recommended.config b/kernel/configs/android-recommended.config
new file mode 100644 (file)
index 0000000..297756b
--- /dev/null
@@ -0,0 +1,125 @@
+#  KEEP ALPHABETICALLY SORTED
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_NF_CONNTRACK_SIP is not set
+# CONFIG_PM_WAKELOCKS_GC is not set
+# CONFIG_VT is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_COMPACTION=y
+CONFIG_DEBUG_RODATA=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_UEVENT=y
+CONFIG_DM_VERITY=y
+CONFIG_DM_VERITY_FEC=y
+CONFIG_DRAGONRISE_FF=y
+CONFIG_ENABLE_DEFAULT_TRACERS=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_FUSE_FS=y
+CONFIG_GREENASIA_FF=y
+CONFIG_HIDRAW=y
+CONFIG_HID_A4TECH=y
+CONFIG_HID_ACRUX=y
+CONFIG_HID_ACRUX_FF=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_CYPRESS=y
+CONFIG_HID_DRAGONRISE=y
+CONFIG_HID_ELECOM=y
+CONFIG_HID_EMS_FF=y
+CONFIG_HID_EZKEY=y
+CONFIG_HID_GREENASIA=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_HOLTEK=y
+CONFIG_HID_KENSINGTON=y
+CONFIG_HID_KEYTOUCH=y
+CONFIG_HID_KYE=y
+CONFIG_HID_LCPOWER=y
+CONFIG_HID_LOGITECH=y
+CONFIG_HID_LOGITECH_DJ=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+CONFIG_HID_MULTITOUCH=y
+CONFIG_HID_NTRIG=y
+CONFIG_HID_ORTEK=y
+CONFIG_HID_PANTHERLORD=y
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_PICOLCD=y
+CONFIG_HID_PRIMAX=y
+CONFIG_HID_PRODIKEYS=y
+CONFIG_HID_ROCCAT=y
+CONFIG_HID_SAITEK=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SMARTJOYPLUS=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SPEEDLINK=y
+CONFIG_HID_SUNPLUS=y
+CONFIG_HID_THRUSTMASTER=y
+CONFIG_HID_TIVO=y
+CONFIG_HID_TOPSEED=y
+CONFIG_HID_TWINHAN=y
+CONFIG_HID_UCLOGIC=y
+CONFIG_HID_WACOM=y
+CONFIG_HID_WALTOP=y
+CONFIG_HID_WIIMOTE=y
+CONFIG_HID_ZEROPLUS=y
+CONFIG_HID_ZYDACRON=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_GPIO=y
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_TABLET=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_ION=y
+CONFIG_JOYSTICK_XPAD=y
+CONFIG_JOYSTICK_XPAD_FF=y
+CONFIG_JOYSTICK_XPAD_LEDS=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_KSM=y
+CONFIG_LOGIG940_FF=y
+CONFIG_LOGIRUMBLEPAD2_FF=y
+CONFIG_LOGITECH_FF=y
+CONFIG_MD=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MSDOS_FS=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_PANTHERLORD_FF=y
+CONFIG_PERF_EVENTS=y
+CONFIG_PM_DEBUG=y
+CONFIG_PM_RUNTIME=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+CONFIG_POWER_SUPPLY=y
+CONFIG_PSTORE=y
+CONFIG_PSTORE_CONSOLE=y
+CONFIG_PSTORE_RAM=y
+CONFIG_SCHEDSTATS=y
+CONFIG_SMARTJOYPLUS_FF=y
+CONFIG_SND=y
+CONFIG_SOUND=y
+CONFIG_SUSPEND_TIME=y
+CONFIG_TABLET_USB_ACECAD=y
+CONFIG_TABLET_USB_AIPTEK=y
+CONFIG_TABLET_USB_GTCO=y
+CONFIG_TABLET_USB_HANWANG=y
+CONFIG_TABLET_USB_KBTAB=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_TASK_XACCT=y
+CONFIG_TIMER_STATS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_UHID=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_HIDDEV=y
+CONFIG_USB_USBNET=y
+CONFIG_VFAT_FS=y
index 6aebd44..06d54f5 100644 (file)
@@ -764,7 +764,7 @@ void do_exit(long code)
                disassociate_ctty(1);
        exit_task_namespaces(tsk);
        exit_task_work(tsk);
-       exit_thread();
+       exit_thread(tsk);
 
        /*
         * Flush inherited counters to the parent - before the parent
index 71e277d..a0eeedb 100644 (file)
@@ -2875,6 +2875,15 @@ static struct module *setup_load_info(struct load_info *info, int flags)
        return mod;
 }
 
+static void check_modinfo_retpoline(struct module *mod, struct load_info *info)
+{
+       if (retpoline_module_ok(get_modinfo(info, "retpoline")))
+               return;
+
+       pr_warn("%s: loading module not compiled with retpoline compiler.\n",
+               mod->name);
+}
+
 static int check_modinfo(struct module *mod, struct load_info *info, int flags)
 {
        const char *modmagic = get_modinfo(info, "vermagic");
@@ -2901,6 +2910,8 @@ static int check_modinfo(struct module *mod, struct load_info *info, int flags)
                add_taint_module(mod, TAINT_OOT_MODULE, LOCKDEP_STILL_OK);
        }
 
+       check_modinfo_retpoline(mod, info);
+
        if (get_modinfo(info, "staging")) {
                add_taint_module(mod, TAINT_CRAP, LOCKDEP_STILL_OK);
                pr_warn("%s: module is from the staging directory, the quality "
index 99513e1..9cd8e18 100644 (file)
@@ -44,7 +44,7 @@ int prof_on __read_mostly;
 EXPORT_SYMBOL_GPL(prof_on);
 
 static cpumask_var_t prof_cpu_mask;
-#ifdef CONFIG_SMP
+#if defined(CONFIG_SMP) && defined(CONFIG_PROC_FS)
 static DEFINE_PER_CPU(struct profile_hit *[2], cpu_profile_hits);
 static DEFINE_PER_CPU(int, cpu_profile_flip);
 static DEFINE_MUTEX(profile_flip_mutex);
@@ -201,7 +201,7 @@ int profile_event_unregister(enum profile_type type, struct notifier_block *n)
 }
 EXPORT_SYMBOL_GPL(profile_event_unregister);
 
-#ifdef CONFIG_SMP
+#if defined(CONFIG_SMP) && defined(CONFIG_PROC_FS)
 /*
  * Each cpu has a pair of open-addressed hashtables for pending
  * profile hits. read_profile() IPI's all cpus to request them
index 41a8fdb..03b59c3 100644 (file)
@@ -6631,6 +6631,19 @@ static void rq_attach_root(struct rq *rq, struct root_domain *rd)
                call_rcu_sched(&old_rd->rcu, free_rootdomain);
 }
 
+void sched_get_rd(struct root_domain *rd)
+{
+       atomic_inc(&rd->refcount);
+}
+
+void sched_put_rd(struct root_domain *rd)
+{
+       if (!atomic_dec_and_test(&rd->refcount))
+               return;
+
+       call_rcu_sched(&rd->rcu, free_rootdomain);
+}
+
 static int init_rootdomain(struct root_domain *rd)
 {
        memset(rd, 0, sizeof(*rd));
index 2ea3a43..ce683b0 100644 (file)
@@ -6596,10 +6596,22 @@ static int sched_group_energy(struct energy_env *eenv)
 {
        struct cpumask visit_cpus;
        u64 total_energy = 0;
+       int cpu_count;
 
        WARN_ON(!eenv->sg_top->sge);
 
        cpumask_copy(&visit_cpus, sched_group_cpus(eenv->sg_top));
+       /* If a cpu is hotplugged in while we are in this function,
+        * it does not appear in the existing visit_cpus mask
+        * which came from the sched_group pointer of the
+        * sched_domain pointed at by sd_ea for either the prev
+        * or next cpu and was dereferenced in __energy_diff.
+        * Since we will dereference sd_scs later as we iterate
+        * through the CPUs we expect to visit, new CPUs can
+        * be present which are not in the visit_cpus mask.
+        * Guard this with cpu_count.
+        */
+       cpu_count = cpumask_weight(&visit_cpus);
 
        while (!cpumask_empty(&visit_cpus)) {
                struct sched_group *sg_shared_cap = NULL;
@@ -6609,6 +6621,8 @@ static int sched_group_energy(struct energy_env *eenv)
                /*
                 * Is the group utilization affected by cpus outside this
                 * sched_group?
+                * This sd may have groups with cpus which were not present
+                * when we took visit_cpus.
                 */
                sd = rcu_dereference(per_cpu(sd_scs, cpu));
 
@@ -6658,8 +6672,24 @@ static int sched_group_energy(struct energy_env *eenv)
 
                                total_energy += sg_busy_energy + sg_idle_energy;
 
-                               if (!sd->child)
+                               if (!sd->child) {
+                                       /*
+                                        * cpu_count here is the number of
+                                        * cpus we expect to visit in this
+                                        * calculation. If we race against
+                                        * hotplug, we can have extra cpus
+                                        * added to the groups we are
+                                        * iterating which do not appear in
+                                        * the visit_cpus mask. In that case
+                                        * we are not able to calculate energy
+                                        * without restarting so we will bail
+                                        * out and use prev_cpu this time.
+                                        */
+                                       if (!cpu_count)
+                                               return -EINVAL;
                                        cpumask_xor(&visit_cpus, &visit_cpus, sched_group_cpus(sg));
+                                       cpu_count--;
+                               }
 
                                if (cpumask_equal(sched_group_cpus(sg), sched_group_cpus(eenv->sg_top)))
                                        goto next_cpu;
@@ -6671,6 +6701,9 @@ static int sched_group_energy(struct energy_env *eenv)
                 * If we raced with hotplug and got an sd NULL-pointer;
                 * returning a wrong energy estimation is better than
                 * entering an infinite loop.
+                * Specifically: If a cpu is unplugged after we took
+                * the visit_cpus mask, it no longer has an sd_scs
+                * pointer, so when we dereference it, we get NULL.
                 */
                if (cpumask_test_cpu(cpu, &visit_cpus))
                        return -EINVAL;
index baad64b..05d635c 100644 (file)
@@ -2276,9 +2276,8 @@ static void push_rt_tasks(struct rq *rq)
  * the rt_loop_next will cause the iterator to perform another scan.
  *
  */
-static int rto_next_cpu(struct rq *rq)
+static int rto_next_cpu(struct root_domain *rd)
 {
-       struct root_domain *rd = rq->rd;
        int next;
        int cpu;
 
@@ -2354,19 +2353,24 @@ static void tell_cpu_to_push(struct rq *rq)
         * Otherwise it is finishing up and an ipi needs to be sent.
         */
        if (rq->rd->rto_cpu < 0)
-               cpu = rto_next_cpu(rq);
+               cpu = rto_next_cpu(rq->rd);
 
        raw_spin_unlock(&rq->rd->rto_lock);
 
        rto_start_unlock(&rq->rd->rto_loop_start);
 
-       if (cpu >= 0)
+       if (cpu >= 0) {
+               /* Make sure the rd does not get freed while pushing */
+               sched_get_rd(rq->rd);
                irq_work_queue_on(&rq->rd->rto_push_work, cpu);
+       }
 }
 
 /* Called from hardirq context */
 void rto_push_irq_work_func(struct irq_work *work)
 {
+       struct root_domain *rd =
+               container_of(work, struct root_domain, rto_push_work);
        struct rq *rq;
        int cpu;
 
@@ -2382,18 +2386,20 @@ void rto_push_irq_work_func(struct irq_work *work)
                raw_spin_unlock(&rq->lock);
        }
 
-       raw_spin_lock(&rq->rd->rto_lock);
+       raw_spin_lock(&rd->rto_lock);
 
        /* Pass the IPI to the next rt overloaded queue */
-       cpu = rto_next_cpu(rq);
+       cpu = rto_next_cpu(rd);
 
-       raw_spin_unlock(&rq->rd->rto_lock);
+       raw_spin_unlock(&rd->rto_lock);
 
-       if (cpu < 0)
+       if (cpu < 0) {
+               sched_put_rd(rd);
                return;
+       }
 
        /* Try the next RT overloaded CPU */
-       irq_work_queue_on(&rq->rd->rto_push_work, cpu);
+       irq_work_queue_on(&rd->rto_push_work, cpu);
 }
 #endif /* HAVE_RT_PUSH_IPI */
 
index 6ef3a59..b6cd129 100644 (file)
@@ -673,6 +673,8 @@ struct root_domain {
 };
 
 extern struct root_domain def_root_domain;
+extern void sched_get_rd(struct root_domain *rd);
+extern void sched_put_rd(struct root_domain *rd);
 
 #ifdef HAVE_RT_PUSH_IPI
 extern void rto_push_irq_work_func(struct irq_work *work);
@@ -1272,6 +1274,11 @@ static inline bool is_max_capacity_cpu(int cpu)
        return cpu_max_possible_capacity(cpu) == max_possible_capacity;
 }
 
+static inline bool is_min_capacity_cpu(int cpu)
+{
+       return cpu_max_possible_capacity(cpu) == min_max_possible_capacity;
+}
+
 /*
  * 'load' is in reference to "best cpu" at its best frequency.
  * Scale that in reference to a given cpu, accounting for how bad it is
index ba5a326..f03ed68 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012, 2015-2017, 2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -119,6 +119,43 @@ void sched_get_nr_running_avg(int *avg, int *iowait_avg, int *big_avg,
 }
 EXPORT_SYMBOL(sched_get_nr_running_avg);
 
+static DEFINE_PER_CPU(atomic64_t, last_busy_time) = ATOMIC64_INIT(0);
+
+#define BUSY_NR_RUN            3
+#define BUSY_LOAD_FACTOR       10
+
+#ifdef CONFIG_SCHED_HMP
+static inline void update_last_busy_time(int cpu, bool dequeue,
+                               unsigned long prev_nr_run, u64 curr_time)
+{
+       bool nr_run_trigger = false, load_trigger = false;
+
+       if (!hmp_capable() || is_min_capacity_cpu(cpu))
+               return;
+
+       if (prev_nr_run >= BUSY_NR_RUN && per_cpu(nr, cpu) < BUSY_NR_RUN)
+               nr_run_trigger = true;
+
+       if (dequeue) {
+               u64 load;
+
+               load = cpu_rq(cpu)->hmp_stats.cumulative_runnable_avg;
+               load = scale_load_to_cpu(load, cpu);
+
+               if (load * BUSY_LOAD_FACTOR > sched_ravg_window)
+                       load_trigger = true;
+       }
+
+       if (nr_run_trigger || load_trigger)
+               atomic64_set(&per_cpu(last_busy_time, cpu), curr_time);
+}
+#else
+static inline void update_last_busy_time(int cpu, bool dequeue,
+                               unsigned long prev_nr_run, u64 curr_time)
+{
+}
+#endif
+
 /**
  * sched_update_nr_prod
  * @cpu: The core id of the nr running driver.
@@ -147,9 +184,16 @@ void sched_update_nr_prod(int cpu, long delta, bool inc)
        if (per_cpu(nr, cpu) > per_cpu(nr_max, cpu))
                per_cpu(nr_max, cpu) = per_cpu(nr, cpu);
 
+       update_last_busy_time(cpu, !inc, nr_running, curr_time);
+
        per_cpu(nr_prod_sum, cpu) += nr_running * diff;
        per_cpu(nr_big_prod_sum, cpu) += nr_eligible_big_tasks(cpu) * diff;
        per_cpu(iowait_prod_sum, cpu) += nr_iowait_cpu(cpu) * diff;
        spin_unlock_irqrestore(&per_cpu(nr_lock, cpu), flags);
 }
 EXPORT_SYMBOL(sched_update_nr_prod);
+
+u64 sched_get_cpu_last_busy_time(int cpu)
+{
+       return atomic64_read(&per_cpu(last_busy_time, cpu));
+}
index f2826c3..fc7c37a 100644 (file)
@@ -507,17 +507,22 @@ static struct pid *good_sigevent(sigevent_t * event)
 {
        struct task_struct *rtn = current->group_leader;
 
-       if ((event->sigev_notify & SIGEV_THREAD_ID ) &&
-               (!(rtn = find_task_by_vpid(event->sigev_notify_thread_id)) ||
-                !same_thread_group(rtn, current) ||
-                (event->sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_SIGNAL))
+       switch (event->sigev_notify) {
+       case SIGEV_SIGNAL | SIGEV_THREAD_ID:
+               rtn = find_task_by_vpid(event->sigev_notify_thread_id);
+               if (!rtn || !same_thread_group(rtn, current))
+                       return NULL;
+               /* FALLTHRU */
+       case SIGEV_SIGNAL:
+       case SIGEV_THREAD:
+               if (event->sigev_signo <= 0 || event->sigev_signo > SIGRTMAX)
+                       return NULL;
+               /* FALLTHRU */
+       case SIGEV_NONE:
+               return task_pid(rtn);
+       default:
                return NULL;
-
-       if (((event->sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) &&
-           ((event->sigev_signo <= 0) || (event->sigev_signo > SIGRTMAX)))
-               return NULL;
-
-       return task_pid(rtn);
+       }
 }
 
 void posix_timers_register_clock(const clockid_t clock_id,
@@ -745,8 +750,7 @@ common_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting)
        /* interval timer ? */
        if (iv.tv64)
                cur_setting->it_interval = ktime_to_timespec(iv);
-       else if (!hrtimer_active(timer) &&
-                (timr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE)
+       else if (!hrtimer_active(timer) && timr->it_sigev_notify != SIGEV_NONE)
                return;
 
        now = timer->base->get_time();
@@ -757,7 +761,7 @@ common_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting)
         * expiry is > now.
         */
        if (iv.tv64 && (timr->it_requeue_pending & REQUEUE_PENDING ||
-           (timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE))
+                       timr->it_sigev_notify == SIGEV_NONE))
                timr->it_overrun += (unsigned int) hrtimer_forward(timer, now, iv);
 
        remaining = __hrtimer_expires_remaining_adjusted(timer, now);
@@ -767,7 +771,7 @@ common_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting)
                 * A single shot SIGEV_NONE timer must return 0, when
                 * it is expired !
                 */
-               if ((timr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE)
+               if (timr->it_sigev_notify != SIGEV_NONE)
                        cur_setting->it_value.tv_nsec = 1;
        } else
                cur_setting->it_value = ktime_to_timespec(remaining);
@@ -865,7 +869,7 @@ common_timer_set(struct k_itimer *timr, int flags,
        timr->it.real.interval = timespec_to_ktime(new_setting->it_interval);
 
        /* SIGEV_NONE timers are not queued ! See common_timer_get */
-       if (((timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE)) {
+       if (timr->it_sigev_notify == SIGEV_NONE) {
                /* Setup correct expiry time for relative timers */
                if (mode == HRTIMER_MODE_REL) {
                        hrtimer_add_expires(timer, timer->base->get_time());
index fc86fdc..7902ecb 100644 (file)
@@ -633,9 +633,7 @@ static inline void tk_update_ktime_data(struct timekeeper *tk)
        tk->ktime_sec = seconds;
 
        /* Update the monotonic raw base */
-       seconds = tk->raw_sec;
-       nsec = (u32)(tk->tkr_raw.xtime_nsec >> tk->tkr_raw.shift);
-       tk->tkr_raw.base = ns_to_ktime(seconds * NSEC_PER_SEC + nsec);
+       tk->tkr_raw.base = ns_to_ktime(tk->raw_sec * NSEC_PER_SEC);
 }
 
 /* must hold timekeeper_lock */
index 7b61276..b674a7a 100644 (file)
@@ -57,7 +57,8 @@ static struct tracer_flags blk_tracer_flags = {
 };
 
 /* Global reference count of probes */
-static atomic_t blk_probes_ref = ATOMIC_INIT(0);
+static DEFINE_MUTEX(blk_probe_mutex);
+static int blk_probes_ref;
 
 static void blk_register_tracepoints(void);
 static void blk_unregister_tracepoints(void);
@@ -300,11 +301,26 @@ static void blk_trace_free(struct blk_trace *bt)
        kfree(bt);
 }
 
+static void get_probe_ref(void)
+{
+       mutex_lock(&blk_probe_mutex);
+       if (++blk_probes_ref == 1)
+               blk_register_tracepoints();
+       mutex_unlock(&blk_probe_mutex);
+}
+
+static void put_probe_ref(void)
+{
+       mutex_lock(&blk_probe_mutex);
+       if (!--blk_probes_ref)
+               blk_unregister_tracepoints();
+       mutex_unlock(&blk_probe_mutex);
+}
+
 static void blk_trace_cleanup(struct blk_trace *bt)
 {
        blk_trace_free(bt);
-       if (atomic_dec_and_test(&blk_probes_ref))
-               blk_unregister_tracepoints();
+       put_probe_ref();
 }
 
 int blk_trace_remove(struct request_queue *q)
@@ -522,8 +538,7 @@ int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
        if (cmpxchg(&q->blk_trace, NULL, bt))
                goto err;
 
-       if (atomic_inc_return(&blk_probes_ref) == 1)
-               blk_register_tracepoints();
+       get_probe_ref();
 
        return 0;
 err:
@@ -1518,9 +1533,7 @@ static int blk_trace_remove_queue(struct request_queue *q)
        if (bt == NULL)
                return -EINVAL;
 
-       if (atomic_dec_and_test(&blk_probes_ref))
-               blk_unregister_tracepoints();
-
+       put_probe_ref();
        blk_trace_free(bt);
        return 0;
 }
@@ -1551,8 +1564,7 @@ static int blk_trace_setup_queue(struct request_queue *q,
        if (cmpxchg(&q->blk_trace, NULL, bt))
                goto free_bt;
 
-       if (atomic_inc_return(&blk_probes_ref) == 1)
-               blk_register_tracepoints();
+       get_probe_ref();
        return 0;
 
 free_bt:
index fc0051f..ac758a5 100644 (file)
@@ -3845,7 +3845,6 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
                func_g.type = filter_parse_regex(glob, strlen(glob),
                                                 &func_g.search, &not);
                func_g.len = strlen(func_g.search);
-               func_g.search = glob;
 
                /* we do not support '!' for function probes */
                if (WARN_ON(not))
index 98515f8..2d8447a 100644 (file)
@@ -197,7 +197,7 @@ config ENABLE_MUST_CHECK
 config FRAME_WARN
        int "Warn for stack frames larger than (needs gcc 4.4)"
        range 0 8192
-       default 0 if KASAN
+       default 2048 if GCC_PLUGIN_LATENT_ENTROPY
        default 1024 if !64BIT
        default 2048 if 64BIT
        help
index 318f382..150e04d 100644 (file)
@@ -116,7 +116,7 @@ int sprint_oid(const void *data, size_t datasize, char *buffer, size_t bufsize)
        int count;
 
        if (v >= end)
-               return -EBADMSG;
+               goto bad;
 
        n = *v++;
        ret = count = snprintf(buffer, bufsize, "%u.%u", n / 40, n % 40);
@@ -134,7 +134,7 @@ int sprint_oid(const void *data, size_t datasize, char *buffer, size_t bufsize)
                        num = n & 0x7f;
                        do {
                                if (v >= end)
-                                       return -EBADMSG;
+                                       goto bad;
                                n = *v++;
                                num <<= 7;
                                num |= n & 0x7f;
@@ -148,6 +148,10 @@ int sprint_oid(const void *data, size_t datasize, char *buffer, size_t bufsize)
        }
 
        return ret;
+
+bad:
+       snprintf(buffer, bufsize, "(bad)");
+       return -EBADMSG;
 }
 EXPORT_SYMBOL_GPL(sprint_oid);
 
index faee480..86687ec 100644 (file)
@@ -853,7 +853,7 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
                                        locked = false;
                                }
 
-                               if (isolate_movable_page(page, isolate_mode))
+                               if (!isolate_movable_page(page, isolate_mode))
                                        goto isolate_success;
                        }
 
index 6d5717b..57540de 100644 (file)
@@ -103,7 +103,7 @@ __early_ioremap(resource_size_t phys_addr, unsigned long size, pgprot_t prot)
        enum fixed_addresses idx;
        int i, slot;
 
-       WARN_ON(system_state != SYSTEM_BOOTING);
+       WARN_ON(system_state >= SYSTEM_RUNNING);
 
        slot = -1;
        for (i = 0; i < FIX_BTMAPS_SLOTS; i++) {
index d6e10c8..291cbf5 100644 (file)
@@ -72,7 +72,7 @@
 
 #include "internal.h"
 
-#ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS
+#if defined(LAST_CPUPID_NOT_IN_PAGE_FLAGS) && !defined(CONFIG_COMPILE_TEST)
 #warning Unfortunate NUMA and NUMA Balancing config, growing page-frame for last_cpupid.
 #endif
 
index 2e80a7b..191b9ef 100644 (file)
@@ -1423,10 +1423,10 @@ int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn,
 }
 
 /*
- * Scan pfn range [start,end) to find movable/migratable pages (LRU pages
- * and hugepages). We scan pfn because it's much easier than scanning over
- * linked list. This function returns the pfn of the first found movable
- * page if it's found, otherwise 0.
+ * Scan pfn range [start,end) to find movable/migratable pages (LRU pages,
+ * non-lru movable pages and hugepages). We scan pfn because it's much
+ * easier than scanning over linked list. This function returns the pfn
+ * of the first found movable page if it's found, otherwise 0.
  */
 static unsigned long scan_movable_pages(unsigned long start, unsigned long end)
 {
@@ -1437,6 +1437,8 @@ static unsigned long scan_movable_pages(unsigned long start, unsigned long end)
                        page = pfn_to_page(pfn);
                        if (PageLRU(page))
                                return pfn;
+                       if (__PageMovable(page))
+                               return pfn;
                        if (PageHuge(page)) {
                                if (page_huge_active(page))
                                        return pfn;
@@ -1480,22 +1482,24 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
                if (!get_page_unless_zero(page))
                        continue;
                /*
-                * We can skip free pages. And we can only deal with pages on
-                * LRU.
+                * We can skip free pages. And we can deal with pages on
+                * LRU and non-lru movable pages.
                 */
-               ret = isolate_lru_page(page);
+               if (PageLRU(page))
+                       ret = isolate_lru_page(page);
+               else
+                       ret = isolate_movable_page(page, ISOLATE_UNEVICTABLE);
                if (!ret) { /* Success */
                        put_page(page);
                        list_add_tail(&page->lru, &source);
                        move_pages--;
-                       inc_zone_page_state(page, NR_ISOLATED_ANON +
-                                           page_is_file_cache(page));
-
+                       if (!__PageMovable(page))
+                               inc_zone_page_state(page, NR_ISOLATED_ANON +
+                                                   page_is_file_cache(page));
                } else {
 #ifdef CONFIG_DEBUG_VM
-                       printk(KERN_ALERT "removing pfn %lx from LRU failed\n",
-                              pfn);
-                       dump_page(page, "failed to remove from LRU");
+                       pr_alert("failed to isolate pfn %lx\n", pfn);
+                       dump_page(page, "isolation failed");
 #endif
                        put_page(page);
                        /* Because we don't have big zone->lock. we should
index a021071..921cf12 100644 (file)
@@ -75,7 +75,7 @@ int migrate_prep_local(void)
        return 0;
 }
 
-bool isolate_movable_page(struct page *page, isolate_mode_t mode)
+int isolate_movable_page(struct page *page, isolate_mode_t mode)
 {
        struct address_space *mapping;
 
@@ -126,14 +126,14 @@ bool isolate_movable_page(struct page *page, isolate_mode_t mode)
        __SetPageIsolated(page);
        unlock_page(page);
 
-       return true;
+       return 0;
 
 out_no_isolated:
        unlock_page(page);
 out_putpage:
        put_page(page);
 out:
-       return false;
+       return -EBUSY;
 }
 
 /* It should be called on page which is PG_movable */
index 3c3d813..bad5f32 100644 (file)
@@ -6652,8 +6652,9 @@ void set_pfnblock_flags_mask(struct page *page, unsigned long flags,
  * If @count is not zero, it is okay to include less @count unmovable pages
  *
  * PageLRU check without isolation or lru_lock could race so that
- * MIGRATE_MOVABLE block might include unmovable pages. It means you can't
- * expect this function should be exact.
+ * MIGRATE_MOVABLE block might include unmovable pages. And __PageMovable
+ * check without lock_page also may miss some movable non-lru pages at
+ * race condition. So you can't expect this function should be exact.
  */
 bool has_unmovable_pages(struct zone *zone, struct page *page, int count,
                         bool skip_hwpoisoned_pages)
@@ -6709,6 +6710,9 @@ bool has_unmovable_pages(struct zone *zone, struct page *page, int count,
                if (skip_hwpoisoned_pages && PageHWPoison(page))
                        continue;
 
+               if (__PageMovable(page))
+                       continue;
+
                if (!PageLRU(page))
                        found++;
                /*
index d41da54..9fa1aaa 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -80,6 +80,8 @@ EXPORT_SYMBOL(kstrdup_const);
  * @s: the string to duplicate
  * @max: read at most @max chars from @s
  * @gfp: the GFP mask used in the kmalloc() call when allocating memory
+ *
+ * Note: Use kmemdup_nul() instead if the size is known exactly.
  */
 char *kstrndup(const char *s, size_t max, gfp_t gfp)
 {
@@ -118,6 +120,28 @@ void *kmemdup(const void *src, size_t len, gfp_t gfp)
 EXPORT_SYMBOL(kmemdup);
 
 /**
+ * kmemdup_nul - Create a NUL-terminated string from unterminated data
+ * @s: The data to stringify
+ * @len: The size of the data
+ * @gfp: the GFP mask used in the kmalloc() call when allocating memory
+ */
+char *kmemdup_nul(const char *s, size_t len, gfp_t gfp)
+{
+       char *buf;
+
+       if (!s)
+               return NULL;
+
+       buf = kmalloc_track_caller(len + 1, gfp);
+       if (buf) {
+               memcpy(buf, s, len);
+               buf[len] = '\0';
+       }
+       return buf;
+}
+EXPORT_SYMBOL(kmemdup_nul);
+
+/**
  * memdup_user - duplicate memory region from user space
  *
  * @src: source address in user space
index 5f6e29f..67da944 100644 (file)
@@ -267,10 +267,13 @@ EXPORT_SYMBOL(register_shrinker);
  */
 void unregister_shrinker(struct shrinker *shrinker)
 {
+       if (!shrinker->nr_deferred)
+               return;
        down_write(&shrinker_rwsem);
        list_del(&shrinker->list);
        up_write(&shrinker_rwsem);
        kfree(shrinker->nr_deferred);
+       shrinker->nr_deferred = NULL;
 }
 EXPORT_SYMBOL(unregister_shrinker);
 
index b45123c..d9da78d 100644 (file)
@@ -411,6 +411,10 @@ config LWTUNNEL
 
 source "net/ipc_router/Kconfig"
 
+config DST_CACHE
+       bool
+       default n
+
 endif   # if NET
 
 # Used by archs to tell that they support BPF_JIT
index 87e2e18..0d35bba 100644 (file)
@@ -25,3 +25,4 @@ obj-$(CONFIG_CGROUP_NET_PRIO) += netprio_cgroup.o
 obj-$(CONFIG_CGROUP_NET_CLASSID) += netclassid_cgroup.o
 obj-$(CONFIG_LWTUNNEL) += lwtunnel.o
 obj-$(CONFIG_SOCKEV_NLMCAST) += sockev_nlmcast.o
+obj-$(CONFIG_DST_CACHE) += dst_cache.o
index 1c79e01..e8eb30f 100644 (file)
@@ -2600,7 +2600,7 @@ struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
 
        segs = skb_mac_gso_segment(skb, features);
 
-       if (unlikely(skb_needs_check(skb, tx_path)))
+       if (unlikely(skb_needs_check(skb, tx_path) && !IS_ERR(segs)))
                skb_warn_bad_offload(skb);
 
        return segs;
diff --git a/net/core/dst_cache.c b/net/core/dst_cache.c
new file mode 100644 (file)
index 0000000..554d364
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * net/core/dst_cache.c - dst entry cache
+ *
+ * Copyright (c) 2016 Paolo Abeni <pabeni@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/percpu.h>
+#include <net/dst_cache.h>
+#include <net/route.h>
+#if IS_ENABLED(CONFIG_IPV6)
+#include <net/ip6_fib.h>
+#endif
+#include <uapi/linux/in.h>
+
+struct dst_cache_pcpu {
+       unsigned long refresh_ts;
+       struct dst_entry *dst;
+       u32 cookie;
+       union {
+               struct in_addr in_saddr;
+               struct in6_addr in6_saddr;
+       };
+};
+
+static void dst_cache_per_cpu_dst_set(struct dst_cache_pcpu *dst_cache,
+                                     struct dst_entry *dst, u32 cookie)
+{
+       dst_release(dst_cache->dst);
+       if (dst)
+               dst_hold(dst);
+
+       dst_cache->cookie = cookie;
+       dst_cache->dst = dst;
+}
+
+static struct dst_entry *dst_cache_per_cpu_get(struct dst_cache *dst_cache,
+                                              struct dst_cache_pcpu *idst)
+{
+       struct dst_entry *dst;
+
+       dst = idst->dst;
+       if (!dst)
+               goto fail;
+
+       /* the cache already hold a dst reference; it can't go away */
+       dst_hold(dst);
+
+       if (unlikely(!time_after(idst->refresh_ts, dst_cache->reset_ts) ||
+                    (dst->obsolete && !dst->ops->check(dst, idst->cookie)))) {
+               dst_cache_per_cpu_dst_set(idst, NULL, 0);
+               dst_release(dst);
+               goto fail;
+       }
+       return dst;
+
+fail:
+       idst->refresh_ts = jiffies;
+       return NULL;
+}
+
+struct dst_entry *dst_cache_get(struct dst_cache *dst_cache)
+{
+       if (!dst_cache->cache)
+               return NULL;
+
+       return dst_cache_per_cpu_get(dst_cache, this_cpu_ptr(dst_cache->cache));
+}
+EXPORT_SYMBOL_GPL(dst_cache_get);
+
+struct rtable *dst_cache_get_ip4(struct dst_cache *dst_cache, __be32 *saddr)
+{
+       struct dst_cache_pcpu *idst;
+       struct dst_entry *dst;
+
+       if (!dst_cache->cache)
+               return NULL;
+
+       idst = this_cpu_ptr(dst_cache->cache);
+       dst = dst_cache_per_cpu_get(dst_cache, idst);
+       if (!dst)
+               return NULL;
+
+       *saddr = idst->in_saddr.s_addr;
+       return container_of(dst, struct rtable, dst);
+}
+EXPORT_SYMBOL_GPL(dst_cache_get_ip4);
+
+void dst_cache_set_ip4(struct dst_cache *dst_cache, struct dst_entry *dst,
+                      __be32 saddr)
+{
+       struct dst_cache_pcpu *idst;
+
+       if (!dst_cache->cache)
+               return;
+
+       idst = this_cpu_ptr(dst_cache->cache);
+       dst_cache_per_cpu_dst_set(idst, dst, 0);
+       idst->in_saddr.s_addr = saddr;
+}
+EXPORT_SYMBOL_GPL(dst_cache_set_ip4);
+
+#if IS_ENABLED(CONFIG_IPV6)
+void dst_cache_set_ip6(struct dst_cache *dst_cache, struct dst_entry *dst,
+                      const struct in6_addr *addr)
+{
+       struct dst_cache_pcpu *idst;
+
+       if (!dst_cache->cache)
+               return;
+
+       idst = this_cpu_ptr(dst_cache->cache);
+       dst_cache_per_cpu_dst_set(this_cpu_ptr(dst_cache->cache), dst,
+                                 rt6_get_cookie((struct rt6_info *)dst));
+       idst->in6_saddr = *addr;
+}
+EXPORT_SYMBOL_GPL(dst_cache_set_ip6);
+
+struct dst_entry *dst_cache_get_ip6(struct dst_cache *dst_cache,
+                                   struct in6_addr *saddr)
+{
+       struct dst_cache_pcpu *idst;
+       struct dst_entry *dst;
+
+       if (!dst_cache->cache)
+               return NULL;
+
+       idst = this_cpu_ptr(dst_cache->cache);
+       dst = dst_cache_per_cpu_get(dst_cache, idst);
+       if (!dst)
+               return NULL;
+
+       *saddr = idst->in6_saddr;
+       return dst;
+}
+EXPORT_SYMBOL_GPL(dst_cache_get_ip6);
+#endif
+
+int dst_cache_init(struct dst_cache *dst_cache, gfp_t gfp)
+{
+       dst_cache->cache = alloc_percpu_gfp(struct dst_cache_pcpu,
+                                           gfp | __GFP_ZERO);
+       if (!dst_cache->cache)
+               return -ENOMEM;
+
+       dst_cache_reset(dst_cache);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(dst_cache_init);
+
+void dst_cache_destroy(struct dst_cache *dst_cache)
+{
+       int i;
+
+       if (!dst_cache->cache)
+               return;
+
+       for_each_possible_cpu(i)
+               dst_release(per_cpu_ptr(dst_cache->cache, i)->dst);
+
+       free_percpu(dst_cache->cache);
+}
+EXPORT_SYMBOL_GPL(dst_cache_destroy);
index b68168f..9d43c1f 100644 (file)
@@ -259,6 +259,7 @@ int dccp_disconnect(struct sock *sk, int flags)
 {
        struct inet_connection_sock *icsk = inet_csk(sk);
        struct inet_sock *inet = inet_sk(sk);
+       struct dccp_sock *dp = dccp_sk(sk);
        int err = 0;
        const int old_state = sk->sk_state;
 
@@ -278,6 +279,10 @@ int dccp_disconnect(struct sock *sk, int flags)
                sk->sk_err = ECONNRESET;
 
        dccp_clear_xmit_timers(sk);
+       ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
+       ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
+       dp->dccps_hc_rx_ccid = NULL;
+       dp->dccps_hc_tx_ccid = NULL;
 
        __skb_queue_purge(&sk->sk_receive_queue);
        __skb_queue_purge(&sk->sk_write_queue);
index 13d6b1a..9d8fcde 100644 (file)
@@ -1337,6 +1337,12 @@ static int dn_setsockopt(struct socket *sock, int level, int optname, char __use
        lock_sock(sk);
        err = __dn_setsockopt(sock, level, optname, optval, optlen, 0);
        release_sock(sk);
+#ifdef CONFIG_NETFILTER
+       /* we need to exclude all possible ENOPROTOOPTs except default case */
+       if (err == -ENOPROTOOPT && optname != DSO_LINKINFO &&
+           optname != DSO_STREAM && optname != DSO_SEQPACKET)
+               err = nf_setsockopt(sk, PF_DECnet, optname, optval, optlen);
+#endif
 
        return err;
 }
@@ -1444,15 +1450,6 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char __us
                dn_nsp_send_disc(sk, 0x38, 0, sk->sk_allocation);
                break;
 
-       default:
-#ifdef CONFIG_NETFILTER
-               return nf_setsockopt(sk, PF_DECnet, optname, optval, optlen);
-#endif
-       case DSO_LINKINFO:
-       case DSO_STREAM:
-       case DSO_SEQPACKET:
-               return -ENOPROTOOPT;
-
        case DSO_MAXWINDOW:
                if (optlen != sizeof(unsigned long))
                        return -EINVAL;
@@ -1500,6 +1497,12 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char __us
                        return -EINVAL;
                scp->info_loc = u.info;
                break;
+
+       case DSO_LINKINFO:
+       case DSO_STREAM:
+       case DSO_SEQPACKET:
+       default:
+               return -ENOPROTOOPT;
        }
 
        return 0;
@@ -1513,6 +1516,20 @@ static int dn_getsockopt(struct socket *sock, int level, int optname, char __use
        lock_sock(sk);
        err = __dn_getsockopt(sock, level, optname, optval, optlen, 0);
        release_sock(sk);
+#ifdef CONFIG_NETFILTER
+       if (err == -ENOPROTOOPT && optname != DSO_STREAM &&
+           optname != DSO_SEQPACKET && optname != DSO_CONACCEPT &&
+           optname != DSO_CONREJECT) {
+               int len;
+
+               if (get_user(len, optlen))
+                       return -EFAULT;
+
+               err = nf_getsockopt(sk, PF_DECnet, optname, optval, &len);
+               if (err >= 0)
+                       err = put_user(len, optlen);
+       }
+#endif
 
        return err;
 }
@@ -1578,26 +1595,6 @@ static int __dn_getsockopt(struct socket *sock, int level,int optname, char __us
                r_data = &link;
                break;
 
-       default:
-#ifdef CONFIG_NETFILTER
-       {
-               int ret, len;
-
-               if (get_user(len, optlen))
-                       return -EFAULT;
-
-               ret = nf_getsockopt(sk, PF_DECnet, optname, optval, &len);
-               if (ret >= 0)
-                       ret = put_user(len, optlen);
-               return ret;
-       }
-#endif
-       case DSO_STREAM:
-       case DSO_SEQPACKET:
-       case DSO_CONACCEPT:
-       case DSO_CONREJECT:
-               return -ENOPROTOOPT;
-
        case DSO_MAXWINDOW:
                if (r_len > sizeof(unsigned long))
                        r_len = sizeof(unsigned long);
@@ -1629,6 +1626,13 @@ static int __dn_getsockopt(struct socket *sock, int level,int optname, char __us
                        r_len = sizeof(unsigned char);
                r_data = &scp->info_rem;
                break;
+
+       case DSO_STREAM:
+       case DSO_SEQPACKET:
+       case DSO_CONACCEPT:
+       case DSO_CONREJECT:
+       default:
+               return -ENOPROTOOPT;
        }
 
        if (r_data) {
index 8212ed8..c67efa3 100644 (file)
@@ -392,7 +392,11 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, unsigned int mtu)
        pip->frag_off = htons(IP_DF);
        pip->ttl      = 1;
        pip->daddr    = fl4.daddr;
+
+       rcu_read_lock();
        pip->saddr    = igmpv3_get_srcaddr(dev, &fl4);
+       rcu_read_unlock();
+
        pip->protocol = IPPROTO_IGMP;
        pip->tot_len  = 0;      /* filled in later */
        ip_select_ident(net, skb, NULL);
index 097a124..3a819d2 100644 (file)
@@ -1221,11 +1221,8 @@ int ip_setsockopt(struct sock *sk, int level,
        if (err == -ENOPROTOOPT && optname != IP_HDRINCL &&
                        optname != IP_IPSEC_POLICY &&
                        optname != IP_XFRM_POLICY &&
-                       !ip_mroute_opt(optname)) {
-               lock_sock(sk);
+                       !ip_mroute_opt(optname))
                err = nf_setsockopt(sk, PF_INET, optname, optval, optlen);
-               release_sock(sk);
-       }
 #endif
        return err;
 }
@@ -1250,12 +1247,9 @@ int compat_ip_setsockopt(struct sock *sk, int level, int optname,
        if (err == -ENOPROTOOPT && optname != IP_HDRINCL &&
                        optname != IP_IPSEC_POLICY &&
                        optname != IP_XFRM_POLICY &&
-                       !ip_mroute_opt(optname)) {
-               lock_sock(sk);
-               err = compat_nf_setsockopt(sk, PF_INET, optname,
-                                          optval, optlen);
-               release_sock(sk);
-       }
+                       !ip_mroute_opt(optname))
+               err = compat_nf_setsockopt(sk, PF_INET, optname, optval,
+                                          optlen);
 #endif
        return err;
 }
index 0bc7412..9d6b9c4 100644 (file)
@@ -152,7 +152,11 @@ static char dhcp_client_identifier[253] __initdata;
 
 /* Persistent data: */
 
+#ifdef IPCONFIG_DYNAMIC
 static int ic_proto_used;                      /* Protocol used, if any */
+#else
+#define ic_proto_used 0
+#endif
 static __be32 ic_nameservers[CONF_NAMESERVERS_MAX]; /* DNS Server IP addresses */
 static u8 ic_domain[64];               /* DNS (not NIS) domain name */
 
index 4a9e6db..16599ba 100644 (file)
@@ -365,7 +365,7 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par)
        struct ipt_clusterip_tgt_info *cipinfo = par->targinfo;
        const struct ipt_entry *e = par->entryinfo;
        struct clusterip_config *config;
-       int ret;
+       int ret, i;
 
        if (par->nft_compat) {
                pr_err("cannot use CLUSTERIP target from nftables compat\n");
@@ -384,8 +384,18 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par)
                pr_info("Please specify destination IP\n");
                return -EINVAL;
        }
-
-       /* FIXME: further sanity checks */
+       if (cipinfo->num_local_nodes > ARRAY_SIZE(cipinfo->local_nodes)) {
+               pr_info("bad num_local_nodes %u\n", cipinfo->num_local_nodes);
+               return -EINVAL;
+       }
+       for (i = 0; i < cipinfo->num_local_nodes; i++) {
+               if (cipinfo->local_nodes[i] - 1 >=
+                   sizeof(config->local_nodes) * 8) {
+                       pr_info("bad local_nodes[%d] %u\n",
+                               i, cipinfo->local_nodes[i]);
+                       return -EINVAL;
+               }
+       }
 
        config = clusterip_config_find_get(par->net, e->ip.dst.s_addr, 1);
        if (!config) {
index 6a20195..3fe8c95 100644 (file)
@@ -259,15 +259,19 @@ getorigdst(struct sock *sk, int optval, void __user *user, int *len)
        struct nf_conntrack_tuple tuple;
 
        memset(&tuple, 0, sizeof(tuple));
+
+       lock_sock(sk);
        tuple.src.u3.ip = inet->inet_rcv_saddr;
        tuple.src.u.tcp.port = inet->inet_sport;
        tuple.dst.u3.ip = inet->inet_daddr;
        tuple.dst.u.tcp.port = inet->inet_dport;
        tuple.src.l3num = PF_INET;
        tuple.dst.protonum = sk->sk_protocol;
+       release_sock(sk);
 
        /* We only do TCP and SCTP at the moment: is there a better way? */
-       if (sk->sk_protocol != IPPROTO_TCP && sk->sk_protocol != IPPROTO_SCTP) {
+       if (tuple.dst.protonum != IPPROTO_TCP &&
+           tuple.dst.protonum != IPPROTO_SCTP) {
                pr_debug("SO_ORIGINAL_DST: Not a TCP/SCTP socket\n");
                return -ENOPROTOOPT;
        }
index aa82e08..1c04dad 100644 (file)
@@ -2285,6 +2285,12 @@ int tcp_disconnect(struct sock *sk, int flags)
 
        WARN_ON(inet->inet_num && !icsk->icsk_bind_hash);
 
+       if (sk->sk_frag.page) {
+               put_page(sk->sk_frag.page);
+               sk->sk_frag.page = NULL;
+               sk->sk_frag.offset = 0;
+       }
+
        sk->sk_error_report(sk);
        return err;
 }
index 983bb99..851d5c9 100644 (file)
@@ -205,6 +205,7 @@ config IPV6_NDISC_NODETYPE
 config IPV6_TUNNEL
        tristate "IPv6: IP-in-IPv6 tunnel (RFC2473)"
        select INET6_TUNNEL
+       select DST_CACHE
        ---help---
          Support for IPv6-in-IPv6 and IPv4-in-IPv6 tunnels described in
          RFC 2473.
index 9d1a54d..85afef1 100644 (file)
@@ -362,7 +362,7 @@ static void ip6gre_tunnel_uninit(struct net_device *dev)
        struct ip6gre_net *ign = net_generic(t->net, ip6gre_net_id);
 
        ip6gre_tunnel_unlink(ign, t);
-       ip6_tnl_dst_reset(t);
+       dst_cache_reset(&t->dst_cache);
        dev_put(dev);
 }
 
@@ -640,7 +640,7 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
        }
 
        if (!fl6->flowi6_mark)
-               dst = ip6_tnl_dst_get(tunnel);
+               dst = dst_cache_get(&tunnel->dst_cache);
 
        if (!dst) {
                dst = ip6_route_output(net, NULL, fl6);
@@ -709,7 +709,7 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
        }
 
        if (!fl6->flowi6_mark && ndst)
-               ip6_tnl_dst_set(tunnel, ndst);
+               dst_cache_set_ip6(&tunnel->dst_cache, ndst, &fl6->saddr);
        skb_dst_set(skb, dst);
 
        proto = NEXTHDR_GRE;
@@ -1021,7 +1021,7 @@ static int ip6gre_tnl_change(struct ip6_tnl *t,
        t->parms.o_key = p->o_key;
        t->parms.i_flags = p->i_flags;
        t->parms.o_flags = p->o_flags;
-       ip6_tnl_dst_reset(t);
+       dst_cache_reset(&t->dst_cache);
        ip6gre_tnl_link_config(t, set_mtu);
        return 0;
 }
@@ -1232,7 +1232,7 @@ static void ip6gre_dev_free(struct net_device *dev)
 {
        struct ip6_tnl *t = netdev_priv(dev);
 
-       ip6_tnl_dst_destroy(t);
+       dst_cache_destroy(&t->dst_cache);
        free_percpu(dev->tstats);
        free_netdev(dev);
 }
@@ -1270,7 +1270,7 @@ static int ip6gre_tunnel_init_common(struct net_device *dev)
        if (!dev->tstats)
                return -ENOMEM;
 
-       ret = ip6_tnl_dst_init(tunnel);
+       ret = dst_cache_init(&tunnel->dst_cache, GFP_KERNEL);
        if (ret) {
                free_percpu(dev->tstats);
                dev->tstats = NULL;
index cbea14e..27b00c4 100644 (file)
@@ -122,97 +122,6 @@ static struct net_device_stats *ip6_get_stats(struct net_device *dev)
        return &dev->stats;
 }
 
-/*
- * Locking : hash tables are protected by RCU and RTNL
- */
-
-static void ip6_tnl_per_cpu_dst_set(struct ip6_tnl_dst *idst,
-                                   struct dst_entry *dst)
-{
-       write_seqlock_bh(&idst->lock);
-       dst_release(rcu_dereference_protected(
-                           idst->dst,
-                           lockdep_is_held(&idst->lock.lock)));
-       if (dst) {
-               dst_hold(dst);
-               idst->cookie = rt6_get_cookie((struct rt6_info *)dst);
-       } else {
-               idst->cookie = 0;
-       }
-       rcu_assign_pointer(idst->dst, dst);
-       write_sequnlock_bh(&idst->lock);
-}
-
-struct dst_entry *ip6_tnl_dst_get(struct ip6_tnl *t)
-{
-       struct ip6_tnl_dst *idst;
-       struct dst_entry *dst;
-       unsigned int seq;
-       u32 cookie;
-
-       idst = raw_cpu_ptr(t->dst_cache);
-
-       rcu_read_lock();
-       do {
-               seq = read_seqbegin(&idst->lock);
-               dst = rcu_dereference(idst->dst);
-               cookie = idst->cookie;
-       } while (read_seqretry(&idst->lock, seq));
-
-       if (dst && !atomic_inc_not_zero(&dst->__refcnt))
-               dst = NULL;
-       rcu_read_unlock();
-
-       if (dst && dst->obsolete && !dst->ops->check(dst, cookie)) {
-               ip6_tnl_per_cpu_dst_set(idst, NULL);
-               dst_release(dst);
-               dst = NULL;
-       }
-       return dst;
-}
-EXPORT_SYMBOL_GPL(ip6_tnl_dst_get);
-
-void ip6_tnl_dst_reset(struct ip6_tnl *t)
-{
-       int i;
-
-       for_each_possible_cpu(i)
-               ip6_tnl_per_cpu_dst_set(per_cpu_ptr(t->dst_cache, i), NULL);
-}
-EXPORT_SYMBOL_GPL(ip6_tnl_dst_reset);
-
-void ip6_tnl_dst_set(struct ip6_tnl *t, struct dst_entry *dst)
-{
-       ip6_tnl_per_cpu_dst_set(raw_cpu_ptr(t->dst_cache), dst);
-
-}
-EXPORT_SYMBOL_GPL(ip6_tnl_dst_set);
-
-void ip6_tnl_dst_destroy(struct ip6_tnl *t)
-{
-       if (!t->dst_cache)
-               return;
-
-       ip6_tnl_dst_reset(t);
-       free_percpu(t->dst_cache);
-}
-EXPORT_SYMBOL_GPL(ip6_tnl_dst_destroy);
-
-int ip6_tnl_dst_init(struct ip6_tnl *t)
-{
-       int i;
-
-       t->dst_cache = alloc_percpu(struct ip6_tnl_dst);
-       if (!t->dst_cache)
-               return -ENOMEM;
-
-       for_each_possible_cpu(i)
-               seqlock_init(&per_cpu_ptr(t->dst_cache, i)->lock);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(ip6_tnl_dst_init);
-
 /**
  * ip6_tnl_lookup - fetch tunnel matching the end-point addresses
  *   @remote: the address of the tunnel exit-point
@@ -331,7 +240,7 @@ static void ip6_dev_free(struct net_device *dev)
 {
        struct ip6_tnl *t = netdev_priv(dev);
 
-       ip6_tnl_dst_destroy(t);
+       dst_cache_destroy(&t->dst_cache);
        free_percpu(dev->tstats);
        free_netdev(dev);
 }
@@ -464,7 +373,7 @@ ip6_tnl_dev_uninit(struct net_device *dev)
                RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL);
        else
                ip6_tnl_unlink(ip6n, t);
-       ip6_tnl_dst_reset(t);
+       dst_cache_reset(&t->dst_cache);
        dev_put(dev);
 }
 
@@ -1053,7 +962,6 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
        struct ipv6_tel_txoption opt;
        struct dst_entry *dst = NULL, *ndst = NULL;
        struct net_device *tdev;
-       bool use_cache = false;
        int mtu;
        unsigned int max_headroom = sizeof(struct ipv6hdr);
        u8 proto;
@@ -1061,39 +969,28 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
 
        /* NBMA tunnel */
        if (ipv6_addr_any(&t->parms.raddr)) {
-               if (skb->protocol == htons(ETH_P_IPV6)) {
-                       struct in6_addr *addr6;
-                       struct neighbour *neigh;
-                       int addr_type;
-
-                       if (!skb_dst(skb))
-                               goto tx_err_link_failure;
+               struct in6_addr *addr6;
+               struct neighbour *neigh;
+               int addr_type;
 
-                       neigh = dst_neigh_lookup(skb_dst(skb),
-                                                &ipv6_hdr(skb)->daddr);
-                       if (!neigh)
-                               goto tx_err_link_failure;
+               if (!skb_dst(skb))
+                       goto tx_err_link_failure;
 
-                       addr6 = (struct in6_addr *)&neigh->primary_key;
-                       addr_type = ipv6_addr_type(addr6);
+               neigh = dst_neigh_lookup(skb_dst(skb),
+                                        &ipv6_hdr(skb)->daddr);
+               if (!neigh)
+                       goto tx_err_link_failure;
 
-                       if (addr_type == IPV6_ADDR_ANY)
-                               addr6 = &ipv6_hdr(skb)->daddr;
+               addr6 = (struct in6_addr *)&neigh->primary_key;
+               addr_type = ipv6_addr_type(addr6);
 
-                       memcpy(&fl6->daddr, addr6, sizeof(fl6->daddr));
-                       neigh_release(neigh);
-               }
-       } else if (t->parms.proto != 0 && !(t->parms.flags &
-                                           (IP6_TNL_F_USE_ORIG_TCLASS |
-                                            IP6_TNL_F_USE_ORIG_FWMARK))) {
-               /* enable the cache only if neither the outer protocol nor the
-                * routing decision depends on the current inner header value
-                */
-               use_cache = true;
-       }
+               if (addr_type == IPV6_ADDR_ANY)
+                       addr6 = &ipv6_hdr(skb)->daddr;
 
-       if (use_cache)
-               dst = ip6_tnl_dst_get(t);
+               memcpy(&fl6->daddr, addr6, sizeof(fl6->daddr));
+               neigh_release(neigh);
+       } else if (!fl6->flowi6_mark)
+               dst = dst_cache_get(&t->dst_cache);
 
        if (!ip6_tnl_xmit_ctl(t, &fl6->saddr, &fl6->daddr))
                goto tx_err_link_failure;
@@ -1156,8 +1053,8 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
                skb = new_skb;
        }
 
-       if (use_cache && ndst)
-               ip6_tnl_dst_set(t, ndst);
+       if (!fl6->flowi6_mark && ndst)
+               dst_cache_set_ip6(&t->dst_cache, ndst, &fl6->saddr);
        skb_dst_set(skb, dst);
 
        skb->transport_header = skb->network_header;
@@ -1395,7 +1292,7 @@ ip6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p)
        t->parms.flowinfo = p->flowinfo;
        t->parms.link = p->link;
        t->parms.proto = p->proto;
-       ip6_tnl_dst_reset(t);
+       dst_cache_reset(&t->dst_cache);
        ip6_tnl_link_config(t);
        return 0;
 }
@@ -1666,7 +1563,7 @@ ip6_tnl_dev_init_gen(struct net_device *dev)
        if (!dev->tstats)
                return -ENOMEM;
 
-       ret = ip6_tnl_dst_init(t);
+       ret = dst_cache_init(&t->dst_cache, GFP_KERNEL);
        if (ret) {
                free_percpu(dev->tstats);
                dev->tstats = NULL;
index 06db53f..00111ac 100644 (file)
@@ -646,7 +646,7 @@ vti6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p)
        t->parms.i_key = p->i_key;
        t->parms.o_key = p->o_key;
        t->parms.proto = p->proto;
-       ip6_tnl_dst_reset(t);
+       dst_cache_reset(&t->dst_cache);
        vti6_link_config(t);
        return 0;
 }
index 8361d73..e5846d1 100644 (file)
@@ -495,6 +495,7 @@ static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
                return ERR_PTR(-ENOENT);
 
        it->mrt = mrt;
+       it->cache = NULL;
        return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1)
                : SEQ_START_TOKEN;
 }
index 9011176..ede9d0e 100644 (file)
@@ -905,12 +905,8 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname,
 #ifdef CONFIG_NETFILTER
        /* we need to exclude all possible ENOPROTOOPTs except default case */
        if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY &&
-                       optname != IPV6_XFRM_POLICY) {
-               lock_sock(sk);
-               err = nf_setsockopt(sk, PF_INET6, optname, optval,
-                               optlen);
-               release_sock(sk);
-       }
+                       optname != IPV6_XFRM_POLICY)
+               err = nf_setsockopt(sk, PF_INET6, optname, optval, optlen);
 #endif
        return err;
 }
@@ -940,12 +936,9 @@ int compat_ipv6_setsockopt(struct sock *sk, int level, int optname,
 #ifdef CONFIG_NETFILTER
        /* we need to exclude all possible ENOPROTOOPTs except default case */
        if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY &&
-           optname != IPV6_XFRM_POLICY) {
-               lock_sock(sk);
-               err = compat_nf_setsockopt(sk, PF_INET6, optname,
-                                          optval, optlen);
-               release_sock(sk);
-       }
+           optname != IPV6_XFRM_POLICY)
+               err = compat_nf_setsockopt(sk, PF_INET6, optname, optval,
+                                          optlen);
 #endif
        return err;
 }
index 1aa5848..aa051d9 100644 (file)
@@ -226,20 +226,27 @@ static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = {
 static int
 ipv6_getorigdst(struct sock *sk, int optval, void __user *user, int *len)
 {
-       const struct inet_sock *inet = inet_sk(sk);
+       struct nf_conntrack_tuple tuple = { .src.l3num = NFPROTO_IPV6 };
        const struct ipv6_pinfo *inet6 = inet6_sk(sk);
+       const struct inet_sock *inet = inet_sk(sk);
        const struct nf_conntrack_tuple_hash *h;
        struct sockaddr_in6 sin6;
-       struct nf_conntrack_tuple tuple = { .src.l3num = NFPROTO_IPV6 };
        struct nf_conn *ct;
+       __be32 flow_label;
+       int bound_dev_if;
 
+       lock_sock(sk);
        tuple.src.u3.in6 = sk->sk_v6_rcv_saddr;
        tuple.src.u.tcp.port = inet->inet_sport;
        tuple.dst.u3.in6 = sk->sk_v6_daddr;
        tuple.dst.u.tcp.port = inet->inet_dport;
        tuple.dst.protonum = sk->sk_protocol;
+       bound_dev_if = sk->sk_bound_dev_if;
+       flow_label = inet6->flow_label;
+       release_sock(sk);
 
-       if (sk->sk_protocol != IPPROTO_TCP && sk->sk_protocol != IPPROTO_SCTP)
+       if (tuple.dst.protonum != IPPROTO_TCP &&
+           tuple.dst.protonum != IPPROTO_SCTP)
                return -ENOPROTOOPT;
 
        if (*len < 0 || (unsigned int) *len < sizeof(sin6))
@@ -257,14 +264,13 @@ ipv6_getorigdst(struct sock *sk, int optval, void __user *user, int *len)
 
        sin6.sin6_family = AF_INET6;
        sin6.sin6_port = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.tcp.port;
-       sin6.sin6_flowinfo = inet6->flow_label & IPV6_FLOWINFO_MASK;
+       sin6.sin6_flowinfo = flow_label & IPV6_FLOWINFO_MASK;
        memcpy(&sin6.sin6_addr,
                &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.in6,
                                        sizeof(sin6.sin6_addr));
 
        nf_ct_put(ct);
-       sin6.sin6_scope_id = ipv6_iface_scope_id(&sin6.sin6_addr,
-                                                sk->sk_bound_dev_if);
+       sin6.sin6_scope_id = ipv6_iface_scope_id(&sin6.sin6_addr, bound_dev_if);
        return copy_to_user(user, &sin6, sizeof(sin6)) ? -EFAULT : 0;
 }
 
index 0328f72..299edc6 100644 (file)
@@ -605,17 +605,13 @@ static const struct file_operations ip_vs_app_fops = {
 
 int __net_init ip_vs_app_net_init(struct netns_ipvs *ipvs)
 {
-       struct net *net = ipvs->net;
-
        INIT_LIST_HEAD(&ipvs->app_list);
-       proc_create("ip_vs_app", 0, net->proc_net, &ip_vs_app_fops);
+       proc_create("ip_vs_app", 0, ipvs->net->proc_net, &ip_vs_app_fops);
        return 0;
 }
 
 void __net_exit ip_vs_app_net_cleanup(struct netns_ipvs *ipvs)
 {
-       struct net *net = ipvs->net;
-
        unregister_ip_vs_app(ipvs, NULL /* all */);
-       remove_proc_entry("ip_vs_app", net->proc_net);
+       remove_proc_entry("ip_vs_app", ipvs->net->proc_net);
 }
index 2c937c1..2f0e4f6 100644 (file)
@@ -3951,7 +3951,6 @@ static struct notifier_block ip_vs_dst_notifier = {
 
 int __net_init ip_vs_control_net_init(struct netns_ipvs *ipvs)
 {
-       struct net *net = ipvs->net;
        int i, idx;
 
        /* Initialize rs_table */
@@ -3978,9 +3977,9 @@ int __net_init ip_vs_control_net_init(struct netns_ipvs *ipvs)
 
        spin_lock_init(&ipvs->tot_stats.lock);
 
-       proc_create("ip_vs", 0, net->proc_net, &ip_vs_info_fops);
-       proc_create("ip_vs_stats", 0, net->proc_net, &ip_vs_stats_fops);
-       proc_create("ip_vs_stats_percpu", 0, net->proc_net,
+       proc_create("ip_vs", 0, ipvs->net->proc_net, &ip_vs_info_fops);
+       proc_create("ip_vs_stats", 0, ipvs->net->proc_net, &ip_vs_stats_fops);
+       proc_create("ip_vs_stats_percpu", 0, ipvs->net->proc_net,
                    &ip_vs_stats_percpu_fops);
 
        if (ip_vs_control_net_init_sysctl(ipvs))
@@ -3995,13 +3994,11 @@ err:
 
 void __net_exit ip_vs_control_net_cleanup(struct netns_ipvs *ipvs)
 {
-       struct net *net = ipvs->net;
-
        ip_vs_trash_cleanup(ipvs);
        ip_vs_control_net_cleanup_sysctl(ipvs);
-       remove_proc_entry("ip_vs_stats_percpu", net->proc_net);
-       remove_proc_entry("ip_vs_stats", net->proc_net);
-       remove_proc_entry("ip_vs", net->proc_net);
+       remove_proc_entry("ip_vs_stats_percpu", ipvs->net->proc_net);
+       remove_proc_entry("ip_vs_stats", ipvs->net->proc_net);
+       remove_proc_entry("ip_vs", ipvs->net->proc_net);
        free_percpu(ipvs->tot_stats.cpustats);
 }
 
index 5baa8e2..b19ad20 100644 (file)
  * Once the queue is registered it must reinject all packets it
  * receives, no matter what.
  */
-static const struct nf_queue_handler __rcu *queue_handler __read_mostly;
 
 /* return EBUSY when somebody else is registered, return EEXIST if the
  * same handler is registered, return 0 in case of success. */
-void nf_register_queue_handler(const struct nf_queue_handler *qh)
+void nf_register_queue_handler(struct net *net, const struct nf_queue_handler *qh)
 {
        /* should never happen, we only have one queueing backend in kernel */
-       WARN_ON(rcu_access_pointer(queue_handler));
-       rcu_assign_pointer(queue_handler, qh);
+       WARN_ON(rcu_access_pointer(net->nf.queue_handler));
+       rcu_assign_pointer(net->nf.queue_handler, qh);
 }
 EXPORT_SYMBOL(nf_register_queue_handler);
 
 /* The caller must flush their queue before this */
-void nf_unregister_queue_handler(void)
+void nf_unregister_queue_handler(struct net *net)
 {
-       RCU_INIT_POINTER(queue_handler, NULL);
-       synchronize_rcu();
+       RCU_INIT_POINTER(net->nf.queue_handler, NULL);
 }
 EXPORT_SYMBOL(nf_unregister_queue_handler);
 
@@ -103,7 +101,7 @@ void nf_queue_nf_hook_drop(struct net *net, struct nf_hook_ops *ops)
        const struct nf_queue_handler *qh;
 
        rcu_read_lock();
-       qh = rcu_dereference(queue_handler);
+       qh = rcu_dereference(net->nf.queue_handler);
        if (qh)
                qh->nf_hook_drop(net, ops);
        rcu_read_unlock();
@@ -122,9 +120,10 @@ int nf_queue(struct sk_buff *skb,
        struct nf_queue_entry *entry = NULL;
        const struct nf_afinfo *afinfo;
        const struct nf_queue_handler *qh;
+       struct net *net = state->net;
 
        /* QUEUE == DROP if no one is waiting, to be safe. */
-       qh = rcu_dereference(queue_handler);
+       qh = rcu_dereference(net->nf.queue_handler);
        if (!qh) {
                status = -ESRCH;
                goto err;
index c14d2e8..f853b55 100644 (file)
@@ -1382,21 +1382,29 @@ static int __net_init nfnl_queue_net_init(struct net *net)
                         net->nf.proc_netfilter, &nfqnl_file_ops))
                return -ENOMEM;
 #endif
+       nf_register_queue_handler(net, &nfqh);
        return 0;
 }
 
 static void __net_exit nfnl_queue_net_exit(struct net *net)
 {
+       nf_unregister_queue_handler(net);
 #ifdef CONFIG_PROC_FS
        remove_proc_entry("nfnetlink_queue", net->nf.proc_netfilter);
 #endif
 }
 
+static void nfnl_queue_net_exit_batch(struct list_head *net_exit_list)
+{
+       synchronize_rcu();
+}
+
 static struct pernet_operations nfnl_queue_net_ops = {
-       .init   = nfnl_queue_net_init,
-       .exit   = nfnl_queue_net_exit,
-       .id     = &nfnl_queue_net_id,
-       .size   = sizeof(struct nfnl_queue_net),
+       .init           = nfnl_queue_net_init,
+       .exit           = nfnl_queue_net_exit,
+       .exit_batch     = nfnl_queue_net_exit_batch,
+       .id             = &nfnl_queue_net_id,
+       .size           = sizeof(struct nfnl_queue_net),
 };
 
 static int __init nfnetlink_queue_init(void)
@@ -1417,7 +1425,6 @@ static int __init nfnetlink_queue_init(void)
        }
 
        register_netdevice_notifier(&nfqnl_dev_notifier);
-       nf_register_queue_handler(&nfqh);
        return status;
 
 cleanup_netlink_notifier:
@@ -1429,7 +1436,6 @@ out:
 
 static void __exit nfnetlink_queue_fini(void)
 {
-       nf_unregister_queue_handler();
        unregister_netdevice_notifier(&nfqnl_dev_notifier);
        nfnetlink_subsys_unregister(&nfqnl_subsys);
        netlink_unregister_notifier(&nfqnl_rtnl_notifier);
index 7b42b0a..5b52dd3 100644 (file)
@@ -38,8 +38,6 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
 MODULE_DESCRIPTION("{ip,ip6,arp,eb}_tables backend module");
 
-#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
-
 struct compat_delta {
        unsigned int offset; /* offset in kernel */
        int delta; /* delta in 32bit user land */
@@ -208,6 +206,9 @@ xt_request_find_match(uint8_t nfproto, const char *name, uint8_t revision)
 {
        struct xt_match *match;
 
+       if (strnlen(name, XT_EXTENSION_MAXNAMELEN) == XT_EXTENSION_MAXNAMELEN)
+               return ERR_PTR(-EINVAL);
+
        match = xt_find_match(nfproto, name, revision);
        if (IS_ERR(match)) {
                request_module("%st_%s", xt_prefix[nfproto], name);
@@ -250,6 +251,9 @@ struct xt_target *xt_request_find_target(u8 af, const char *name, u8 revision)
 {
        struct xt_target *target;
 
+       if (strnlen(name, XT_EXTENSION_MAXNAMELEN) == XT_EXTENSION_MAXNAMELEN)
+               return ERR_PTR(-EINVAL);
+
        target = xt_find_target(af, name, revision);
        if (IS_ERR(target)) {
                request_module("%st_%s", xt_prefix[af], name);
@@ -954,7 +958,7 @@ struct xt_table_info *xt_alloc_table_info(unsigned int size)
                return NULL;
 
        /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
-       if ((SMP_ALIGN(size) >> PAGE_SHIFT) + 2 > totalram_pages)
+       if ((size >> PAGE_SHIFT) + 2 > totalram_pages)
                return NULL;
 
        if (sz <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER))
index 604df6f..0be96f8 100644 (file)
@@ -40,23 +40,31 @@ static void xt_rateest_hash_insert(struct xt_rateest *est)
        hlist_add_head(&est->list, &rateest_hash[h]);
 }
 
-struct xt_rateest *xt_rateest_lookup(const char *name)
+static struct xt_rateest *__xt_rateest_lookup(const char *name)
 {
        struct xt_rateest *est;
        unsigned int h;
 
        h = xt_rateest_hash(name);
-       mutex_lock(&xt_rateest_mutex);
        hlist_for_each_entry(est, &rateest_hash[h], list) {
                if (strcmp(est->name, name) == 0) {
                        est->refcnt++;
-                       mutex_unlock(&xt_rateest_mutex);
                        return est;
                }
        }
-       mutex_unlock(&xt_rateest_mutex);
+
        return NULL;
 }
+
+struct xt_rateest *xt_rateest_lookup(const char *name)
+{
+       struct xt_rateest *est;
+
+       mutex_lock(&xt_rateest_mutex);
+       est = __xt_rateest_lookup(name);
+       mutex_unlock(&xt_rateest_mutex);
+       return est;
+}
 EXPORT_SYMBOL_GPL(xt_rateest_lookup);
 
 void xt_rateest_put(struct xt_rateest *est)
@@ -104,8 +112,10 @@ static int xt_rateest_tg_checkentry(const struct xt_tgchk_param *par)
                rnd_inited = true;
        }
 
-       est = xt_rateest_lookup(info->name);
+       mutex_lock(&xt_rateest_mutex);
+       est = __xt_rateest_lookup(info->name);
        if (est) {
+               mutex_unlock(&xt_rateest_mutex);
                /*
                 * If estimator parameters are specified, they must match the
                 * existing estimator.
@@ -143,11 +153,13 @@ static int xt_rateest_tg_checkentry(const struct xt_tgchk_param *par)
 
        info->est = est;
        xt_rateest_hash_insert(est);
+       mutex_unlock(&xt_rateest_mutex);
        return 0;
 
 err2:
        kfree(est);
 err1:
+       mutex_unlock(&xt_rateest_mutex);
        return ret;
 }
 
index d44469c..fa011b3 100644 (file)
@@ -519,13 +519,11 @@ static struct tag_ref *get_tag_ref(tag_t full_tag,
 
        DR_DEBUG("qtaguid: get_tag_ref(0x%llx)\n",
                 full_tag);
-       spin_lock_bh(&uid_tag_data_tree_lock);
        tr_entry = lookup_tag_ref(full_tag, &utd_entry);
        BUG_ON(IS_ERR_OR_NULL(utd_entry));
        if (!tr_entry)
                tr_entry = new_tag_ref(full_tag, utd_entry);
 
-       spin_unlock_bh(&uid_tag_data_tree_lock);
        if (utd_res)
                *utd_res = utd_entry;
        DR_DEBUG("qtaguid: get_tag_ref(0x%llx) utd=%p tr=%p\n",
@@ -2021,6 +2019,7 @@ static int ctrl_cmd_delete(const char *input)
 
        /* Delete socket tags */
        spin_lock_bh(&sock_tag_list_lock);
+       spin_lock_bh(&uid_tag_data_tree_lock);
        node = rb_first(&sock_tag_tree);
        while (node) {
                st_entry = rb_entry(node, struct sock_tag, sock_node);
@@ -2050,6 +2049,7 @@ static int ctrl_cmd_delete(const char *input)
                                list_del(&st_entry->list);
                }
        }
+       spin_unlock_bh(&uid_tag_data_tree_lock);
        spin_unlock_bh(&sock_tag_list_lock);
 
        sock_tag_tree_erase(&st_to_free_tree);
@@ -2259,10 +2259,12 @@ static int ctrl_cmd_tag(const char *input)
        full_tag = combine_atag_with_uid(acct_tag, uid_int);
 
        spin_lock_bh(&sock_tag_list_lock);
+       spin_lock_bh(&uid_tag_data_tree_lock);
        sock_tag_entry = get_sock_stat_nl(el_socket->sk);
        tag_ref_entry = get_tag_ref(full_tag, &uid_tag_data_entry);
        if (IS_ERR(tag_ref_entry)) {
                res = PTR_ERR(tag_ref_entry);
+               spin_unlock_bh(&uid_tag_data_tree_lock);
                spin_unlock_bh(&sock_tag_list_lock);
                goto err_put;
        }
@@ -2289,9 +2291,14 @@ static int ctrl_cmd_tag(const char *input)
                        pr_err("qtaguid: ctrl_tag(%s): "
                               "socket tag alloc failed\n",
                               input);
+                       BUG_ON(tag_ref_entry->num_sock_tags <= 0);
+                       tag_ref_entry->num_sock_tags--;
+                       free_tag_ref_from_utd_entry(tag_ref_entry,
+                                                   uid_tag_data_entry);
+                       spin_unlock_bh(&uid_tag_data_tree_lock);
                        spin_unlock_bh(&sock_tag_list_lock);
                        res = -ENOMEM;
-                       goto err_tag_unref_put;
+                       goto err_put;
                }
                /*
                 * Hold the sk refcount here to make sure the sk pointer cannot
@@ -2301,7 +2308,6 @@ static int ctrl_cmd_tag(const char *input)
                sock_tag_entry->sk = el_socket->sk;
                sock_tag_entry->pid = current->tgid;
                sock_tag_entry->tag = combine_atag_with_uid(acct_tag, uid_int);
-               spin_lock_bh(&uid_tag_data_tree_lock);
                pqd_entry = proc_qtu_data_tree_search(
                        &proc_qtu_data_tree, current->tgid);
                /*
@@ -2319,11 +2325,11 @@ static int ctrl_cmd_tag(const char *input)
                else
                        list_add(&sock_tag_entry->list,
                                 &pqd_entry->sock_tag_list);
-               spin_unlock_bh(&uid_tag_data_tree_lock);
 
                sock_tag_tree_insert(sock_tag_entry, &sock_tag_tree);
                atomic64_inc(&qtu_events.sockets_tagged);
        }
+       spin_unlock_bh(&uid_tag_data_tree_lock);
        spin_unlock_bh(&sock_tag_list_lock);
        /* We keep the ref to the sk until it is untagged */
        CT_DEBUG("qtaguid: ctrl_tag(%s): done st@%p ...->sk_refcnt=%d\n",
@@ -2332,10 +2338,6 @@ static int ctrl_cmd_tag(const char *input)
        sockfd_put(el_socket);
        return 0;
 
-err_tag_unref_put:
-       BUG_ON(tag_ref_entry->num_sock_tags <= 0);
-       tag_ref_entry->num_sock_tags--;
-       free_tag_ref_from_utd_entry(tag_ref_entry, uid_tag_data_entry);
 err_put:
        CT_DEBUG("qtaguid: ctrl_tag(%s): done. ...->sk_refcnt=%d\n",
                 input, atomic_read(&el_socket->sk->sk_refcnt) - 1);
index 0a08c86..e8dcf94 100644 (file)
@@ -438,6 +438,9 @@ static int choke_change(struct Qdisc *sch, struct nlattr *opt)
 
        ctl = nla_data(tb[TCA_CHOKE_PARMS]);
 
+       if (!red_check_params(ctl->qth_min, ctl->qth_max, ctl->Wlog))
+               return -EINVAL;
+
        if (ctl->limit > CHOKE_MAX_QUEUE)
                return -EINVAL;
 
index 8010510..f9e8dee 100644 (file)
@@ -389,6 +389,9 @@ static inline int gred_change_vq(struct Qdisc *sch, int dp,
        struct gred_sched *table = qdisc_priv(sch);
        struct gred_sched_data *q = table->tab[dp];
 
+       if (!red_check_params(ctl->qth_min, ctl->qth_max, ctl->Wlog))
+               return -EINVAL;
+
        if (!q) {
                table->tab[dp] = q = *prealloc;
                *prealloc = NULL;
index 8c0508c..0505b84 100644 (file)
@@ -199,6 +199,8 @@ static int red_change(struct Qdisc *sch, struct nlattr *opt)
        max_P = tb[TCA_RED_MAX_P] ? nla_get_u32(tb[TCA_RED_MAX_P]) : 0;
 
        ctl = nla_data(tb[TCA_RED_PARMS]);
+       if (!red_check_params(ctl->qth_min, ctl->qth_max, ctl->Wlog))
+               return -EINVAL;
 
        if (ctl->limit > 0) {
                child = fifo_create_dflt(sch, &bfifo_qdisc_ops, ctl->limit);
index 3f2c3ee..8b8c084 100644 (file)
@@ -633,6 +633,9 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt)
        if (ctl->divisor &&
            (!is_power_of_2(ctl->divisor) || ctl->divisor > 65536))
                return -EINVAL;
+       if (ctl_v1 && !red_check_params(ctl_v1->qth_min, ctl_v1->qth_max,
+                                       ctl_v1->Wlog))
+               return -EINVAL;
        if (ctl_v1 && ctl_v1->qth_min) {
                p = kmalloc(sizeof(*p), GFP_KERNEL);
                if (!p)
index 01d0c4e..397e37d 100644 (file)
@@ -393,6 +393,8 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
                if (rv)
                        goto use_default_name;
        } else {
+               int rv;
+
 use_default_name:
                /* NOTE:  This is *probably* safe w/out holding rtnl because of
                 * the restrictions on phy names.  Probably this call could
@@ -400,7 +402,11 @@ use_default_name:
                 * phyX.  But, might should add some locking and check return
                 * value, and use a different name if this one exists?
                 */
-               dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx);
+               rv = dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx);
+               if (rv < 0) {
+                       kfree(rdev);
+                       return NULL;
+               }
        }
 
        INIT_LIST_HEAD(&rdev->wiphy.wdev_list);
index d70694d..605ff10 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/nl80211.h>
 #include <linux/rtnetlink.h>
 #include <linux/netlink.h>
+#include <linux/nospec.h>
 #include <linux/etherdevice.h>
 #include <net/net_namespace.h>
 #include <net/genetlink.h>
@@ -1974,20 +1975,22 @@ static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = {
 static int parse_txq_params(struct nlattr *tb[],
                            struct ieee80211_txq_params *txq_params)
 {
+       u8 ac;
+
        if (!tb[NL80211_TXQ_ATTR_AC] || !tb[NL80211_TXQ_ATTR_TXOP] ||
            !tb[NL80211_TXQ_ATTR_CWMIN] || !tb[NL80211_TXQ_ATTR_CWMAX] ||
            !tb[NL80211_TXQ_ATTR_AIFS])
                return -EINVAL;
 
-       txq_params->ac = nla_get_u8(tb[NL80211_TXQ_ATTR_AC]);
+       ac = nla_get_u8(tb[NL80211_TXQ_ATTR_AC]);
        txq_params->txop = nla_get_u16(tb[NL80211_TXQ_ATTR_TXOP]);
        txq_params->cwmin = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMIN]);
        txq_params->cwmax = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMAX]);
        txq_params->aifs = nla_get_u8(tb[NL80211_TXQ_ATTR_AIFS]);
 
-       if (txq_params->ac >= NL80211_NUM_ACS)
+       if (ac >= NL80211_NUM_ACS)
                return -EINVAL;
-
+       txq_params->ac = array_index_nospec(ac, NL80211_NUM_ACS);
        return 0;
 }
 
index 54ea796..0e9ae80 100644 (file)
@@ -1225,9 +1225,15 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(const struct sock *sk, int dir,
        read_lock_bh(&net->xfrm.xfrm_policy_lock);
        pol = rcu_dereference(sk->sk_policy[dir]);
        if (pol != NULL) {
-               bool match = xfrm_selector_match(&pol->selector, fl, family);
+               bool match;
                int err = 0;
 
+               if (pol->family != family) {
+                       pol = NULL;
+                       goto out;
+               }
+
+               match = xfrm_selector_match(&pol->selector, fl, family);
                if (match) {
                        if ((sk->sk_mark & pol->mark.m) != pol->mark.v) {
                                pol = NULL;
index 8b71b09..ed5c79a 100644 (file)
@@ -868,13 +868,13 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
                              &x->replay);
        if (ret)
                goto out;
-       if (x->security)
-               ret = copy_sec_ctx(x->security, skb);
        if (x->props.output_mark) {
                ret = nla_put_u32(skb, XFRMA_OUTPUT_MARK, x->props.output_mark);
                if (ret)
                        goto out;
        }
+       if (x->security)
+               ret = copy_sec_ctx(x->security, skb);
 out:
        return ret;
 }
@@ -1384,11 +1384,14 @@ static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut,
 
 static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family)
 {
+       u16 prev_family;
        int i;
 
        if (nr > XFRM_MAX_DEPTH)
                return -EINVAL;
 
+       prev_family = family;
+
        for (i = 0; i < nr; i++) {
                /* We never validated the ut->family value, so many
                 * applications simply leave it at zero.  The check was
@@ -1400,6 +1403,12 @@ static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family)
                if (!ut[i].family)
                        ut[i].family = family;
 
+               if ((ut[i].mode == XFRM_MODE_TRANSPORT) &&
+                   (ut[i].family != prev_family))
+                       return -EINVAL;
+
+               prev_family = ut[i].family;
+
                switch (ut[i].family) {
                case AF_INET:
                        break;
@@ -1410,6 +1419,21 @@ static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family)
                default:
                        return -EINVAL;
                }
+
+               switch (ut[i].id.proto) {
+               case IPPROTO_AH:
+               case IPPROTO_ESP:
+               case IPPROTO_COMP:
+#if IS_ENABLED(CONFIG_IPV6)
+               case IPPROTO_ROUTING:
+               case IPPROTO_DSTOPTS:
+#endif
+               case IPSEC_PROTO_ANY:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
        }
 
        return 0;
index e81a8c7..3d18e45 100644 (file)
@@ -40,16 +40,11 @@ enum checkstatus {
 
 struct check;
 
-typedef void (*tree_check_fn)(struct check *c, struct node *dt);
-typedef void (*node_check_fn)(struct check *c, struct node *dt, struct node *node);
-typedef void (*prop_check_fn)(struct check *c, struct node *dt,
-                             struct node *node, struct property *prop);
+typedef void (*check_fn)(struct check *c, struct dt_info *dti, struct node *node);
 
 struct check {
        const char *name;
-       tree_check_fn tree_fn;
-       node_check_fn node_fn;
-       prop_check_fn prop_fn;
+       check_fn fn;
        void *data;
        bool warn, error;
        enum checkstatus status;
@@ -58,45 +53,24 @@ struct check {
        struct check **prereq;
 };
 
-#define CHECK_ENTRY(nm, tfn, nfn, pfn, d, w, e, ...)          \
-       static struct check *nm##_prereqs[] = { __VA_ARGS__ }; \
-       static struct check nm = { \
-               .name = #nm, \
-               .tree_fn = (tfn), \
-               .node_fn = (nfn), \
-               .prop_fn = (pfn), \
-               .data = (d), \
-               .warn = (w), \
-               .error = (e), \
+#define CHECK_ENTRY(_nm, _fn, _d, _w, _e, ...)        \
+       static struct check *_nm##_prereqs[] = { __VA_ARGS__ }; \
+       static struct check _nm = { \
+               .name = #_nm, \
+               .fn = (_fn), \
+               .data = (_d), \
+               .warn = (_w), \
+               .error = (_e), \
                .status = UNCHECKED, \
-               .num_prereqs = ARRAY_SIZE(nm##_prereqs), \
-               .prereq = nm##_prereqs, \
+               .num_prereqs = ARRAY_SIZE(_nm##_prereqs), \
+               .prereq = _nm##_prereqs, \
        };
-#define WARNING(nm, tfn, nfn, pfn, d, ...) \
-       CHECK_ENTRY(nm, tfn, nfn, pfn, d, true, false, __VA_ARGS__)
-#define ERROR(nm, tfn, nfn, pfn, d, ...) \
-       CHECK_ENTRY(nm, tfn, nfn, pfn, d, false, true, __VA_ARGS__)
-#define CHECK(nm, tfn, nfn, pfn, d, ...) \
-       CHECK_ENTRY(nm, tfn, nfn, pfn, d, false, false, __VA_ARGS__)
-
-#define TREE_WARNING(nm, d, ...) \
-       WARNING(nm, check_##nm, NULL, NULL, d, __VA_ARGS__)
-#define TREE_ERROR(nm, d, ...) \
-       ERROR(nm, check_##nm, NULL, NULL, d, __VA_ARGS__)
-#define TREE_CHECK(nm, d, ...) \
-       CHECK(nm, check_##nm, NULL, NULL, d, __VA_ARGS__)
-#define NODE_WARNING(nm, d, ...) \
-       WARNING(nm, NULL, check_##nm, NULL, d,  __VA_ARGS__)
-#define NODE_ERROR(nm, d, ...) \
-       ERROR(nm, NULL, check_##nm, NULL, d, __VA_ARGS__)
-#define NODE_CHECK(nm, d, ...) \
-       CHECK(nm, NULL, check_##nm, NULL, d, __VA_ARGS__)
-#define PROP_WARNING(nm, d, ...) \
-       WARNING(nm, NULL, NULL, check_##nm, d, __VA_ARGS__)
-#define PROP_ERROR(nm, d, ...) \
-       ERROR(nm, NULL, NULL, check_##nm, d, __VA_ARGS__)
-#define PROP_CHECK(nm, d, ...) \
-       CHECK(nm, NULL, NULL, check_##nm, d, __VA_ARGS__)
+#define WARNING(_nm, _fn, _d, ...) \
+       CHECK_ENTRY(_nm, _fn, _d, true, false, __VA_ARGS__)
+#define ERROR(_nm, _fn, _d, ...) \
+       CHECK_ENTRY(_nm, _fn, _d, false, true, __VA_ARGS__)
+#define CHECK(_nm, _fn, _d, ...) \
+       CHECK_ENTRY(_nm, _fn, _d, false, false, __VA_ARGS__)
 
 #ifdef __GNUC__
 static inline void check_msg(struct check *c, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
@@ -123,27 +97,21 @@ static inline void check_msg(struct check *c, const char *fmt, ...)
                check_msg((c), __VA_ARGS__); \
        } while (0)
 
-static void check_nodes_props(struct check *c, struct node *dt, struct node *node)
+static void check_nodes_props(struct check *c, struct dt_info *dti, struct node *node)
 {
        struct node *child;
-       struct property *prop;
 
        TRACE(c, "%s", node->fullpath);
-       if (c->node_fn)
-               c->node_fn(c, dt, node);
-
-       if (c->prop_fn)
-               for_each_property(node, prop) {
-                       TRACE(c, "%s\t'%s'", node->fullpath, prop->name);
-                       c->prop_fn(c, dt, node, prop);
-               }
+       if (c->fn)
+               c->fn(c, dti, node);
 
        for_each_child(node, child)
-               check_nodes_props(c, dt, child);
+               check_nodes_props(c, dti, child);
 }
 
-static bool run_check(struct check *c, struct node *dt)
+static bool run_check(struct check *c, struct dt_info *dti)
 {
+       struct node *dt = dti->dt;
        bool error = false;
        int i;
 
@@ -156,7 +124,7 @@ static bool run_check(struct check *c, struct node *dt)
 
        for (i = 0; i < c->num_prereqs; i++) {
                struct check *prq = c->prereq[i];
-               error = error || run_check(prq, dt);
+               error = error || run_check(prq, dti);
                if (prq->status != PASSED) {
                        c->status = PREREQ;
                        check_msg(c, "Failed prerequisite '%s'",
@@ -167,11 +135,8 @@ static bool run_check(struct check *c, struct node *dt)
        if (c->status != UNCHECKED)
                goto out;
 
-       if (c->node_fn || c->prop_fn)
-               check_nodes_props(c, dt, dt);
+       check_nodes_props(c, dti, dt);
 
-       if (c->tree_fn)
-               c->tree_fn(c, dt);
        if (c->status == UNCHECKED)
                c->status = PASSED;
 
@@ -189,13 +154,14 @@ out:
  */
 
 /* A check which always fails, for testing purposes only */
-static inline void check_always_fail(struct check *c, struct node *dt)
+static inline void check_always_fail(struct check *c, struct dt_info *dti,
+                                    struct node *node)
 {
        FAIL(c, "always_fail check");
 }
-TREE_CHECK(always_fail, NULL);
+CHECK(always_fail, check_always_fail, NULL);
 
-static void check_is_string(struct check *c, struct node *root,
+static void check_is_string(struct check *c, struct dt_info *dti,
                            struct node *node)
 {
        struct property *prop;
@@ -210,11 +176,11 @@ static void check_is_string(struct check *c, struct node *root,
                     propname, node->fullpath);
 }
 #define WARNING_IF_NOT_STRING(nm, propname) \
-       WARNING(nm, NULL, check_is_string, NULL, (propname))
+       WARNING(nm, check_is_string, (propname))
 #define ERROR_IF_NOT_STRING(nm, propname) \
-       ERROR(nm, NULL, check_is_string, NULL, (propname))
+       ERROR(nm, check_is_string, (propname))
 
-static void check_is_cell(struct check *c, struct node *root,
+static void check_is_cell(struct check *c, struct dt_info *dti,
                          struct node *node)
 {
        struct property *prop;
@@ -229,15 +195,15 @@ static void check_is_cell(struct check *c, struct node *root,
                     propname, node->fullpath);
 }
 #define WARNING_IF_NOT_CELL(nm, propname) \
-       WARNING(nm, NULL, check_is_cell, NULL, (propname))
+       WARNING(nm, check_is_cell, (propname))
 #define ERROR_IF_NOT_CELL(nm, propname) \
-       ERROR(nm, NULL, check_is_cell, NULL, (propname))
+       ERROR(nm, check_is_cell, (propname))
 
 /*
  * Structural check functions
  */
 
-static void check_duplicate_node_names(struct check *c, struct node *dt,
+static void check_duplicate_node_names(struct check *c, struct dt_info *dti,
                                       struct node *node)
 {
        struct node *child, *child2;
@@ -250,9 +216,9 @@ static void check_duplicate_node_names(struct check *c, struct node *dt,
                                FAIL(c, "Duplicate node name %s",
                                     child->fullpath);
 }
-NODE_ERROR(duplicate_node_names, NULL);
+ERROR(duplicate_node_names, check_duplicate_node_names, NULL);
 
-static void check_duplicate_property_names(struct check *c, struct node *dt,
+static void check_duplicate_property_names(struct check *c, struct dt_info *dti,
                                           struct node *node)
 {
        struct property *prop, *prop2;
@@ -267,14 +233,14 @@ static void check_duplicate_property_names(struct check *c, struct node *dt,
                }
        }
 }
-NODE_ERROR(duplicate_property_names, NULL);
+ERROR(duplicate_property_names, check_duplicate_property_names, NULL);
 
 #define LOWERCASE      "abcdefghijklmnopqrstuvwxyz"
 #define UPPERCASE      "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 #define DIGITS         "0123456789"
 #define PROPNODECHARS  LOWERCASE UPPERCASE DIGITS ",._+*#?-"
 
-static void check_node_name_chars(struct check *c, struct node *dt,
+static void check_node_name_chars(struct check *c, struct dt_info *dti,
                                  struct node *node)
 {
        int n = strspn(node->name, c->data);
@@ -283,27 +249,55 @@ static void check_node_name_chars(struct check *c, struct node *dt,
                FAIL(c, "Bad character '%c' in node %s",
                     node->name[n], node->fullpath);
 }
-NODE_ERROR(node_name_chars, PROPNODECHARS "@");
+ERROR(node_name_chars, check_node_name_chars, PROPNODECHARS "@");
 
-static void check_node_name_format(struct check *c, struct node *dt,
+static void check_node_name_format(struct check *c, struct dt_info *dti,
                                   struct node *node)
 {
        if (strchr(get_unitname(node), '@'))
                FAIL(c, "Node %s has multiple '@' characters in name",
                     node->fullpath);
 }
-NODE_ERROR(node_name_format, NULL, &node_name_chars);
+ERROR(node_name_format, check_node_name_format, NULL, &node_name_chars);
+
+static void check_unit_address_vs_reg(struct check *c, struct dt_info *dti,
+                                     struct node *node)
+{
+       const char *unitname = get_unitname(node);
+       struct property *prop = get_property(node, "reg");
+
+       if (!prop) {
+               prop = get_property(node, "ranges");
+               if (prop && !prop->val.len)
+                       prop = NULL;
+       }
+
+       if (prop) {
+               if (!unitname[0])
+                       FAIL(c, "Node %s has a reg or ranges property, but no unit name",
+                           node->fullpath);
+       } else {
+               if (unitname[0])
+                       FAIL(c, "Node %s has a unit name, but no reg property",
+                           node->fullpath);
+       }
+}
+WARNING(unit_address_vs_reg, check_unit_address_vs_reg, NULL);
 
-static void check_property_name_chars(struct check *c, struct node *dt,
-                                     struct node *node, struct property *prop)
+static void check_property_name_chars(struct check *c, struct dt_info *dti,
+                                     struct node *node)
 {
-       int n = strspn(prop->name, c->data);
+       struct property *prop;
 
-       if (n < strlen(prop->name))
-               FAIL(c, "Bad character '%c' in property name \"%s\", node %s",
-                    prop->name[n], prop->name, node->fullpath);
+       for_each_property(node, prop) {
+               int n = strspn(prop->name, c->data);
+
+               if (n < strlen(prop->name))
+                       FAIL(c, "Bad character '%c' in property name \"%s\", node %s",
+                            prop->name[n], prop->name, node->fullpath);
+       }
 }
-PROP_ERROR(property_name_chars, PROPNODECHARS);
+ERROR(property_name_chars, check_property_name_chars, PROPNODECHARS);
 
 #define DESCLABEL_FMT  "%s%s%s%s%s"
 #define DESCLABEL_ARGS(node,prop,mark)         \
@@ -312,10 +306,11 @@ PROP_ERROR(property_name_chars, PROPNODECHARS);
        ((prop) ? (prop)->name : ""), \
        ((prop) ? "' in " : ""), (node)->fullpath
 
-static void check_duplicate_label(struct check *c, struct node *dt,
+static void check_duplicate_label(struct check *c, struct dt_info *dti,
                                  const char *label, struct node *node,
                                  struct property *prop, struct marker *mark)
 {
+       struct node *dt = dti->dt;
        struct node *othernode = NULL;
        struct property *otherprop = NULL;
        struct marker *othermark = NULL;
@@ -338,44 +333,43 @@ static void check_duplicate_label(struct check *c, struct node *dt,
                     DESCLABEL_ARGS(othernode, otherprop, othermark));
 }
 
-static void check_duplicate_label_node(struct check *c, struct node *dt,
+static void check_duplicate_label_node(struct check *c, struct dt_info *dti,
                                       struct node *node)
 {
        struct label *l;
+       struct property *prop;
 
        for_each_label(node->labels, l)
-               check_duplicate_label(c, dt, l->label, node, NULL, NULL);
-}
-static void check_duplicate_label_prop(struct check *c, struct node *dt,
-                                      struct node *node, struct property *prop)
-{
-       struct marker *m = prop->val.markers;
-       struct label *l;
+               check_duplicate_label(c, dti, l->label, node, NULL, NULL);
+
+       for_each_property(node, prop) {
+               struct marker *m = prop->val.markers;
 
-       for_each_label(prop->labels, l)
-               check_duplicate_label(c, dt, l->label, node, prop, NULL);
+               for_each_label(prop->labels, l)
+                       check_duplicate_label(c, dti, l->label, node, prop, NULL);
 
-       for_each_marker_of_type(m, LABEL)
-               check_duplicate_label(c, dt, m->ref, node, prop, m);
+               for_each_marker_of_type(m, LABEL)
+                       check_duplicate_label(c, dti, m->ref, node, prop, m);
+       }
 }
-ERROR(duplicate_label, NULL, check_duplicate_label_node,
-      check_duplicate_label_prop, NULL);
+ERROR(duplicate_label, check_duplicate_label_node, NULL);
 
-static void check_explicit_phandles(struct check *c, struct node *root,
-                                   struct node *node, struct property *prop)
+static cell_t check_phandle_prop(struct check *c, struct dt_info *dti,
+                                struct node *node, const char *propname)
 {
+       struct node *root = dti->dt;
+       struct property *prop;
        struct marker *m;
-       struct node *other;
        cell_t phandle;
 
-       if (!streq(prop->name, "phandle")
-           && !streq(prop->name, "linux,phandle"))
-               return;
+       prop = get_property(node, propname);
+       if (!prop)
+               return 0;
 
        if (prop->val.len != sizeof(cell_t)) {
                FAIL(c, "%s has bad length (%d) %s property",
                     node->fullpath, prop->val.len, prop->name);
-               return;
+               return 0;
        }
 
        m = prop->val.markers;
@@ -387,14 +381,13 @@ static void check_explicit_phandles(struct check *c, struct node *root,
                         * by construction. */ {
                        FAIL(c, "%s in %s is a reference to another node",
                             prop->name, node->fullpath);
-                       return;
                }
                /* But setting this node's phandle equal to its own
                 * phandle is allowed - that means allocate a unique
                 * phandle for this node, even if it's not otherwise
                 * referenced.  The value will be filled in later, so
-                * no further checking for now. */
-               return;
+                * we treat it as having no phandle data for now. */
+               return 0;
        }
 
        phandle = propval_cell(prop);
@@ -402,12 +395,36 @@ static void check_explicit_phandles(struct check *c, struct node *root,
        if ((phandle == 0) || (phandle == -1)) {
                FAIL(c, "%s has bad value (0x%x) in %s property",
                     node->fullpath, phandle, prop->name);
-               return;
+               return 0;
        }
 
-       if (node->phandle && (node->phandle != phandle))
-               FAIL(c, "%s has %s property which replaces existing phandle information",
-                    node->fullpath, prop->name);
+       return phandle;
+}
+
+static void check_explicit_phandles(struct check *c, struct dt_info *dti,
+                                   struct node *node)
+{
+       struct node *root = dti->dt;
+       struct node *other;
+       cell_t phandle, linux_phandle;
+
+       /* Nothing should have assigned phandles yet */
+       assert(!node->phandle);
+
+       phandle = check_phandle_prop(c, dti, node, "phandle");
+
+       linux_phandle = check_phandle_prop(c, dti, node, "linux,phandle");
+
+       if (!phandle && !linux_phandle)
+               /* No valid phandles; nothing further to check */
+               return;
+
+       if (linux_phandle && phandle && (phandle != linux_phandle))
+               FAIL(c, "%s has mismatching 'phandle' and 'linux,phandle'"
+                    " properties", node->fullpath);
+
+       if (linux_phandle && !phandle)
+               phandle = linux_phandle;
 
        other = get_node_by_phandle(root, phandle);
        if (other && (other != node)) {
@@ -418,9 +435,9 @@ static void check_explicit_phandles(struct check *c, struct node *root,
 
        node->phandle = phandle;
 }
-PROP_ERROR(explicit_phandles, NULL);
+ERROR(explicit_phandles, check_explicit_phandles, NULL);
 
-static void check_name_properties(struct check *c, struct node *root,
+static void check_name_properties(struct check *c, struct dt_info *dti,
                                  struct node *node)
 {
        struct property **pp, *prop = NULL;
@@ -448,60 +465,73 @@ static void check_name_properties(struct check *c, struct node *root,
        }
 }
 ERROR_IF_NOT_STRING(name_is_string, "name");
-NODE_ERROR(name_properties, NULL, &name_is_string);
+ERROR(name_properties, check_name_properties, NULL, &name_is_string);
 
 /*
  * Reference fixup functions
  */
 
-static void fixup_phandle_references(struct check *c, struct node *dt,
-                                    struct node *node, struct property *prop)
+static void fixup_phandle_references(struct check *c, struct dt_info *dti,
+                                    struct node *node)
 {
-       struct marker *m = prop->val.markers;
-       struct node *refnode;
-       cell_t phandle;
+       struct node *dt = dti->dt;
+       struct property *prop;
 
-       for_each_marker_of_type(m, REF_PHANDLE) {
-               assert(m->offset + sizeof(cell_t) <= prop->val.len);
+       for_each_property(node, prop) {
+               struct marker *m = prop->val.markers;
+               struct node *refnode;
+               cell_t phandle;
+
+               for_each_marker_of_type(m, REF_PHANDLE) {
+                       assert(m->offset + sizeof(cell_t) <= prop->val.len);
+
+                       refnode = get_node_by_ref(dt, m->ref);
+                       if (! refnode) {
+                               if (!(dti->dtsflags & DTSF_PLUGIN))
+                                       FAIL(c, "Reference to non-existent node or "
+                                                       "label \"%s\"\n", m->ref);
+                               else /* mark the entry as unresolved */
+                                       *((cell_t *)(prop->val.val + m->offset)) =
+                                               cpu_to_fdt32(0xffffffff);
+                               continue;
+                       }
 
-               refnode = get_node_by_ref(dt, m->ref);
-               if (! refnode) {
-                       FAIL(c, "Reference to non-existent node or label \"%s\"\n",
-                            m->ref);
-                       continue;
+                       phandle = get_node_phandle(dt, refnode);
+                       *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
                }
-
-               phandle = get_node_phandle(dt, refnode);
-               *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
        }
 }
-ERROR(phandle_references, NULL, NULL, fixup_phandle_references, NULL,
+ERROR(phandle_references, fixup_phandle_references, NULL,
       &duplicate_node_names, &explicit_phandles);
 
-static void fixup_path_references(struct check *c, struct node *dt,
-                                 struct node *node, struct property *prop)
+static void fixup_path_references(struct check *c, struct dt_info *dti,
+                                 struct node *node)
 {
-       struct marker *m = prop->val.markers;
-       struct node *refnode;
-       char *path;
-
-       for_each_marker_of_type(m, REF_PATH) {
-               assert(m->offset <= prop->val.len);
-
-               refnode = get_node_by_ref(dt, m->ref);
-               if (!refnode) {
-                       FAIL(c, "Reference to non-existent node or label \"%s\"\n",
-                            m->ref);
-                       continue;
-               }
+       struct node *dt = dti->dt;
+       struct property *prop;
+
+       for_each_property(node, prop) {
+               struct marker *m = prop->val.markers;
+               struct node *refnode;
+               char *path;
+
+               for_each_marker_of_type(m, REF_PATH) {
+                       assert(m->offset <= prop->val.len);
 
-               path = refnode->fullpath;
-               prop->val = data_insert_at_marker(prop->val, m, path,
-                                                 strlen(path) + 1);
+                       refnode = get_node_by_ref(dt, m->ref);
+                       if (!refnode) {
+                               FAIL(c, "Reference to non-existent node or label \"%s\"\n",
+                                    m->ref);
+                               continue;
+                       }
+
+                       path = refnode->fullpath;
+                       prop->val = data_insert_at_marker(prop->val, m, path,
+                                                         strlen(path) + 1);
+               }
        }
 }
-ERROR(path_references, NULL, NULL, fixup_path_references, NULL,
-      &duplicate_node_names);
+ERROR(path_references, fixup_path_references, NULL, &duplicate_node_names);
 
 /*
  * Semantic checks
@@ -514,7 +544,7 @@ WARNING_IF_NOT_STRING(device_type_is_string, "device_type");
 WARNING_IF_NOT_STRING(model_is_string, "model");
 WARNING_IF_NOT_STRING(status_is_string, "status");
 
-static void fixup_addr_size_cells(struct check *c, struct node *dt,
+static void fixup_addr_size_cells(struct check *c, struct dt_info *dti,
                                  struct node *node)
 {
        struct property *prop;
@@ -530,7 +560,7 @@ static void fixup_addr_size_cells(struct check *c, struct node *dt,
        if (prop)
                node->size_cells = propval_cell(prop);
 }
-WARNING(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL,
+WARNING(addr_size_cells, fixup_addr_size_cells, NULL,
        &address_cells_is_cell, &size_cells_is_cell);
 
 #define node_addr_cells(n) \
@@ -538,7 +568,7 @@ WARNING(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL,
 #define node_size_cells(n) \
        (((n)->size_cells == -1) ? 1 : (n)->size_cells)
 
-static void check_reg_format(struct check *c, struct node *dt,
+static void check_reg_format(struct check *c, struct dt_info *dti,
                             struct node *node)
 {
        struct property *prop;
@@ -560,14 +590,14 @@ static void check_reg_format(struct check *c, struct node *dt,
        size_cells = node_size_cells(node->parent);
        entrylen = (addr_cells + size_cells) * sizeof(cell_t);
 
-       if ((prop->val.len % entrylen) != 0)
+       if (!entrylen || (prop->val.len % entrylen) != 0)
                FAIL(c, "\"reg\" property in %s has invalid length (%d bytes) "
                     "(#address-cells == %d, #size-cells == %d)",
                     node->fullpath, prop->val.len, addr_cells, size_cells);
 }
-NODE_WARNING(reg_format, NULL, &addr_size_cells);
+WARNING(reg_format, check_reg_format, NULL, &addr_size_cells);
 
-static void check_ranges_format(struct check *c, struct node *dt,
+static void check_ranges_format(struct check *c, struct dt_info *dti,
                                struct node *node)
 {
        struct property *prop;
@@ -606,12 +636,12 @@ static void check_ranges_format(struct check *c, struct node *dt,
                     p_addr_cells, c_addr_cells, c_size_cells);
        }
 }
-NODE_WARNING(ranges_format, NULL, &addr_size_cells);
+WARNING(ranges_format, check_ranges_format, NULL, &addr_size_cells);
 
 /*
  * Style checks
  */
-static void check_avoid_default_addr_size(struct check *c, struct node *dt,
+static void check_avoid_default_addr_size(struct check *c, struct dt_info *dti,
                                          struct node *node)
 {
        struct property *reg, *ranges;
@@ -633,14 +663,21 @@ static void check_avoid_default_addr_size(struct check *c, struct node *dt,
                FAIL(c, "Relying on default #size-cells value for %s",
                     node->fullpath);
 }
-NODE_WARNING(avoid_default_addr_size, NULL, &addr_size_cells);
+WARNING(avoid_default_addr_size, check_avoid_default_addr_size, NULL,
+       &addr_size_cells);
 
 static void check_obsolete_chosen_interrupt_controller(struct check *c,
-                                                      struct node *dt)
+                                                      struct dt_info *dti,
+                                                      struct node *node)
 {
+       struct node *dt = dti->dt;
        struct node *chosen;
        struct property *prop;
 
+       if (node != dt)
+               return;
+
+
        chosen = get_node_by_path(dt, "/chosen");
        if (!chosen)
                return;
@@ -650,7 +687,8 @@ static void check_obsolete_chosen_interrupt_controller(struct check *c,
                FAIL(c, "/chosen has obsolete \"interrupt-controller\" "
                     "property");
 }
-TREE_WARNING(obsolete_chosen_interrupt_controller, NULL);
+WARNING(obsolete_chosen_interrupt_controller,
+       check_obsolete_chosen_interrupt_controller, NULL);
 
 static struct check *check_table[] = {
        &duplicate_node_names, &duplicate_property_names,
@@ -667,6 +705,8 @@ static struct check *check_table[] = {
 
        &addr_size_cells, &reg_format, &ranges_format,
 
+       &unit_address_vs_reg,
+
        &avoid_default_addr_size,
        &obsolete_chosen_interrupt_controller,
 
@@ -734,9 +774,8 @@ void parse_checks_option(bool warn, bool error, const char *arg)
        die("Unrecognized check name \"%s\"\n", name);
 }
 
-void process_checks(bool force, struct boot_info *bi)
+void process_checks(bool force, struct dt_info *dti)
 {
-       struct node *dt = bi->dt;
        int i;
        int error = 0;
 
@@ -744,7 +783,7 @@ void process_checks(bool force, struct boot_info *bi)
                struct check *c = check_table[i];
 
                if (c->warn || c->error)
-                       error = error || run_check(c, dt);
+                       error = error || run_check(c, dti);
        }
 
        if (error) {
diff --git a/scripts/dtc/dt_to_config b/scripts/dtc/dt_to_config
new file mode 100755 (executable)
index 0000000..9a248b5
--- /dev/null
@@ -0,0 +1,1213 @@
+#!/usr/bin/perl
+
+# Copyright 2016 by Frank Rowand
+# Copyright 2016 by Gaurav Minocha
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License v2.
+
+use strict 'refs';
+use strict subs;
+
+use Getopt::Long;
+
+$VUFX = "160610a";
+
+$script_name = $0;
+$script_name =~ s|^.*/||;
+
+
+# ----- constants for print_flags()
+
+# Position in string $pr_flags.  Range of 0..($num_pr_flags - 1).
+$pr_flag_pos_mcompatible       = 0;
+$pr_flag_pos_driver            = 1;
+$pr_flag_pos_mdriver           = 2;
+$pr_flag_pos_config            = 3;
+$pr_flag_pos_mconfig           = 4;
+$pr_flag_pos_node_not_enabled  = 5;
+$pr_flag_pos_white_list        = 6;
+$pr_flag_pos_hard_coded        = 7;
+$pr_flag_pos_config_hard_coded = 8;
+$pr_flag_pos_config_none       = 9;
+$pr_flag_pos_config_m          = 10;
+$pr_flag_pos_config_y          = 11;
+$pr_flag_pos_config_test_fail  = 12;
+
+$num_pr_flags = $pr_flag_pos_config_test_fail + 1;
+
+# flags in @pr_flag_value must be unique values to allow simple regular
+# expessions to work for --include_flags and --exclude_flags.
+# Convention: use upper case letters for potential issues or problems.
+
+@pr_flag_value = ('M', 'd', 'D', 'c', 'C', 'E', 'W', 'H', 'x', 'n', 'm', 'y', 'F');
+
+@pr_flag_help = (
+    "multiple compatibles found for this node",
+    "driver found for this compatible",
+    "multiple drivers found for this compatible",
+    "kernel config found for this driver",
+    "multiple config options found for this driver",
+    "node is not enabled",
+    "compatible is white listed",
+    "matching driver and/or kernel config is hard coded",
+    "kernel config hard coded in Makefile",
+    "one or more kernel config file options is not set",
+    "one or more kernel config file options is set to 'm'",
+    "one or more kernel config file options is set to 'y'",
+    "one of more kernel config file options fails to have correct value"
+);
+
+
+# -----
+
+%driver_config = ();   # driver config array, indexed by driver source file
+%driver_count = ();    # driver_cnt, indexed by compatible
+%compat_driver = ();   # compatible driver array, indexed by compatible
+%existing_config = (); # existing config symbols present in given config file
+                       # expected values are: "y", "m", a decimal number, a
+                       # hex number, or a string
+
+# ----- magic compatibles, do not have a driver
+#
+# Will not search for drivers for these compatibles.
+
+%compat_white_list = (
+       'none'                  => '1',
+       'pci'                   => '1',
+       'simple-bus'            => '1',
+);
+
+# Will not search for drivers for these compatibles.
+#
+# These compatibles have a very large number of false positives.
+#
+# 'hardcoded_no_driver' is a magic value.  Other code knows this
+# magic value.  Do not use 'no_driver' here!
+#
+# Revisit each 'hardcoded_no_driver' to see how the compatible
+# is used.  Are there drivers that can be provided?
+
+%driver_hard_code_list = (
+       'cache'                 => ['hardcoded_no_driver'],
+       'eeprom'                => ['hardcoded_no_driver'],
+       'gpio'                  => ['hardcoded_no_driver'],
+       'gpio-keys'             => ['drivers/input/keyboard/gpio_keys.c'],
+       'i2c-gpio'              => ['drivers/i2c/busses/i2c-gpio.c'],
+       'isa'                   => ['arch/mips/mti-malta/malta-dt.c',
+                                    'arch/x86/kernel/devicetree.c'],
+       'led'                   => ['hardcoded_no_driver'],
+       'm25p32'                => ['hardcoded_no_driver'],
+       'm25p64'                => ['hardcoded_no_driver'],
+       'm25p80'                => ['hardcoded_no_driver'],
+       'mtd-ram'               => ['drivers/mtd/maps/physmap_of.c'],
+       'pwm-backlight'         => ['drivers/video/backlight/pwm_bl.c'],
+       'spidev'                => ['hardcoded_no_driver'],
+       'syscon'                => ['drivers/mfd/syscon.c'],
+       'tlv320aic23'           => ['hardcoded_no_driver'],
+       'wm8731'                => ['hardcoded_no_driver'],
+);
+
+# Use these config options instead of searching makefiles
+
+%driver_config_hard_code_list = (
+
+       # this one needed even if %driver_hard_code_list is empty
+       'no_driver'                             => ['no_config'],
+       'hardcoded_no_driver'                   => ['no_config'],
+
+       # drivers/usb/host/ehci-ppc-of.c
+       # drivers/usb/host/ehci-xilinx-of.c
+       #  are included from:
+       #    drivers/usb/host/ehci-hcd.c
+       #  thus the search of Makefile for the included .c files is incorrect
+       # ehci-hcd.c wraps the includes with ifdef CONFIG_USB_EHCI_HCD_..._OF
+       #
+       # similar model for ohci-hcd.c (but no ohci-xilinx-of.c)
+       #
+       # similarly, uhci-hcd.c includes uhci-platform.c
+
+       'drivers/usb/host/ehci-ppc-of.c'        => ['CONFIG_USB_EHCI_HCD',
+                                                   'CONFIG_USB_EHCI_HCD_PPC_OF'],
+       'drivers/usb/host/ohci-ppc-of.c'        => ['CONFIG_USB_OHCI_HCD',
+                                                   'CONFIG_USB_OHCI_HCD_PPC_OF'],
+
+       'drivers/usb/host/ehci-xilinx-of.c'     => ['CONFIG_USB_EHCI_HCD',
+                                                   'CONFIG_USB_EHCI_HCD_XILINX'],
+
+       'drivers/usb/host/uhci-platform.c'      => ['CONFIG_USB_UHCI_HCD',
+                                                   'CONFIG_USB_UHCI_PLATFORM'],
+
+       # scan_makefile will find only one of these config options:
+       #    ifneq ($(CONFIG_SOC_IMX6)$(CONFIG_SOC_LS1021A),)
+       'arch/arm/mach-imx/platsmp.c'           => ['CONFIG_SOC_IMX6 && CONFIG_SMP',
+                                                   'CONFIG_SOC_LS1021A && CONFIG_SMP'],
+);
+
+
+# 'virt/kvm/arm/.*' are controlled by makefiles in other directories,
+# using relative paths, such as 'KVM := ../../../virt/kvm'.  Do not
+# add complexity to find_kconfig() to deal with this.  There is a long
+# term intent to change the kvm related makefiles to the normal kernel
+# style.  After that is done, this entry can be removed from the
+# black_list_driver.
+
+@black_list_driver = (
+       # kvm no longer a problem after commit 503a62862e8f in 4.7-rc1
+       # 'virt/kvm/arm/.*',
+);
+
+
+sub usage()
+{
+       print
+"
+Usage: $script_name [options] device-tree...
+
+    device_tree is: dts_file | dtb_file | proc_device-tree
+
+
+Valid options:
+     -c FILE             Read kernel config options from FILE
+    --config FILE        synonym for 'c'
+    --config-format      config file friendly output format
+    --exclude-flag FLAG  exclude entries with a matching flag
+     -h                  Display this message and exit
+    --help               synonym for 'h'
+    --black-list-driver  use driver black list
+    --white-list-config  use config white list
+    --white-list-driver  use driver white list
+    --include-flag FLAG  include only entries with a matching flag
+    --include-suspect    include only entries with an uppercase flag
+    --short-name         do not show the path portion of the node name
+    --show-lists         report of white and black lists
+    --version            Display program version and exit
+
+
+  Report driver source files that match the compatibles in the device
+  tree file and the kernel config options that enable the driver source
+  files.
+
+  This program must be run in the root directory of a Linux kernel
+  source tree.
+
+  The default format is a report that is intended to be easily human
+  scannable.
+
+  An alternate format can be selected by --config-format.  This will
+  create output that can easily be edited to create a fragment that can
+  be appended to the existing kernel config file.  Each entry consists of
+  multiple lines.  The first line reports flags, the node path, compatible
+  value, driver file matching the compatible, configuration options, and
+  current values of the configuration options.  For each configuration
+  option, the following lines report the current value and the value that
+  is required for the driver file to be included in the kernel.
+
+  If a large number of drivers or config options is listed for a node,
+  and the '$pr_flag_value[$pr_flag_pos_hard_coded]' flag is set consider using --white-list-config and/or
+  --white-list-driver.  If the white list option suppresses the correct
+  entry please report that as a bug.
+
+  CAUTION:
+     This program uses heuristics to guess which driver(s) support each
+     compatible string and which config option(s) enables the driver(s).
+     Do not believe that the reported information is fully correct.
+     This program is intended to aid the process of determining the
+     proper kernel configuration for a device tree, but this is not
+     a fully automated process -- human involvement may still be
+     required!
+
+     The driver match heuristic used is to search for source files
+     containing the compatible string enclosed in quotes.
+
+     This program might not be able to find all drivers matching a
+     compatible string.
+
+     Some makefiles are overly clever.  This program was not made
+     complex enough to handle them.  If no config option is listed
+     for a driver, look at the makefile for the driver source file.
+     Even if a config option is listed for a driver, some other
+     available config options may not be listed.
+
+  FLAG values:
+";
+
+       for ($k = 0; $k < $num_pr_flags; $k++) {
+               printf "     %s   %s\n", $pr_flag_value[$k], $pr_flag_help[$k];
+       }
+
+       print
+"
+     Upper case letters indicate potential issues or problems.
+
+  The flag:
+
+";
+
+       $k = $pr_flag_pos_hard_coded;
+       printf "     %s   %s\n", $pr_flag_value[$k], $pr_flag_help[$k];
+
+       print
+"
+  will be set if the config or driver is in the white lists, even if
+  --white-list-config and --white-list-driver are not specified.
+  This is a hint that 1) many of these reported lines are likely to
+  be incorrect, and 2) using those options will reduce the number of
+  drivers and/or config options reported.
+
+  --white-list-config and --white-list-driver may not be accurate if this
+  program is not well maintained.  Use them with appropriate skepticism.
+  Use the --show-lists option to report the values in the list.
+
+  Return value:
+    0   if no error
+    1   error processing command line
+    2   unable to open or read kernel config file
+    3   unable to open or process input device tree file(s)
+
+  EXAMPLES:
+
+     dt_to_config arch/arm/boot/dts/my_dts_file.dts
+
+       Basic report.
+
+     dt_to_config \\
+        --config \${KBUILD_OUTPUT}/.config \\
+        arch/\${ARCH}/boot/dts/my_dts_file.dts
+
+       Full report, with config file issues noted.
+
+     dt_to_config --include-suspect \\
+        --config \${KBUILD_OUTPUT}/.config \\
+        arch/\${ARCH}/boot/dts/my_dts_file.dts
+
+       Report of node / compatible string / driver tuples that should
+       be further investigated.  A node may have multiple compatible
+       strings.  A compatible string may be matched by multiple drivers.
+       A driver may have config file issues noted.  The compatible string
+       and/or driver may be in the white lists.
+
+     dt_to_config --include-suspect --config-format \\
+        --config ${KBUILD_OUTPUT}/.config \\
+        arch/\${ARCH}/boot/dts/my_dts_file.dts
+
+       Report of node / compatible string / driver tuples that should
+       be further investigated.  The report can be edited to uncomment
+       the config options to select the desired tuple for a given node.
+       A node may have multiple compatible strings.  A compatible string
+       may be matched by multiple drivers.  A driver may have config file
+       issues noted.  The compatible string and/or driver may be in the
+       white lists.
+
+";
+}
+
+sub set_flag()
+{
+       # pr_flags_ref is a reference to $pr_flags
+
+       my $pr_flags_ref = shift;
+       my $pos          = shift;
+
+       substr $$pr_flags_ref, $pos, 1, $pr_flag_value[$pos];
+
+       return $pr_flags;
+}
+
+sub print_flags()
+{
+       # return 1 if anything printed, else 0
+
+       # some fields of pn_arg_ref might not be used in this function, but
+       # extract all of them anyway.
+       my $pn_arg_ref     = shift;
+
+       my $compat         = $pn_arg_ref->{compat};
+       my $compatible_cnt = $pn_arg_ref->{compatible_cnt};
+       my $config         = $pn_arg_ref->{config};
+       my $config_cnt     = $pn_arg_ref->{config_cnt};
+       my $driver         = $pn_arg_ref->{driver};
+       my $driver_cnt     = $pn_arg_ref->{driver_cnt};
+       my $full_node      = $pn_arg_ref->{full_node};
+       my $node           = $pn_arg_ref->{node};
+       my $node_enabled   = $pn_arg_ref->{node_enabled};
+       my $white_list     = $pn_arg_ref->{white_list};
+
+       my $pr_flags       = '-' x $num_pr_flags;
+
+
+       # ----- set flags in $pr_flags
+
+       if ($compatible_cnt > 1) {
+               &set_flag(\$pr_flags, $pr_flag_pos_mcompatible);
+       }
+
+       if ($config_cnt > 1) {
+               &set_flag(\$pr_flags, $pr_flag_pos_mconfig);
+       }
+
+       if ($driver_cnt >= 1) {
+               &set_flag(\$pr_flags, $pr_flag_pos_driver);
+       }
+
+       if ($driver_cnt > 1) {
+               &set_flag(\$pr_flags, $pr_flag_pos_mdriver);
+       }
+
+       # These strings are the same way the linux kernel tests.
+       # The ePapr lists of values is slightly different.
+       if (!(
+             ($node_enabled eq "") ||
+             ($node_enabled eq "ok") ||
+             ($node_enabled eq "okay")
+            )) {
+               &set_flag(\$pr_flags, $pr_flag_pos_node_not_enabled);
+       }
+
+       if ($white_list) {
+               &set_flag(\$pr_flags, $pr_flag_pos_white_list);
+       }
+
+       if (exists($driver_hard_code_list{$compat}) ||
+           (exists($driver_config_hard_code_list{$driver}) &&
+            ($driver ne "no_driver"))) {
+               &set_flag(\$pr_flags, $pr_flag_pos_hard_coded);
+       }
+
+       my @configs = split(' && ', $config);
+       for $configs (@configs) {
+               $not = $configs =~ /^!/;
+               $configs =~ s/^!//;
+
+               if (($configs ne "no_config") && ($configs ne "no_makefile")) {
+                       &set_flag(\$pr_flags, $pr_flag_pos_config);
+               }
+
+               if (($config_cnt >= 1) &&
+                   ($configs !~ /CONFIG_/) &&
+                   (($configs ne "no_config") && ($configs ne "no_makefile"))) {
+                       &set_flag(\$pr_flags, $pr_flag_pos_config_hard_coded);
+               }
+
+               my $existing_config = $existing_config{$configs};
+               if ($existing_config eq "m") {
+                       &set_flag(\$pr_flags, $pr_flag_pos_config_m);
+                       # Possible fail, depends on whether built in or
+                       # module is desired.
+                       &set_flag(\$pr_flags, $pr_flag_pos_config_test_fail);
+               } elsif ($existing_config eq "y") {
+                       &set_flag(\$pr_flags, $pr_flag_pos_config_y);
+                       if ($not) {
+                               &set_flag(\$pr_flags, $pr_flag_pos_config_test_fail);
+                       }
+               } elsif (($config_file) && ($configs =~ /CONFIG_/)) {
+                       &set_flag(\$pr_flags, $pr_flag_pos_config_none);
+                       if (!$not) {
+                               &set_flag(\$pr_flags, $pr_flag_pos_config_test_fail);
+                       }
+               }
+       }
+
+       # ----- include / exclude filters
+
+       if ($include_flag_pattern && ($pr_flags !~ m/$include_flag_pattern/)) {
+               return 0;
+       }
+
+       if ($exclude_flag_pattern && ($pr_flags =~ m/$exclude_flag_pattern/)) {
+               return 0;
+       }
+
+       if ($config_format) {
+               print "# ";
+       }
+       print "$pr_flags : ";
+
+       return 1;
+}
+
+
+sub print_node()
+{
+       # return number of lines printed
+
+       # some fields of pn_arg_ref might not be used in this function, but
+       # extract all of them anyway.
+       my $pn_arg_ref     = shift;
+
+       my $compat         = $pn_arg_ref->{compat};
+       my $compatible_cnt = $pn_arg_ref->{compatible_cnt};
+       my $config         = $pn_arg_ref->{config};
+       my $config_cnt     = $pn_arg_ref->{config_cnt};
+       my $driver         = $pn_arg_ref->{driver};
+       my $driver_cnt     = $pn_arg_ref->{driver_cnt};
+       my $full_node      = $pn_arg_ref->{full_node};
+       my $node           = $pn_arg_ref->{node};
+       my $node_enabled   = $pn_arg_ref->{node_enabled};
+       my $white_list     = $pn_arg_ref->{white_list};
+
+       my $separator;
+
+       if (! &print_flags($pn_arg_ref)) {
+               return 0;
+       }
+
+
+       if ($short_name) {
+               print "$node";
+       } else {
+               print "$full_node";
+       }
+       print " : $compat : $driver : $config : ";
+
+       my @configs = split(' && ', $config);
+
+       if ($config_file) {
+               for $configs (@configs) {
+                       $configs =~ s/^!//;
+                       my $existing_config = $existing_config{$configs};
+                       if (!$existing_config) {
+                               # check for /-m/, /-y/, or /-objs/
+                               if ($configs !~ /CONFIG_/) {
+                                       $existing_config = "x";
+                               };
+                       };
+                       if ($existing_config) {
+                               print "$separator", "$existing_config";
+                               $separator = ", ";
+                       } else {
+                               print "$separator", "n";
+                               $separator = ", ";
+                       }
+               }
+       } else {
+               print "none";
+       }
+
+       print "\n";
+
+       if ($config_format) {
+               for $configs (@configs) {
+                       $not = $configs =~ /^!/;
+                       $configs =~ s/^!//;
+                       my $existing_config = $existing_config{$configs};
+
+                       if ($not) {
+                               if ($configs !~ /CONFIG_/) {
+                                       print "# $configs\n";
+                               } elsif ($existing_config eq "m") {
+                                       print "# $configs is m\n";
+                                       print "# $configs=n\n";
+                               } elsif ($existing_config eq "y") {
+                                       print "# $configs is set\n";
+                                       print "# $configs=n\n";
+                               } else {
+                                       print "# $configs is not set\n";
+                                       print "# $configs=n\n";
+                               }
+
+                       } else {
+                               if ($configs !~ /CONFIG_/) {
+                                       print "# $configs\n";
+                               } elsif ($existing_config eq "m") {
+                                       print "# $configs is m\n";
+                                       print "# $configs=y\n";
+                               } elsif ($existing_config eq "y") {
+                                       print "# $configs is set\n";
+                                       print "# $configs=y\n";
+                               } else {
+                                       print "# $configs is not set\n";
+                                       print "# $configs=y\n";
+                               }
+                       }
+               }
+       }
+
+       return 1;
+}
+
+
+sub scan_makefile
+{
+       my $pn_arg_ref    = shift;
+       my $driver        = shift;
+
+       # ----- Find Kconfig symbols that enable driver
+
+       my ($dir, $base) = $driver =~ m{(.*)/(.*).c};
+
+       my $makefile = $dir . "/Makefile";
+       if (! -r $makefile) {
+               $makefile = $dir . "/Kbuild";
+       }
+       if (! -r $makefile) {
+               my $config;
+
+               $config = 'no_makefile';
+               push @{ $driver_config{$driver} }, $config;
+               return;
+       }
+
+       if (!open(MAKEFILE_FILE, "<", "$makefile")) {
+               return;
+       }
+
+       my $line;
+       my @config;
+       my @if_config;
+       my @make_var;
+
+       NEXT_LINE:
+       while ($next_line = <MAKEFILE_FILE>) {
+               my $config;
+               my $if_config;
+               my $ifdef;
+               my $ifeq;
+               my $ifndef;
+               my $ifneq;
+               my $ifdef_config;
+               my $ifeq_config;
+               my $ifndef_config;
+               my $ifneq_config;
+
+               chomp($next_line);
+               $line = $line . $next_line;
+               if ($next_line =~ /\\$/) {
+                       $line =~ s/\\$/ /;
+                       next NEXT_LINE;
+               }
+               if ($line =~ /^\s*#/) {
+                       $line = "";
+                       next NEXT_LINE;
+               }
+
+               # -----  condition ... else ... endif
+
+               if ($line =~ /^([ ]\s*|)else\b/) {
+                       $if_config = "!" . pop @if_config;
+                       $if_config =~ s/^!!//;
+                       push @if_config, $if_config;
+                       $line =~ s/^([ ]\s*|)else\b//;
+               }
+
+               ($null, $ifeq_config,  $ifeq_config_val )  = $line =~ /^([ ]\s*|)ifeq\b.*\b(CONFIG_[A-Za-z0-9_]*)(.*)/;
+               ($null, $ifneq_config, $ifneq_config_val)  = $line =~ /^([ ]\s*|)ifneq\b.*\b(CONFIG_[A-Za-z0-9_]*)(.*)/;
+               ($null, $ifdef_config)                     = $line =~ /^([ ]\s*|)ifdef\b.*\b(CONFIG_[A-Za-z0-9_]*)/;
+               ($null, $ifndef_config)                    = $line =~ /^([ ]\s*|)ifndef\b.*\b(CONFIG_[A-Za-z0-9_]*)/;
+
+               ($null, $ifeq)   = $line =~ /^([ ]\s*|)ifeq\b\s*(.*)/;
+               ($null, $ifneq)  = $line =~ /^([ ]\s*|)ifneq\b\s*(.*)/;
+               ($null, $ifdef)  = $line =~ /^([ ]\s*|)ifdef\b\s*(.*)/;
+               ($null, $ifndef) = $line =~ /^([ ]\s*|)ifndef\b\s*(.*)/;
+
+               # Order of tests is important.  Prefer "CONFIG_*" regex match over
+               # less specific regex match.
+               if ($ifdef_config) {
+                       $if_config = $ifdef_config;
+               } elsif ($ifeq_config) {
+                       if ($ifeq_config_val =~ /y/) {
+                               $if_config = $ifeq_config;
+                       } else {
+                               $if_config = "!" . $ifeq_config;
+                       }
+               } elsif ($ifndef_config) {
+                       $if_config = "!" . $ifndef_config;
+               } elsif ($ifneq_config) {
+                       if ($ifneq_config_val =~ /y/) {
+                               $if_config = "!" . $ifneq_config;
+                       } else {
+                               $if_config = $ifneq_config;
+                       }
+               } elsif ($ifdef) {
+                       $if_config = $ifdef;
+               } elsif ($ifeq) {
+                       $if_config = $ifeq;
+               } elsif ($ifndef) {
+                       $if_config = "!" . $ifndef;
+               } elsif ($ifneq) {
+                       $if_config = "!" . $ifneq;
+               } else {
+                       $if_config = "";
+               }
+               $if_config =~ s/^!!//;
+
+               if ($if_config) {
+                       push @if_config, $if_config;
+                       $line = "";
+                       next NEXT_LINE;
+               }
+
+               if ($line =~ /^([ ]\s*|)endif\b/) {
+                       pop @if_config;
+                       $line = "";
+                       next NEXT_LINE;
+               }
+
+               # ----- simple CONFIG_* = *.[co]  or  xxx [+:?]*= *.[co]
+               # Most makefiles select on *.o, but
+               # arch/powerpc/boot/Makefile selects on *.c
+
+               ($config) = $line =~ /(CONFIG_[A-Za-z0-9_]+).*\b$base.[co]\b/;
+
+               # ----- match a make variable instead of *.[co]
+               # Recursively expanded variables are not handled.
+
+               if (!$config) {
+                       my $make_var;
+                       ($make_var) = $line =~ /\s*(\S+?)\s*[+:\?]*=.*\b$base.[co]\b/;
+                       if ($make_var) {
+                               if ($make_var =~ /[a-zA-Z0-9]+-[ym]/) {
+                                       $config = $make_var;
+                               } elsif ($make_var =~ /[a-zA-Z0-9]+-objs/) {
+                                       $config = $make_var;
+                               } else {
+                                       push @make_var, $make_var;
+                               }
+                       }
+               }
+
+               if (!$config) {
+                       for $make_var (@make_var) {
+                               ($config) = $line =~ /(CONFIG_[A-Za-z0-9_]+).*\b$make_var\b/;
+                               last if ($config);
+                       }
+               }
+
+               if (!$config) {
+                       for $make_var (@make_var) {
+                               ($config) = $line =~ /\s*(\S+?)\s*[+:\?]*=.*\b$make_var\b/;
+                               last if ($config);
+                       }
+               }
+
+               # ----- next if no config found
+
+               if (!$config) {
+                       $line = "";
+                       next NEXT_LINE;
+               }
+
+               for $if_config (@if_config) {
+                       $config = $if_config . " && " . $config;
+               }
+
+               push @{ $driver_config{$driver} }, $config;
+
+               $line = "";
+       }
+
+       close(MAKEFILE_FILE);
+
+}
+
+
+sub find_kconfig
+{
+       my $pn_arg_ref    = shift;
+       my $driver        = shift;
+
+       my $lines_printed = 0;
+       my @configs;
+
+       if (!@{ $driver_config{$driver} }) {
+               &scan_makefile($pn_arg_ref, $driver);
+               if (!@{ $driver_config{$driver} }) {
+                       push @{ $driver_config{$driver} }, "no_config";
+               }
+       }
+
+       @configs = @{ $driver_config{$driver} };
+
+       $$pn_arg_ref{config_cnt} = $#configs + 1;
+       for my $config (@configs) {
+               $$pn_arg_ref{config} = $config;
+               $lines_printed += &print_node($pn_arg_ref);
+       }
+
+       return $lines_printed;
+}
+
+
+sub handle_compatible()
+{
+       my $full_node     = shift;
+       my $node          = shift;
+       my $compatible    = shift;
+       my $node_enabled  = shift;
+
+       my $compat;
+       my $lines_printed = 0;
+       my %pn_arg        = ();
+
+       return if (!$node or !$compatible);
+
+       # Do not process compatible property of root node,
+       # it is used to match board, not to bind a driver.
+       return if ($node eq "/");
+
+       $pn_arg{full_node}    = $full_node;
+       $pn_arg{node}         = $node;
+       $pn_arg{node_enabled} = $node_enabled;
+
+       my @compatibles = split('", "', $compatible);
+
+       $compatibles[0] =~ s/^"//;
+       $compatibles[$#compatibles] =~ s/"$//;
+
+       $pn_arg{compatible_cnt} = $#compatibles + 1;
+
+       COMPAT:
+       for $compat (@compatibles) {
+
+               $pn_arg{compat}     = $compat;
+               $pn_arg{driver_cnt} = 0;
+               $pn_arg{white_list} = 0;
+
+               if (exists($compat_white_list{$compat})) {
+                       $pn_arg{white_list} = 1;
+                       $pn_arg{driver}     = "no_driver";
+                       $pn_arg{config_cnt} = 1;
+                       $pn_arg{config}     = "no_config";
+                       $lines_printed += &print_node(\%pn_arg);
+                       next COMPAT;
+               }
+
+               # ----- if compat previously seen, use cached info
+
+               if (exists($compat_driver{$compat})) {
+                       for my $driver (@{ $compat_driver{$compat} }) {
+                               $pn_arg{driver}     = $driver;
+                               $pn_arg{driver_cnt} = $driver_count{$compat};
+                               $pn_arg{config_cnt} = $#{ $driver_config{$driver}} + 1;
+
+                               for my $config (@{ $driver_config{$driver} }) {
+                                       $pn_arg{config} = $config;
+                                       $lines_printed += &print_node(\%pn_arg);
+                               }
+
+                               if (!@{ $driver_config{$driver} }) {
+                                       # no config cached yet
+                                       # $driver in %driver_hard_code_list
+                                       # but not %driver_config_hard_code_list
+                                       $lines_printed += &find_kconfig(\%pn_arg, $driver);
+                               }
+                       }
+                       next COMPAT;
+               }
+
+
+               # ----- Find drivers (source files that contain compatible)
+
+               # this will miss arch/sparc/include/asm/parport.h
+               # It is better to move the compatible out of the .h
+               # than to add *.h. to the files list, because *.h generates
+               # a lot of false negatives.
+               my $files = '"*.c"';
+               my $drivers = `git grep -l '"$compat"' -- $files`;
+               chomp($drivers);
+               if ($drivers eq "") {
+                       $pn_arg{driver} = "no_driver";
+                       $pn_arg{config_cnt} = 1;
+                       $pn_arg{config} = "no_config";
+                       push @{ $compat_driver{$compat} }, "no_driver";
+                       $lines_printed += &print_node(\%pn_arg);
+                       next COMPAT;
+               }
+
+               my @drivers = split("\n", $drivers);
+               $driver_count{$compat} = $#drivers + 1;
+               $pn_arg{driver_cnt}    = $#drivers + 1;
+
+               DRIVER:
+               for my $driver (@drivers) {
+                       push @{ $compat_driver{$compat} }, $driver;
+                       $pn_arg{driver} = $driver;
+
+                       # ----- if driver previously seen, use cached info
+
+                       $pn_arg{config_cnt} = $#{ $driver_config{$driver} } + 1;
+                       for my $config (@{ $driver_config{$driver} }) {
+                               $pn_arg{config} = $config;
+                               $lines_printed += &print_node(\%pn_arg);
+                       }
+                       if (@{ $driver_config{$driver} }) {
+                               next DRIVER;
+                       }
+
+                       if ($black_list_driver) {
+                               for $black (@black_list_driver) {
+                                       next DRIVER if ($driver =~ /^$black$/);
+                               }
+                       }
+
+
+                       # ----- Find Kconfig symbols that enable driver
+
+                       $lines_printed += &find_kconfig(\%pn_arg, $driver);
+
+               }
+       }
+
+       # White space (line) between nodes for readability.
+       # Each node may report several compatibles.
+       # For each compatible, multiple drivers may be reported.
+       # For each driver, multiple CONFIG_ options may be reported.
+       if ($lines_printed) {
+               print "\n";
+       }
+}
+
+sub read_dts()
+{
+       my $file         = shift;
+
+       my $compatible   = "";
+       my $line;
+       my $node         = "";
+       my $node_enabled = "";
+
+       if (! -r $file) {
+               print STDERR "file '$file' is not readable or does not exist\n";
+               exit 3;
+       }
+
+       if (!open(DT_FILE, "-|", "$dtx_diff $file")) {
+               print STDERR "\n";
+               print STDERR "shell command failed:\n";
+               print STDERR "   $dtx_diff $file\n";
+               print STDERR "\n";
+               exit 3;
+       }
+
+       FILE:
+       while ($line = <DT_FILE>) {
+               chomp($line);
+
+               if ($line =~ /{/) {
+
+                       &handle_compatible($full_node, $node, $compatible,
+                                          $node_enabled);
+
+                       while ($end_node_count-- > 0) {
+                               pop @full_node;
+                       };
+                       $end_node_count = 0;
+                       $full_node = @full_node[-1];
+
+                       $node = $line;
+                       $node =~ s/^\s*(.*)\s+\{.*/$1/;
+                       $node =~ s/.*: //;
+                       if ($node eq '/' ) {
+                               $full_node = '/';
+                       } elsif ($full_node ne '/') {
+                               $full_node = $full_node . '/' . $node;
+                       } else {
+                               $full_node = '/' . $node;
+                       }
+                       push @full_node, $full_node;
+
+                       $compatible = "";
+                       $node_enabled = "";
+                       next FILE;
+               }
+
+               if ($line =~ /}/) {
+                       $end_node_count++;
+               }
+
+               if ($line =~ /(\s+|^)status =/) {
+                       $node_enabled = $line;
+                       $node_enabled =~ s/^\t*//;
+                       $node_enabled =~ s/^status = "//;
+                       $node_enabled =~ s/";$//;
+                       next FILE;
+               }
+
+               if ($line =~ /(\s+|^)compatible =/) {
+                       # Extract all compatible entries for this device
+                       # White space matching here and in handle_compatible() is
+                       # precise, because input format is the output of dtc,
+                       # which is invoked by dtx_diff.
+                       $compatible = $line;
+                       $compatible =~ s/^\t*//;
+                       $compatible =~ s/^compatible = //;
+                       $compatible =~ s/;$//;
+               }
+       }
+
+       &handle_compatible($full_node, $node, $compatible, $node_enabled);
+
+       close(DT_FILE);
+}
+
+
+sub read_config_file()
+{
+       if (! -r $config_file) {
+               print STDERR "file '$config_file' is not readable or does not exist\n";
+               exit 2;
+       }
+
+       if (!open(CONFIG_FILE, "<", "$config_file")) {
+               print STDERR "open $config_file failed\n";
+               exit 2;
+       }
+
+       my @line;
+
+       LINE:
+       while ($line = <CONFIG_FILE>) {
+               chomp($line);
+               next LINE if ($line =~ /^\s*#/);
+               next LINE if ($line =~ /^\s*$/);
+               @line = split /=/, $line;
+               $existing_config{@line[0]} = @line[1];
+       }
+
+       close(CONFIG_FILE);
+}
+
+
+sub cmd_line_err()
+{
+       my $msg = shift;
+
+       print STDERR "\n";
+       print STDERR "   ERROR processing command line options\n";
+       print STDERR "         $msg\n" if ($msg ne "");
+       print STDERR "\n";
+       print STDERR "   For help, type '$script_name --help'\n";
+       print STDERR "\n";
+}
+
+
+# -----------------------------------------------------------------------------
+# program entry point
+
+Getopt::Long::Configure("no_ignore_case", "bundling");
+
+if (!GetOptions(
+       "c=s"               => \$config_file,
+       "config=s"          => \$config_file,
+       "config-format"     => \$config_format,
+       "exclude-flag=s"    => \@exclude_flag,
+       "h"                 => \$help,
+       "help"              => \$help,
+       "black-list-driver" => \$black_list_driver,
+       "white-list-config" => \$white_list_config,
+       "white-list-driver" => \$white_list_driver,
+       "include-flag=s"    => \@include_flag,
+       "include-suspect"   => \$include_suspect,
+       "short-name"        => \$short_name,
+       "show-lists"        => \$show_lists,
+       "version"           => \$version,
+       )) {
+
+       &cmd_line_err();
+
+       exit 1;
+}
+
+
+my $exit_after_messages = 0;
+
+if ($version) {
+       print STDERR "\n$script_name  $VUFX\n\n";
+       $exit_after_messages = 1;
+}
+
+
+if ($help) {
+       &usage;
+       $exit_after_messages = 1;
+}
+
+
+if ($show_lists) {
+
+       print "\n";
+       print "These compatibles are hard coded to have no driver.\n";
+       print "\n";
+       for my $compat (sort keys %compat_white_list) {
+               print "   $compat\n";
+       }
+
+
+       print "\n\n";
+       print "The driver for these compatibles is hard coded (white list).\n";
+       print "\n";
+       my $max_compat_len = 0;
+       for my $compat (sort keys %driver_hard_code_list) {
+               if (length $compat > $max_compat_len) {
+                       $max_compat_len = length $compat;
+               }
+       }
+       for my $compat (sort keys %driver_hard_code_list) {
+               if (($driver ne "hardcoded_no_driver") && ($driver ne "no_driver")) {
+                       my $first = 1;
+                       for my $driver (@{ $driver_hard_code_list{$compat} }) {
+                               if ($first) {
+                                       print "   $compat";
+                                       print " " x ($max_compat_len - length $compat);
+                                       $first = 0;
+                               } else {
+                                       print "   ", " " x $max_compat_len;
+                               }
+                               print "  $driver\n";
+                       }
+               }
+       }
+
+
+       print "\n\n";
+       print "The configuration option for these drivers is hard coded (white list).\n";
+       print "\n";
+       my $max_driver_len = 0;
+       for my $driver (sort keys %driver_config_hard_code_list) {
+               if (length $driver > $max_driver_len) {
+                       $max_driver_len = length $driver;
+               }
+       }
+       for my $driver (sort keys %driver_config_hard_code_list) {
+               if (($driver ne "hardcoded_no_driver") && ($driver ne "no_driver")) {
+                       my $first = 1;
+                       for my $config (@{ $driver_config_hard_code_list{$driver} }) {
+                               if ($first) {
+                                       print "   $driver";
+                                       print " " x ($max_driver_len - length $driver);
+                                       $first = 0;
+                               } else {
+                                       print "   ", " " x $max_driver_len;
+                               }
+                               print "  $config\n";
+                       }
+               }
+       }
+
+
+       print "\n\n";
+       print "These drivers are black listed.\n";
+       print "\n";
+       for my $driver (@black_list_driver) {
+               print "   $driver\n";
+       }
+
+       print "\n";
+
+       $exit_after_messages = 1;
+}
+
+
+if ($exit_after_messages) {
+       exit 0;
+}
+
+
+$exclude_flag_pattern = "[";
+for my $exclude_flag (@exclude_flag) {
+       $exclude_flag_pattern = $exclude_flag_pattern . $exclude_flag;
+}
+$exclude_flag_pattern = $exclude_flag_pattern . "]";
+# clean up if empty
+$exclude_flag_pattern =~ s/^\[\]$//;
+
+
+$include_flag_pattern = "[";
+for my $include_flag (@include_flag) {
+       $include_flag_pattern = $include_flag_pattern . $include_flag;
+}
+$include_flag_pattern = $include_flag_pattern . "]";
+# clean up if empty
+$include_flag_pattern =~ s/^\[\]$//;
+
+
+if ($exclude_flag_pattern) {
+       my $found = 0;
+       for $pr_flag_value (@pr_flag_value) {
+               if ($exclude_flag_pattern =~ m/$pr_flag_value/) {
+                       $found = 1;
+               }
+       }
+       if (!$found) {
+               &cmd_line_err("invalid value for FLAG in --exclude-flag\n");
+               exit 1
+       }
+}
+
+if ($include_flag_pattern) {
+       my $found = 0;
+       for $pr_flag_value (@pr_flag_value) {
+               if ($include_flag_pattern =~ m/$pr_flag_value/) {
+                       $found = 1;
+               }
+       }
+       if (!$found) {
+               &cmd_line_err("invalid value for FLAG in --include-flag\n");
+               exit 1
+       }
+}
+
+if ($include_suspect) {
+       $include_flag_pattern =~ s/\[//;
+       $include_flag_pattern =~ s/\]//;
+       $include_flag_pattern = "[" . $include_flag_pattern . "A-Z]";
+}
+
+if ($exclude_flag_pattern =~ m/$include_flag_pattern/) {
+       &cmd_line_err("the same flag appears in both --exclude-flag and --include-flag or --include-suspect\n");
+       exit 1
+}
+
+
+# ($#ARGV < 0) is valid for --help, --version
+if ($#ARGV < 0) {
+       &cmd_line_err("device-tree... is required");
+       exit 1
+}
+
+
+if ($config_file) {
+       &read_config_file();
+}
+
+
+# avoid pushing duplicates for this value
+$driver = "hardcoded_no_driver";
+for $config ( @{ $driver_config_hard_code_list{$driver} } ) {
+       push @{ $driver_config{$driver} }, $config;
+}
+
+if ($white_list_driver) {
+       for my $compat (keys %driver_hard_code_list) {
+               for my $driver (@{ $driver_hard_code_list{$compat} }) {
+                       push @{ $compat_driver{$compat} }, $driver;
+                       if ($driver ne "hardcoded_no_driver") {
+                               $driver_count{$compat} = scalar @{ $compat_driver{$compat} };
+                       }
+               }
+       }
+}
+
+if ($white_list_config) {
+       for my $driver (keys %driver_config_hard_code_list) {
+               if ($driver ne "hardcoded_no_driver") {
+                       for $config ( @{ $driver_config_hard_code_list{$driver} } ) {
+                               push @{ $driver_config{$driver} }, $config;
+                       }
+               }
+       }
+}
+
+if (-x "scripts/dtc/dtx_diff") {
+       $dtx_diff = "scripts/dtc/dtx_diff";
+} else {
+
+       print STDERR "\n";
+       print STDERR "$script_name must be run from the root directory of a Linux kernel tree\n";
+       print STDERR "\n";
+       exit 3;
+}
+
+for $file (@ARGV) {
+       &read_dts($file);
+}
index 0ee1caf..c600603 100644 (file)
@@ -73,24 +73,32 @@ static void lexical_error(const char *fmt, ...);
                }
 
 <*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)? {
-                       char *line, *tmp, *fn;
+                       char *line, *fnstart, *fnend;
+                       struct data fn;
                        /* skip text before line # */
                        line = yytext;
                        while (!isdigit((unsigned char)*line))
                                line++;
-                       /* skip digits in line # */
-                       tmp = line;
-                       while (!isspace((unsigned char)*tmp))
-                               tmp++;
-                       /* "NULL"-terminate line # */
-                       *tmp = '\0';
-                       /* start of filename */
-                       fn = strchr(tmp + 1, '"') + 1;
-                       /* strip trailing " from filename */
-                       tmp = strchr(fn, '"');
-                       *tmp = 0;
+
+                       /* regexp ensures that first and list "
+                        * in the whole yytext are those at
+                        * beginning and end of the filename string */
+                       fnstart = memchr(yytext, '"', yyleng);
+                       for (fnend = yytext + yyleng - 1;
+                            *fnend != '"'; fnend--)
+                               ;
+                       assert(fnstart && fnend && (fnend > fnstart));
+
+                       fn = data_copy_escape_string(fnstart + 1,
+                                                    fnend - fnstart - 1);
+
+                       /* Don't allow nuls in filenames */
+                       if (memchr(fn.val, '\0', fn.len - 1))
+                               lexical_error("nul in line number directive");
+
                        /* -1 since #line is the number of the next line */
-                       srcpos_set_line(xstrdup(fn), atoi(line) - 1);
+                       srcpos_set_line(xstrdup(fn.val), atoi(line) - 1);
+                       data_free(fn);
                }
 
 <*><<EOF>>             {
@@ -113,6 +121,11 @@ static void lexical_error(const char *fmt, ...);
                        return DT_V1;
                }
 
+<*>"/plugin/"  {
+                       DPRINT("Keyword: /plugin/\n");
+                       return DT_PLUGIN;
+               }
+
 <*>"/memreserve/"      {
                        DPRINT("Keyword: /memreserve/\n");
                        BEGIN_DEFAULT();
@@ -153,7 +166,10 @@ static void lexical_error(const char *fmt, ...);
                        errno = 0;
                        yylval.integer = strtoull(yytext, &e, 0);
 
-                       assert(!(*e) || !e[strspn(e, "UL")]);
+                       if (*e && e[strspn(e, "UL")]) {
+                               lexical_error("Bad integer literal '%s'",
+                                             yytext);
+                       }
 
                        if (errno == ERANGE)
                                lexical_error("Integer literal '%s' out of range",
@@ -173,16 +189,16 @@ static void lexical_error(const char *fmt, ...);
                        if (d.len == 1) {
                                lexical_error("Empty character literal");
                                yylval.integer = 0;
-                               return DT_CHAR_LITERAL;
-                       }
+                       } else {
+                               yylval.integer = (unsigned char)d.val[0];
 
-                       yylval.integer = (unsigned char)d.val[0];
-
-                       if (d.len > 2)
-                               lexical_error("Character literal has %d"
-                                             " characters instead of 1",
-                                             d.len - 1);
+                               if (d.len > 2)
+                                       lexical_error("Character literal has %d"
+                                                     " characters instead of 1",
+                                                     d.len - 1);
+                       }
 
+                       data_free(d);
                        return DT_CHAR_LITERAL;
                }
 
index 11cd78e..2c862bc 100644 (file)
@@ -8,8 +8,8 @@
 
 #define FLEX_SCANNER
 #define YY_FLEX_MAJOR_VERSION 2
-#define YY_FLEX_MINOR_VERSION 5
-#define YY_FLEX_SUBMINOR_VERSION 39
+#define YY_FLEX_MINOR_VERSION 6
+#define YY_FLEX_SUBMINOR_VERSION 1
 #if YY_FLEX_SUBMINOR_VERSION > 0
 #define FLEX_BETA
 #endif
@@ -88,25 +88,13 @@ typedef unsigned int flex_uint32_t;
 
 #endif /* ! FLEXINT_H */
 
-#ifdef __cplusplus
-
-/* The "const" storage-class-modifier is valid. */
-#define YY_USE_CONST
-
-#else  /* ! __cplusplus */
-
-/* C99 requires __STDC__ to be defined as 1. */
-#if defined (__STDC__)
-
-#define YY_USE_CONST
-
-#endif /* defined (__STDC__) */
-#endif /* ! __cplusplus */
-
-#ifdef YY_USE_CONST
+/* TODO: this is always defined, so inline it */
 #define yyconst const
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define yynoreturn __attribute__((__noreturn__))
 #else
-#define yyconst
+#define yynoreturn
 #endif
 
 /* Returned upon end-of-file. */
@@ -167,7 +155,7 @@ typedef struct yy_buffer_state *YY_BUFFER_STATE;
 typedef size_t yy_size_t;
 #endif
 
-extern yy_size_t yyleng;
+extern int yyleng;
 
 extern FILE *yyin, *yyout;
 
@@ -206,12 +194,12 @@ struct yy_buffer_state
        /* Size of input buffer in bytes, not including room for EOB
         * characters.
         */
-       yy_size_t yy_buf_size;
+       int yy_buf_size;
 
        /* Number of characters read into yy_ch_buf, not including EOB
         * characters.
         */
-       yy_size_t yy_n_chars;
+       int yy_n_chars;
 
        /* Whether we "own" the buffer - i.e., we know we created it,
         * and can realloc() it to grow it, and should free() it to
@@ -234,7 +222,7 @@ struct yy_buffer_state
 
     int yy_bs_lineno; /**< The line count. */
     int yy_bs_column; /**< The column count. */
-    
+
        /* Whether to try to fill the input buffer when we reach the
         * end of it.
         */
@@ -262,7 +250,7 @@ struct yy_buffer_state
 /* Stack of input buffers. */
 static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
 static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
-static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+static YY_BUFFER_STATE * yy_buffer_stack = NULL; /**< Stack as an array. */
 
 /* We provide macros for accessing buffer states in case in the
  * future we want to put the buffer states in a more general
@@ -281,11 +269,11 @@ static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
 
 /* yy_hold_char holds the character lost when yytext is formed. */
 static char yy_hold_char;
-static yy_size_t yy_n_chars;           /* number of characters read into yy_ch_buf */
-yy_size_t yyleng;
+static int yy_n_chars;         /* number of characters read into yy_ch_buf */
+int yyleng;
 
 /* Points to current character in buffer. */
-static char *yy_c_buf_p = (char *) 0;
+static char *yy_c_buf_p = NULL;
 static int yy_init = 0;                /* whether we need to initialize */
 static int yy_start = 0;       /* start state number */
 
@@ -310,7 +298,7 @@ static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file  );
 
 YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size  );
 YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str  );
-YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len  );
+YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len  );
 
 void *yyalloc (yy_size_t  );
 void *yyrealloc (void *,yy_size_t  );
@@ -342,12 +330,12 @@ void yyfree (void *  );
 
 /* Begin user sect3 */
 
-#define yywrap() 1
+#define yywrap() (/*CONSTCOND*/1)
 #define YY_SKIP_YYWRAP
 
 typedef unsigned char YY_CHAR;
 
-FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+FILE *yyin = NULL, *yyout = NULL;
 
 typedef int yy_state_type;
 
@@ -356,25 +344,28 @@ extern int yylineno;
 int yylineno = 1;
 
 extern char *yytext;
+#ifdef yytext_ptr
+#undef yytext_ptr
+#endif
 #define yytext_ptr yytext
 
 static yy_state_type yy_get_previous_state (void );
 static yy_state_type yy_try_NUL_trans (yy_state_type current_state  );
 static int yy_get_next_buffer (void );
-static void yy_fatal_error (yyconst char msg[]  );
+static void yynoreturn yy_fatal_error (yyconst char* msg  );
 
 /* Done after the current pattern has been matched and before the
  * corresponding action - sets up yytext.
  */
 #define YY_DO_BEFORE_ACTION \
        (yytext_ptr) = yy_bp; \
-       yyleng = (size_t) (yy_cp - yy_bp); \
+       yyleng = (int) (yy_cp - yy_bp); \
        (yy_hold_char) = *yy_cp; \
        *yy_cp = '\0'; \
        (yy_c_buf_p) = yy_cp;
 
-#define YY_NUM_RULES 30
-#define YY_END_OF_BUFFER 31
+#define YY_NUM_RULES 31
+#define YY_END_OF_BUFFER 32
 /* This struct is not used in this scanner,
    but its presence is necessary. */
 struct yy_trans_info
@@ -382,28 +373,29 @@ struct yy_trans_info
        flex_int32_t yy_verify;
        flex_int32_t yy_nxt;
        };
-static yyconst flex_int16_t yy_accept[159] =
+static yyconst flex_int16_t yy_accept[166] =
     {   0,
-        0,    0,    0,    0,    0,    0,    0,    0,   31,   29,
-       18,   18,   29,   29,   29,   29,   29,   29,   29,   29,
-       29,   29,   29,   29,   29,   29,   15,   16,   16,   29,
-       16,   10,   10,   18,   26,    0,    3,    0,   27,   12,
-        0,    0,   11,    0,    0,    0,    0,    0,    0,    0,
-       21,   23,   25,   24,   22,    0,    9,   28,    0,    0,
-        0,   14,   14,   16,   16,   16,   10,   10,   10,    0,
-       12,    0,   11,    0,    0,    0,   20,    0,    0,    0,
-        0,    0,    0,    0,    0,   16,   10,   10,   10,    0,
-       13,   19,    0,    0,    0,    0,    0,    0,    0,    0,
-
-        0,   16,    0,    0,    0,    0,    0,    0,    0,    0,
-        0,   16,    6,    0,    0,    0,    0,    0,    0,    2,
-        0,    0,    0,    0,    0,    0,    0,    0,    4,   17,
-        0,    0,    2,    0,    0,    0,    0,    0,    0,    0,
-        0,    0,    0,    0,    0,    1,    0,    0,    0,    0,
-        5,    8,    0,    0,    0,    0,    7,    0
+        0,    0,    0,    0,    0,    0,    0,    0,   32,   30,
+       19,   19,   30,   30,   30,   30,   30,   30,   30,   30,
+       30,   30,   30,   30,   30,   30,   16,   17,   17,   30,
+       17,   11,   11,   19,   27,    0,    3,    0,   28,   13,
+        0,    0,   12,    0,    0,    0,    0,    0,    0,    0,
+        0,   22,   24,   26,   25,   23,    0,   10,   29,    0,
+        0,    0,   15,   15,   17,   17,   17,   11,   11,   11,
+        0,   13,    0,   12,    0,    0,    0,   21,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,   17,   11,   11,
+       11,    0,   14,   20,    0,    0,    0,    0,    0,    0,
+
+        0,    0,    0,    0,   17,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,   17,    7,    0,    0,    0,
+        0,    0,    0,    0,    2,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    4,   18,    0,    0,    5,    2,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    1,    0,    0,    0,    0,    6,    9,    0,
+        0,    0,    0,    8,    0
     } ;
 
-static yyconst flex_int32_t yy_ec[256] =
+static yyconst YY_CHAR yy_ec[256] =
     {   0,
         1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
         4,    4,    4,    1,    1,    1,    1,    1,    1,    1,
@@ -416,9 +408,9 @@ static yyconst flex_int32_t yy_ec[256] =
        22,   22,   22,   22,   24,   22,   22,   25,   22,   22,
         1,   26,   27,    1,   22,    1,   21,   28,   29,   30,
 
-       31,   21,   22,   22,   32,   22,   22,   33,   34,   35,
-       36,   37,   22,   38,   39,   40,   41,   42,   22,   25,
-       43,   22,   44,   45,   46,    1,    1,    1,    1,    1,
+       31,   21,   32,   22,   33,   22,   22,   34,   35,   36,
+       37,   38,   22,   39,   40,   41,   42,   43,   22,   25,
+       44,   22,   45,   46,   47,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
@@ -435,163 +427,165 @@ static yyconst flex_int32_t yy_ec[256] =
         1,    1,    1,    1,    1
     } ;
 
-static yyconst flex_int32_t yy_meta[47] =
+static yyconst YY_CHAR yy_meta[48] =
     {   0,
         1,    1,    1,    1,    1,    1,    2,    3,    1,    2,
         2,    2,    4,    5,    5,    5,    6,    1,    1,    1,
         7,    8,    8,    8,    8,    1,    1,    7,    7,    7,
         7,    8,    8,    8,    8,    8,    8,    8,    8,    8,
-        8,    8,    8,    3,    1,    4
+        8,    8,    8,    8,    3,    1,    4
     } ;
 
-static yyconst flex_int16_t yy_base[173] =
+static yyconst flex_uint16_t yy_base[180] =
     {   0,
-        0,  383,   34,  382,   65,  381,   37,  105,  387,  391,
-       54,  111,  367,  110,  109,  109,  112,   41,  366,  104,
-      367,  338,  124,  117,    0,  144,  391,    0,  121,    0,
-      135,  155,  140,  179,  391,  160,  391,  379,  391,    0,
-      368,  141,  391,  167,  370,  376,  346,  103,  342,  345,
-      391,  391,  391,  391,  391,  358,  391,  391,  175,  342,
-      338,  391,  355,    0,  185,  339,  184,  347,  346,    0,
-        0,  322,  175,  357,  175,  363,  352,  324,  330,  323,
-      332,  326,  201,  324,  329,  322,  391,  333,  181,  309,
-      391,  341,  340,  313,  320,  338,  178,  311,  146,  317,
-
-      314,  315,  335,  331,  303,  300,  309,  299,  308,  188,
-      336,  335,  391,  305,  320,  281,  283,  271,  203,  288,
-      281,  271,  266,  264,  245,  242,  208,  104,  391,  391,
-      244,  218,  204,  219,  206,  224,  201,  212,  204,  229,
-      215,  208,  207,  200,  219,  391,  233,  221,  200,  181,
-      391,  391,  149,  122,   86,   41,  391,  391,  245,  251,
-      259,  263,  267,  273,  280,  284,  292,  300,  304,  310,
-      318,  326
+        0,  393,   35,  392,   66,  391,   38,  107,  397,  401,
+       55,  113,  377,  112,  111,  111,  114,   42,  376,  106,
+      377,  347,  126,  120,    0,  147,  401,    0,  124,    0,
+      137,  158,  170,  163,  401,  153,  401,  389,  401,    0,
+      378,  120,  401,  131,  380,  386,  355,  139,  351,  355,
+      351,  401,  401,  401,  401,  401,  367,  401,  401,  185,
+      350,  346,  401,  364,    0,  185,  347,  189,  356,  355,
+        0,    0,  330,  180,  366,  141,  372,  361,  332,  338,
+      331,  341,  334,  326,  205,  331,  337,  329,  401,  341,
+      167,  316,  401,  349,  348,  320,  328,  346,  180,  318,
+
+      324,  209,  324,  320,  322,  342,  338,  309,  306,  315,
+      305,  315,  312,  192,  342,  341,  401,  293,  306,  282,
+      268,  252,  255,  203,  285,  282,  272,  268,  252,  233,
+      232,  239,  208,  107,  401,  401,  238,  211,  401,  211,
+      212,  208,  228,  203,  215,  207,  233,  222,  212,  211,
+      203,  227,  401,  237,  225,  204,  185,  401,  401,  149,
+      128,   88,   42,  401,  401,  253,  259,  267,  271,  275,
+      281,  288,  292,  300,  308,  312,  318,  326,  334
     } ;
 
-static yyconst flex_int16_t yy_def[173] =
+static yyconst flex_int16_t yy_def[180] =
     {   0,
-      158,    1,    1,    3,  158,    5,    1,    1,  158,  158,
-      158,  158,  158,  159,  160,  161,  158,  158,  158,  158,
-      162,  158,  158,  158,  163,  162,  158,  164,  165,  164,
-      164,  158,  158,  158,  158,  159,  158,  159,  158,  166,
-      158,  161,  158,  161,  167,  168,  158,  158,  158,  158,
-      158,  158,  158,  158,  158,  162,  158,  158,  158,  158,
-      158,  158,  162,  164,  165,  164,  158,  158,  158,  169,
-      166,  170,  161,  167,  167,  168,  158,  158,  158,  158,
-      158,  158,  158,  158,  158,  164,  158,  158,  169,  170,
-      158,  158,  158,  158,  158,  158,  158,  158,  158,  158,
-
-      158,  164,  158,  158,  158,  158,  158,  158,  158,  171,
-      158,  164,  158,  158,  158,  158,  158,  158,  171,  158,
-      171,  158,  158,  158,  158,  158,  158,  158,  158,  158,
-      158,  158,  158,  158,  158,  158,  158,  158,  158,  158,
-      172,  158,  158,  158,  172,  158,  172,  158,  158,  158,
-      158,  158,  158,  158,  158,  158,  158,    0,  158,  158,
-      158,  158,  158,  158,  158,  158,  158,  158,  158,  158,
-      158,  158
+      165,    1,    1,    3,  165,    5,    1,    1,  165,  165,
+      165,  165,  165,  166,  167,  168,  165,  165,  165,  165,
+      169,  165,  165,  165,  170,  169,  165,  171,  172,  171,
+      171,  165,  165,  165,  165,  166,  165,  166,  165,  173,
+      165,  168,  165,  168,  174,  175,  165,  165,  165,  165,
+      165,  165,  165,  165,  165,  165,  169,  165,  165,  165,
+      165,  165,  165,  169,  171,  172,  171,  165,  165,  165,
+      176,  173,  177,  168,  174,  174,  175,  165,  165,  165,
+      165,  165,  165,  165,  165,  165,  165,  171,  165,  165,
+      176,  177,  165,  165,  165,  165,  165,  165,  165,  165,
+
+      165,  165,  165,  165,  171,  165,  165,  165,  165,  165,
+      165,  165,  165,  178,  165,  171,  165,  165,  165,  165,
+      165,  165,  165,  178,  165,  178,  165,  165,  165,  165,
+      165,  165,  165,  165,  165,  165,  165,  165,  165,  165,
+      165,  165,  165,  165,  165,  165,  165,  179,  165,  165,
+      165,  179,  165,  179,  165,  165,  165,  165,  165,  165,
+      165,  165,  165,  165,    0,  165,  165,  165,  165,  165,
+      165,  165,  165,  165,  165,  165,  165,  165,  165
     } ;
 
-static yyconst flex_int16_t yy_nxt[438] =
+static yyconst flex_uint16_t yy_nxt[449] =
     {   0,
        10,   11,   12,   11,   13,   14,   10,   15,   16,   10,
        10,   10,   17,   10,   10,   10,   10,   18,   19,   20,
        21,   21,   21,   21,   21,   10,   10,   21,   21,   21,
        21,   21,   21,   21,   21,   21,   21,   21,   21,   21,
-       21,   21,   21,   10,   22,   10,   24,   25,   25,   25,
-       32,   33,   33,  157,   26,   34,   34,   34,   51,   52,
-       27,   26,   26,   26,   26,   10,   11,   12,   11,   13,
-       14,   28,   15,   16,   28,   28,   28,   24,   28,   28,
-       28,   10,   18,   19,   20,   29,   29,   29,   29,   29,
-       30,   10,   29,   29,   29,   29,   29,   29,   29,   29,
-
-       29,   29,   29,   29,   29,   29,   29,   29,   10,   22,
-       10,   23,   34,   34,   34,   37,   39,   43,   32,   33,
-       33,   45,   54,   55,   46,   59,   45,   64,  156,   46,
-       64,   64,   64,   79,   44,   38,   59,   57,  134,   47,
-      135,   48,   80,   49,   47,   50,   48,   99,   61,   43,
-       50,  110,   41,   67,   67,   67,   60,   63,   63,   63,
-       57,  155,   68,   69,   63,   37,   44,   66,   67,   67,
-       67,   63,   63,   63,   63,   73,   59,   68,   69,   70,
-       34,   34,   34,   43,   75,   38,  154,   92,   83,   83,
-       83,   64,   44,  120,   64,   64,   64,   67,   67,   67,
-
-       44,   57,   99,   68,   69,  107,   68,   69,  120,  127,
-      108,  153,  152,  121,   83,   83,   83,  133,  133,  133,
-      146,  133,  133,  133,  146,  140,  140,  140,  121,  141,
-      140,  140,  140,  151,  141,  158,  150,  149,  148,  144,
-      147,  143,  142,  139,  147,   36,   36,   36,   36,   36,
-       36,   36,   36,   40,  138,  137,  136,   40,   40,   42,
-       42,   42,   42,   42,   42,   42,   42,   56,   56,   56,
-       56,   62,  132,   62,   64,  131,  130,   64,  129,   64,
-       64,   65,  128,  158,   65,   65,   65,   65,   71,  127,
-       71,   71,   74,   74,   74,   74,   74,   74,   74,   74,
-
-       76,   76,   76,   76,   76,   76,   76,   76,   89,  126,
-       89,   90,  125,   90,   90,  124,   90,   90,  119,  119,
-      119,  119,  119,  119,  119,  119,  145,  145,  145,  145,
-      145,  145,  145,  145,  123,  122,   59,   59,  118,  117,
-      116,  115,  114,  113,   45,  112,  108,  111,  109,  106,
-      105,  104,   46,  103,   91,   87,  102,  101,  100,   98,
-       97,   96,   95,   94,   93,   77,   75,   91,   88,   87,
-       86,   57,   85,   84,   57,   82,   81,   78,   77,   75,
-       72,  158,   58,   57,   53,   35,  158,   31,   23,   23,
-        9,  158,  158,  158,  158,  158,  158,  158,  158,  158,
-
-      158,  158,  158,  158,  158,  158,  158,  158,  158,  158,
-      158,  158,  158,  158,  158,  158,  158,  158,  158,  158,
-      158,  158,  158,  158,  158,  158,  158,  158,  158,  158,
-      158,  158,  158,  158,  158,  158,  158
+       21,   21,   21,   21,   10,   22,   10,   24,   25,   25,
+       25,   32,   33,   33,  164,   26,   34,   34,   34,   52,
+       53,   27,   26,   26,   26,   26,   10,   11,   12,   11,
+       13,   14,   28,   15,   16,   28,   28,   28,   24,   28,
+       28,   28,   10,   18,   19,   20,   29,   29,   29,   29,
+       29,   30,   10,   29,   29,   29,   29,   29,   29,   29,
+
+       29,   29,   29,   29,   29,   29,   29,   29,   29,   29,
+       10,   22,   10,   23,   34,   34,   34,   37,   39,   43,
+       32,   33,   33,   45,   55,   56,   46,   60,   43,   45,
+       65,  163,   46,   65,   65,   65,   44,   38,   60,   74,
+       58,   47,  141,   48,  142,   44,   49,   47,   50,   48,
+       76,   51,   62,   94,   50,   41,   44,   51,   37,   61,
+       64,   64,   64,   58,   34,   34,   34,   64,  162,   80,
+       67,   68,   68,   68,   64,   64,   64,   64,   38,   81,
+       69,   70,   71,   68,   68,   68,   60,  161,   43,   69,
+       70,   65,   69,   70,   65,   65,   65,  125,   85,   85,
+
+       85,   58,   68,   68,   68,   44,  102,  110,  125,  133,
+      102,   69,   70,  111,  114,  160,  159,  126,   85,   85,
+       85,  140,  140,  140,  140,  140,  140,  153,  126,  147,
+      147,  147,  153,  148,  147,  147,  147,  158,  148,  165,
+      157,  156,  155,  151,  150,  149,  146,  154,  145,  144,
+      143,  139,  154,   36,   36,   36,   36,   36,   36,   36,
+       36,   40,  138,  137,  136,   40,   40,   42,   42,   42,
+       42,   42,   42,   42,   42,   57,   57,   57,   57,   63,
+      135,   63,   65,  134,  165,   65,  133,   65,   65,   66,
+      132,  131,   66,   66,   66,   66,   72,  130,   72,   72,
+
+       75,   75,   75,   75,   75,   75,   75,   75,   77,   77,
+       77,   77,   77,   77,   77,   77,   91,  129,   91,   92,
+      128,   92,   92,  127,   92,   92,  124,  124,  124,  124,
+      124,  124,  124,  124,  152,  152,  152,  152,  152,  152,
+      152,  152,   60,   60,  123,  122,  121,  120,  119,  118,
+      117,   45,  116,  111,  115,  113,  112,  109,  108,  107,
+       46,  106,   93,   89,  105,  104,  103,  101,  100,   99,
+       98,   97,   96,   95,   78,   76,   93,   90,   89,   88,
+       58,   87,   86,   58,   84,   83,   82,   79,   78,   76,
+       73,  165,   59,   58,   54,   35,  165,   31,   23,   23,
+
+        9,  165,  165,  165,  165,  165,  165,  165,  165,  165,
+      165,  165,  165,  165,  165,  165,  165,  165,  165,  165,
+      165,  165,  165,  165,  165,  165,  165,  165,  165,  165,
+      165,  165,  165,  165,  165,  165,  165,  165,  165,  165,
+      165,  165,  165,  165,  165,  165,  165,  165
     } ;
 
-static yyconst flex_int16_t yy_chk[438] =
+static yyconst flex_int16_t yy_chk[449] =
     {   0,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    3,    3,    3,    3,
-        7,    7,    7,  156,    3,   11,   11,   11,   18,   18,
-        3,    3,    3,    3,    3,    5,    5,    5,    5,    5,
+        1,    1,    1,    1,    1,    1,    1,    3,    3,    3,
+        3,    7,    7,    7,  163,    3,   11,   11,   11,   18,
+       18,    3,    3,    3,    3,    3,    5,    5,    5,    5,
         5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
         5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
         5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
 
         5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
-        5,    8,   12,   12,   12,   14,   15,   16,    8,    8,
-        8,   17,   20,   20,   17,   23,   24,   29,  155,   24,
-       29,   29,   29,   48,   16,   14,   31,   29,  128,   17,
-      128,   17,   48,   17,   24,   17,   24,   99,   24,   42,
-       24,   99,   15,   33,   33,   33,   23,   26,   26,   26,
-       26,  154,   33,   33,   26,   36,   42,   31,   32,   32,
-       32,   26,   26,   26,   26,   44,   59,   32,   32,   32,
-       34,   34,   34,   73,   75,   36,  153,   75,   59,   59,
-       59,   65,   44,  110,   65,   65,   65,   67,   67,   67,
-
-       73,   65,   83,   89,   89,   97,   67,   67,  119,  127,
-       97,  150,  149,  110,   83,   83,   83,  133,  133,  133,
-      141,  127,  127,  127,  145,  136,  136,  136,  119,  136,
-      140,  140,  140,  148,  140,  147,  144,  143,  142,  139,
-      141,  138,  137,  135,  145,  159,  159,  159,  159,  159,
-      159,  159,  159,  160,  134,  132,  131,  160,  160,  161,
-      161,  161,  161,  161,  161,  161,  161,  162,  162,  162,
-      162,  163,  126,  163,  164,  125,  124,  164,  123,  164,
-      164,  165,  122,  121,  165,  165,  165,  165,  166,  120,
-      166,  166,  167,  167,  167,  167,  167,  167,  167,  167,
-
-      168,  168,  168,  168,  168,  168,  168,  168,  169,  118,
-      169,  170,  117,  170,  170,  116,  170,  170,  171,  171,
-      171,  171,  171,  171,  171,  171,  172,  172,  172,  172,
-      172,  172,  172,  172,  115,  114,  112,  111,  109,  108,
-      107,  106,  105,  104,  103,  102,  101,  100,   98,   96,
-       95,   94,   93,   92,   90,   88,   86,   85,   84,   82,
-       81,   80,   79,   78,   77,   76,   74,   72,   69,   68,
-       66,   63,   61,   60,   56,   50,   49,   47,   46,   45,
+        5,    5,    5,    8,   12,   12,   12,   14,   15,   16,
+        8,    8,    8,   17,   20,   20,   17,   23,   42,   24,
+       29,  162,   24,   29,   29,   29,   16,   14,   31,   44,
+       29,   17,  134,   17,  134,   42,   17,   24,   17,   24,
+       76,   17,   24,   76,   24,   15,   44,   24,   36,   23,
+       26,   26,   26,   26,   34,   34,   34,   26,  161,   48,
+       31,   32,   32,   32,   26,   26,   26,   26,   36,   48,
+       32,   32,   32,   33,   33,   33,   60,  160,   74,   91,
+       91,   66,   33,   33,   66,   66,   66,  114,   60,   60,
+
+       60,   66,   68,   68,   68,   74,   85,   99,  124,  133,
+      102,   68,   68,   99,  102,  157,  156,  114,   85,   85,
+       85,  133,  133,  133,  140,  140,  140,  148,  124,  143,
+      143,  143,  152,  143,  147,  147,  147,  155,  147,  154,
+      151,  150,  149,  146,  145,  144,  142,  148,  141,  138,
+      137,  132,  152,  166,  166,  166,  166,  166,  166,  166,
+      166,  167,  131,  130,  129,  167,  167,  168,  168,  168,
+      168,  168,  168,  168,  168,  169,  169,  169,  169,  170,
+      128,  170,  171,  127,  126,  171,  125,  171,  171,  172,
+      123,  122,  172,  172,  172,  172,  173,  121,  173,  173,
+
+      174,  174,  174,  174,  174,  174,  174,  174,  175,  175,
+      175,  175,  175,  175,  175,  175,  176,  120,  176,  177,
+      119,  177,  177,  118,  177,  177,  178,  178,  178,  178,
+      178,  178,  178,  178,  179,  179,  179,  179,  179,  179,
+      179,  179,  116,  115,  113,  112,  111,  110,  109,  108,
+      107,  106,  105,  104,  103,  101,  100,   98,   97,   96,
+       95,   94,   92,   90,   88,   87,   86,   84,   83,   82,
+       81,   80,   79,   78,   77,   75,   73,   70,   69,   67,
+       64,   62,   61,   57,   51,   50,   49,   47,   46,   45,
        41,   38,   22,   21,   19,   13,    9,    6,    4,    2,
-      158,  158,  158,  158,  158,  158,  158,  158,  158,  158,
 
-      158,  158,  158,  158,  158,  158,  158,  158,  158,  158,
-      158,  158,  158,  158,  158,  158,  158,  158,  158,  158,
-      158,  158,  158,  158,  158,  158,  158,  158,  158,  158,
-      158,  158,  158,  158,  158,  158,  158
+      165,  165,  165,  165,  165,  165,  165,  165,  165,  165,
+      165,  165,  165,  165,  165,  165,  165,  165,  165,  165,
+      165,  165,  165,  165,  165,  165,  165,  165,  165,  165,
+      165,  165,  165,  165,  165,  165,  165,  165,  165,  165,
+      165,  165,  165,  165,  165,  165,  165,  165
     } ;
 
 static yy_state_type yy_last_accepting_state;
@@ -662,7 +656,7 @@ static int dts_version = 1;
 static void push_input_file(const char *filename);
 static bool pop_input_file(void);
 static void lexical_error(const char *fmt, ...);
-#line 666 "dtc-lexer.lex.c"
+#line 660 "dtc-lexer.lex.c"
 
 #define INITIAL 0
 #define BYTESTRING 1
@@ -698,19 +692,19 @@ void yyset_extra (YY_EXTRA_TYPE user_defined  );
 
 FILE *yyget_in (void );
 
-void yyset_in  (FILE * in_str  );
+void yyset_in  (FILE * _in_str  );
 
 FILE *yyget_out (void );
 
-void yyset_out  (FILE * out_str  );
+void yyset_out  (FILE * _out_str  );
 
-yy_size_t yyget_leng (void );
+                       int yyget_leng (void );
 
 char *yyget_text (void );
 
 int yyget_lineno (void );
 
-void yyset_lineno (int line_number  );
+void yyset_lineno (int _line_number  );
 
 /* Macros after this point can all be overridden by user definitions in
  * section 1.
@@ -724,6 +718,10 @@ extern int yywrap (void );
 #endif
 #endif
 
+#ifndef YY_NO_UNPUT
+    
+#endif
+
 #ifndef yytext_ptr
 static void yy_flex_strncpy (char *,yyconst char *,int );
 #endif
@@ -757,7 +755,7 @@ static int input (void );
 /* This used to be an fputs(), but since the string might contain NUL's,
  * we now use fwrite().
  */
-#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
+#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0)
 #endif
 
 /* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
@@ -781,7 +779,7 @@ static int input (void );
        else \
                { \
                errno=0; \
-               while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+               while ( (result = (int) fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
                        { \
                        if( errno != EINTR) \
                                { \
@@ -836,7 +834,7 @@ extern int yylex (void);
 
 /* Code executed at the end of each rule. */
 #ifndef YY_BREAK
-#define YY_BREAK break;
+#define YY_BREAK /*LINTED*/break;
 #endif
 
 #define YY_RULE_SETUP \
@@ -849,9 +847,9 @@ extern int yylex (void);
  */
 YY_DECL
 {
-       register yy_state_type yy_current_state;
-       register char *yy_cp, *yy_bp;
-       register int yy_act;
+       yy_state_type yy_current_state;
+       char *yy_cp, *yy_bp;
+       int yy_act;
     
        if ( !(yy_init) )
                {
@@ -882,9 +880,9 @@ YY_DECL
        {
 #line 68 "dtc-lexer.l"
 
-#line 886 "dtc-lexer.lex.c"
+#line 884 "dtc-lexer.lex.c"
 
-       while ( 1 )             /* loops until end-of-file is reached */
+       while ( /*CONSTCOND*/1 )                /* loops until end-of-file is reached */
                {
                yy_cp = (yy_c_buf_p);
 
@@ -901,7 +899,7 @@ YY_DECL
 yy_match:
                do
                        {
-                       register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
+                       YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
                        if ( yy_accept[yy_current_state] )
                                {
                                (yy_last_accepting_state) = yy_current_state;
@@ -910,13 +908,13 @@ yy_match:
                        while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
                                {
                                yy_current_state = (int) yy_def[yy_current_state];
-                               if ( yy_current_state >= 159 )
+                               if ( yy_current_state >= 166 )
                                        yy_c = yy_meta[(unsigned int) yy_c];
                                }
-                       yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+                       yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c];
                        ++yy_cp;
                        }
-               while ( yy_current_state != 158 );
+               while ( yy_current_state != 165 );
                yy_cp = (yy_last_accepting_cpos);
                yy_current_state = (yy_last_accepting_state);
 
@@ -951,31 +949,39 @@ case 2:
 YY_RULE_SETUP
 #line 75 "dtc-lexer.l"
 {
-                       char *line, *tmp, *fn;
+                       char *line, *fnstart, *fnend;
+                       struct data fn;
                        /* skip text before line # */
                        line = yytext;
                        while (!isdigit((unsigned char)*line))
                                line++;
-                       /* skip digits in line # */
-                       tmp = line;
-                       while (!isspace((unsigned char)*tmp))
-                               tmp++;
-                       /* "NULL"-terminate line # */
-                       *tmp = '\0';
-                       /* start of filename */
-                       fn = strchr(tmp + 1, '"') + 1;
-                       /* strip trailing " from filename */
-                       tmp = strchr(fn, '"');
-                       *tmp = 0;
+
+                       /* regexp ensures that first and list "
+                        * in the whole yytext are those at
+                        * beginning and end of the filename string */
+                       fnstart = memchr(yytext, '"', yyleng);
+                       for (fnend = yytext + yyleng - 1;
+                            *fnend != '"'; fnend--)
+                               ;
+                       assert(fnstart && fnend && (fnend > fnstart));
+
+                       fn = data_copy_escape_string(fnstart + 1,
+                                                    fnend - fnstart - 1);
+
+                       /* Don't allow nuls in filenames */
+                       if (memchr(fn.val, '\0', fn.len - 1))
+                               lexical_error("nul in line number directive");
+
                        /* -1 since #line is the number of the next line */
-                       srcpos_set_line(xstrdup(fn), atoi(line) - 1);
+                       srcpos_set_line(xstrdup(fn.val), atoi(line) - 1);
+                       data_free(fn);
                }
        YY_BREAK
 case YY_STATE_EOF(INITIAL):
 case YY_STATE_EOF(BYTESTRING):
 case YY_STATE_EOF(PROPNODENAME):
 case YY_STATE_EOF(V1):
-#line 96 "dtc-lexer.l"
+#line 104 "dtc-lexer.l"
 {
                        if (!pop_input_file()) {
                                yyterminate();
@@ -985,7 +991,7 @@ case YY_STATE_EOF(V1):
 case 3:
 /* rule 3 can match eol */
 YY_RULE_SETUP
-#line 102 "dtc-lexer.l"
+#line 110 "dtc-lexer.l"
 {
                        DPRINT("String: %s\n", yytext);
                        yylval.data = data_copy_escape_string(yytext+1,
@@ -995,7 +1001,7 @@ YY_RULE_SETUP
        YY_BREAK
 case 4:
 YY_RULE_SETUP
-#line 109 "dtc-lexer.l"
+#line 117 "dtc-lexer.l"
 {
                        DPRINT("Keyword: /dts-v1/\n");
                        dts_version = 1;
@@ -1005,25 +1011,33 @@ YY_RULE_SETUP
        YY_BREAK
 case 5:
 YY_RULE_SETUP
-#line 116 "dtc-lexer.l"
+#line 124 "dtc-lexer.l"
+{
+                       DPRINT("Keyword: /plugin/\n");
+                       return DT_PLUGIN;
+               }
+       YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 129 "dtc-lexer.l"
 {
                        DPRINT("Keyword: /memreserve/\n");
                        BEGIN_DEFAULT();
                        return DT_MEMRESERVE;
                }
        YY_BREAK
-case 6:
+case 7:
 YY_RULE_SETUP
-#line 122 "dtc-lexer.l"
+#line 135 "dtc-lexer.l"
 {
                        DPRINT("Keyword: /bits/\n");
                        BEGIN_DEFAULT();
                        return DT_BITS;
                }
        YY_BREAK
-case 7:
+case 8:
 YY_RULE_SETUP
-#line 128 "dtc-lexer.l"
+#line 141 "dtc-lexer.l"
 {
                        DPRINT("Keyword: /delete-property/\n");
                        DPRINT("<PROPNODENAME>\n");
@@ -1031,9 +1045,9 @@ YY_RULE_SETUP
                        return DT_DEL_PROP;
                }
        YY_BREAK
-case 8:
+case 9:
 YY_RULE_SETUP
-#line 135 "dtc-lexer.l"
+#line 148 "dtc-lexer.l"
 {
                        DPRINT("Keyword: /delete-node/\n");
                        DPRINT("<PROPNODENAME>\n");
@@ -1041,9 +1055,9 @@ YY_RULE_SETUP
                        return DT_DEL_NODE;
                }
        YY_BREAK
-case 9:
+case 10:
 YY_RULE_SETUP
-#line 142 "dtc-lexer.l"
+#line 155 "dtc-lexer.l"
 {
                        DPRINT("Label: %s\n", yytext);
                        yylval.labelref = xstrdup(yytext);
@@ -1051,9 +1065,9 @@ YY_RULE_SETUP
                        return DT_LABEL;
                }
        YY_BREAK
-case 10:
+case 11:
 YY_RULE_SETUP
-#line 149 "dtc-lexer.l"
+#line 162 "dtc-lexer.l"
 {
                        char *e;
                        DPRINT("Integer Literal: '%s'\n", yytext);
@@ -1061,7 +1075,10 @@ YY_RULE_SETUP
                        errno = 0;
                        yylval.integer = strtoull(yytext, &e, 0);
 
-                       assert(!(*e) || !e[strspn(e, "UL")]);
+                       if (*e && e[strspn(e, "UL")]) {
+                               lexical_error("Bad integer literal '%s'",
+                                             yytext);
+                       }
 
                        if (errno == ERANGE)
                                lexical_error("Integer literal '%s' out of range",
@@ -1073,10 +1090,10 @@ YY_RULE_SETUP
                        return DT_LITERAL;
                }
        YY_BREAK
-case 11:
-/* rule 11 can match eol */
+case 12:
+/* rule 12 can match eol */
 YY_RULE_SETUP
-#line 168 "dtc-lexer.l"
+#line 184 "dtc-lexer.l"
 {
                        struct data d;
                        DPRINT("Character literal: %s\n", yytext);
@@ -1085,31 +1102,31 @@ YY_RULE_SETUP
                        if (d.len == 1) {
                                lexical_error("Empty character literal");
                                yylval.integer = 0;
-                               return DT_CHAR_LITERAL;
-                       }
-
-                       yylval.integer = (unsigned char)d.val[0];
+                       } else {
+                               yylval.integer = (unsigned char)d.val[0];
 
-                       if (d.len > 2)
-                               lexical_error("Character literal has %d"
-                                             " characters instead of 1",
-                                             d.len - 1);
+                               if (d.len > 2)
+                                       lexical_error("Character literal has %d"
+                                                     " characters instead of 1",
+                                                     d.len - 1);
+                       }
 
+                       data_free(d);
                        return DT_CHAR_LITERAL;
                }
        YY_BREAK
-case 12:
+case 13:
 YY_RULE_SETUP
-#line 189 "dtc-lexer.l"
+#line 205 "dtc-lexer.l"
 {      /* label reference */
                        DPRINT("Ref: %s\n", yytext+1);
                        yylval.labelref = xstrdup(yytext+1);
                        return DT_REF;
                }
        YY_BREAK
-case 13:
+case 14:
 YY_RULE_SETUP
-#line 195 "dtc-lexer.l"
+#line 211 "dtc-lexer.l"
 {      /* new-style path reference */
                        yytext[yyleng-1] = '\0';
                        DPRINT("Ref: %s\n", yytext+2);
@@ -1117,27 +1134,27 @@ YY_RULE_SETUP
                        return DT_REF;
                }
        YY_BREAK
-case 14:
+case 15:
 YY_RULE_SETUP
-#line 202 "dtc-lexer.l"
+#line 218 "dtc-lexer.l"
 {
                        yylval.byte = strtol(yytext, NULL, 16);
                        DPRINT("Byte: %02x\n", (int)yylval.byte);
                        return DT_BYTE;
                }
        YY_BREAK
-case 15:
+case 16:
 YY_RULE_SETUP
-#line 208 "dtc-lexer.l"
+#line 224 "dtc-lexer.l"
 {
                        DPRINT("/BYTESTRING\n");
                        BEGIN_DEFAULT();
                        return ']';
                }
        YY_BREAK
-case 16:
+case 17:
 YY_RULE_SETUP
-#line 214 "dtc-lexer.l"
+#line 230 "dtc-lexer.l"
 {
                        DPRINT("PropNodeName: %s\n", yytext);
                        yylval.propnodename = xstrdup((yytext[0] == '\\') ?
@@ -1146,75 +1163,75 @@ YY_RULE_SETUP
                        return DT_PROPNODENAME;
                }
        YY_BREAK
-case 17:
+case 18:
 YY_RULE_SETUP
-#line 222 "dtc-lexer.l"
+#line 238 "dtc-lexer.l"
 {
                        DPRINT("Binary Include\n");
                        return DT_INCBIN;
                }
        YY_BREAK
-case 18:
-/* rule 18 can match eol */
-YY_RULE_SETUP
-#line 227 "dtc-lexer.l"
-/* eat whitespace */
-       YY_BREAK
 case 19:
 /* rule 19 can match eol */
 YY_RULE_SETUP
-#line 228 "dtc-lexer.l"
-/* eat C-style comments */
+#line 243 "dtc-lexer.l"
+/* eat whitespace */
        YY_BREAK
 case 20:
 /* rule 20 can match eol */
 YY_RULE_SETUP
-#line 229 "dtc-lexer.l"
-/* eat C++-style comments */
+#line 244 "dtc-lexer.l"
+/* eat C-style comments */
        YY_BREAK
 case 21:
+/* rule 21 can match eol */
 YY_RULE_SETUP
-#line 231 "dtc-lexer.l"
-{ return DT_LSHIFT; };
+#line 245 "dtc-lexer.l"
+/* eat C++-style comments */
        YY_BREAK
 case 22:
 YY_RULE_SETUP
-#line 232 "dtc-lexer.l"
-{ return DT_RSHIFT; };
+#line 247 "dtc-lexer.l"
+{ return DT_LSHIFT; };
        YY_BREAK
 case 23:
 YY_RULE_SETUP
-#line 233 "dtc-lexer.l"
-{ return DT_LE; };
+#line 248 "dtc-lexer.l"
+{ return DT_RSHIFT; };
        YY_BREAK
 case 24:
 YY_RULE_SETUP
-#line 234 "dtc-lexer.l"
-{ return DT_GE; };
+#line 249 "dtc-lexer.l"
+{ return DT_LE; };
        YY_BREAK
 case 25:
 YY_RULE_SETUP
-#line 235 "dtc-lexer.l"
-{ return DT_EQ; };
+#line 250 "dtc-lexer.l"
+{ return DT_GE; };
        YY_BREAK
 case 26:
 YY_RULE_SETUP
-#line 236 "dtc-lexer.l"
-{ return DT_NE; };
+#line 251 "dtc-lexer.l"
+{ return DT_EQ; };
        YY_BREAK
 case 27:
 YY_RULE_SETUP
-#line 237 "dtc-lexer.l"
-{ return DT_AND; };
+#line 252 "dtc-lexer.l"
+{ return DT_NE; };
        YY_BREAK
 case 28:
 YY_RULE_SETUP
-#line 238 "dtc-lexer.l"
-{ return DT_OR; };
+#line 253 "dtc-lexer.l"
+{ return DT_AND; };
        YY_BREAK
 case 29:
 YY_RULE_SETUP
-#line 240 "dtc-lexer.l"
+#line 254 "dtc-lexer.l"
+{ return DT_OR; };
+       YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 256 "dtc-lexer.l"
 {
                        DPRINT("Char: %c (\\x%02x)\n", yytext[0],
                                (unsigned)yytext[0]);
@@ -1230,12 +1247,12 @@ YY_RULE_SETUP
                        return yytext[0];
                }
        YY_BREAK
-case 30:
+case 31:
 YY_RULE_SETUP
-#line 255 "dtc-lexer.l"
+#line 271 "dtc-lexer.l"
 ECHO;
        YY_BREAK
-#line 1239 "dtc-lexer.lex.c"
+#line 1256 "dtc-lexer.lex.c"
 
        case YY_END_OF_BUFFER:
                {
@@ -1377,9 +1394,9 @@ ECHO;
  */
 static int yy_get_next_buffer (void)
 {
-       register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
-       register char *source = (yytext_ptr);
-       register int number_to_move, i;
+       char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+       char *source = (yytext_ptr);
+       yy_size_t number_to_move, i;
        int ret_val;
 
        if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
@@ -1408,7 +1425,7 @@ static int yy_get_next_buffer (void)
        /* Try to read more data. */
 
        /* First move last chars to start of buffer. */
-       number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+       number_to_move = (yy_size_t) ((yy_c_buf_p) - (yytext_ptr)) - 1;
 
        for ( i = 0; i < number_to_move; ++i )
                *(dest++) = *(source++);
@@ -1421,7 +1438,7 @@ static int yy_get_next_buffer (void)
 
        else
                {
-                       yy_size_t num_to_read =
+                       int num_to_read =
                        YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
 
                while ( num_to_read <= 0 )
@@ -1435,7 +1452,7 @@ static int yy_get_next_buffer (void)
 
                        if ( b->yy_is_our_buffer )
                                {
-                               yy_size_t new_size = b->yy_buf_size * 2;
+                               int new_size = b->yy_buf_size * 2;
 
                                if ( new_size <= 0 )
                                        b->yy_buf_size += b->yy_buf_size / 8;
@@ -1448,7 +1465,7 @@ static int yy_get_next_buffer (void)
                                }
                        else
                                /* Can't grow it, we don't own it. */
-                               b->yy_ch_buf = 0;
+                               b->yy_ch_buf = NULL;
 
                        if ( ! b->yy_ch_buf )
                                YY_FATAL_ERROR(
@@ -1490,9 +1507,9 @@ static int yy_get_next_buffer (void)
        else
                ret_val = EOB_ACT_CONTINUE_SCAN;
 
-       if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+       if ((int) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
                /* Extend the array by 50%, plus the number we really need. */
-               yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+               int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
                YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size  );
                if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
                        YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
@@ -1511,15 +1528,15 @@ static int yy_get_next_buffer (void)
 
     static yy_state_type yy_get_previous_state (void)
 {
-       register yy_state_type yy_current_state;
-       register char *yy_cp;
+       yy_state_type yy_current_state;
+       char *yy_cp;
     
        yy_current_state = (yy_start);
        yy_current_state += YY_AT_BOL();
 
        for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
                {
-               register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+               YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
                if ( yy_accept[yy_current_state] )
                        {
                        (yy_last_accepting_state) = yy_current_state;
@@ -1528,10 +1545,10 @@ static int yy_get_next_buffer (void)
                while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
                        {
                        yy_current_state = (int) yy_def[yy_current_state];
-                       if ( yy_current_state >= 159 )
+                       if ( yy_current_state >= 166 )
                                yy_c = yy_meta[(unsigned int) yy_c];
                        }
-               yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+               yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c];
                }
 
        return yy_current_state;
@@ -1544,10 +1561,10 @@ static int yy_get_next_buffer (void)
  */
     static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state )
 {
-       register int yy_is_jam;
-       register char *yy_cp = (yy_c_buf_p);
+       int yy_is_jam;
+       char *yy_cp = (yy_c_buf_p);
 
-       register YY_CHAR yy_c = 1;
+       YY_CHAR yy_c = 1;
        if ( yy_accept[yy_current_state] )
                {
                (yy_last_accepting_state) = yy_current_state;
@@ -1556,15 +1573,19 @@ static int yy_get_next_buffer (void)
        while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
                {
                yy_current_state = (int) yy_def[yy_current_state];
-               if ( yy_current_state >= 159 )
+               if ( yy_current_state >= 166 )
                        yy_c = yy_meta[(unsigned int) yy_c];
                }
-       yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-       yy_is_jam = (yy_current_state == 158);
+       yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c];
+       yy_is_jam = (yy_current_state == 165);
 
                return yy_is_jam ? 0 : yy_current_state;
 }
 
+#ifndef YY_NO_UNPUT
+
+#endif
+
 #ifndef YY_NO_INPUT
 #ifdef __cplusplus
     static int yyinput (void)
@@ -1589,7 +1610,7 @@ static int yy_get_next_buffer (void)
 
                else
                        { /* need more input */
-                       yy_size_t offset = (yy_c_buf_p) - (yytext_ptr);
+                       int offset = (yy_c_buf_p) - (yytext_ptr);
                        ++(yy_c_buf_p);
 
                        switch ( yy_get_next_buffer(  ) )
@@ -1613,7 +1634,7 @@ static int yy_get_next_buffer (void)
                                case EOB_ACT_END_OF_FILE:
                                        {
                                        if ( yywrap( ) )
-                                               return EOF;
+                                               return 0;
 
                                        if ( ! (yy_did_buffer_switch_on_eof) )
                                                YY_NEW_FILE;
@@ -1716,7 +1737,7 @@ static void yy_load_buffer_state  (void)
        if ( ! b )
                YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
 
-       b->yy_buf_size = size;
+       b->yy_buf_size = (yy_size_t)size;
 
        /* yy_ch_buf has to be 2 characters longer than the size given because
         * we need to put in 2 end-of-buffer characters.
@@ -1863,7 +1884,7 @@ void yypop_buffer_state (void)
  */
 static void yyensure_buffer_stack (void)
 {
-       yy_size_t num_to_alloc;
+       int num_to_alloc;
     
        if (!(yy_buffer_stack)) {
 
@@ -1871,15 +1892,15 @@ static void yyensure_buffer_stack (void)
                 * scanner will even need a stack. We use 2 instead of 1 to avoid an
                 * immediate realloc on the next call.
          */
-               num_to_alloc = 1;
+      num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */
                (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
                                                                (num_to_alloc * sizeof(struct yy_buffer_state*)
                                                                );
                if ( ! (yy_buffer_stack) )
                        YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
-                                                                 
+
                memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
-                               
+
                (yy_buffer_stack_max) = num_to_alloc;
                (yy_buffer_stack_top) = 0;
                return;
@@ -1888,7 +1909,7 @@ static void yyensure_buffer_stack (void)
        if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
 
                /* Increase the buffer to prepare for a possible push. */
-               int grow_size = 8 /* arbitrary grow size */;
+               yy_size_t grow_size = 8 /* arbitrary grow size */;
 
                num_to_alloc = (yy_buffer_stack_max) + grow_size;
                (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
@@ -1908,7 +1929,7 @@ static void yyensure_buffer_stack (void)
  * @param base the character buffer
  * @param size the size in bytes of the character buffer
  * 
- * @return the newly allocated buffer state object. 
+ * @return the newly allocated buffer state object.
  */
 YY_BUFFER_STATE yy_scan_buffer  (char * base, yy_size_t  size )
 {
@@ -1918,7 +1939,7 @@ YY_BUFFER_STATE yy_scan_buffer  (char * base, yy_size_t  size )
             base[size-2] != YY_END_OF_BUFFER_CHAR ||
             base[size-1] != YY_END_OF_BUFFER_CHAR )
                /* They forgot to leave room for the EOB's. */
-               return 0;
+               return NULL;
 
        b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state )  );
        if ( ! b )
@@ -1927,7 +1948,7 @@ YY_BUFFER_STATE yy_scan_buffer  (char * base, yy_size_t  size )
        b->yy_buf_size = size - 2;      /* "- 2" to take care of EOB's */
        b->yy_buf_pos = b->yy_ch_buf = base;
        b->yy_is_our_buffer = 0;
-       b->yy_input_file = 0;
+       b->yy_input_file = NULL;
        b->yy_n_chars = b->yy_buf_size;
        b->yy_is_interactive = 0;
        b->yy_at_bol = 1;
@@ -1950,7 +1971,7 @@ YY_BUFFER_STATE yy_scan_buffer  (char * base, yy_size_t  size )
 YY_BUFFER_STATE yy_scan_string (yyconst char * yystr )
 {
     
-       return yy_scan_bytes(yystr,strlen(yystr) );
+       return yy_scan_bytes(yystr,(int) strlen(yystr) );
 }
 
 /** Setup the input buffer state to scan the given bytes. The next call to yylex() will
@@ -1960,7 +1981,7 @@ YY_BUFFER_STATE yy_scan_string (yyconst char * yystr )
  * 
  * @return the newly allocated buffer state object.
  */
-YY_BUFFER_STATE yy_scan_bytes  (yyconst char * yybytes, yy_size_t  _yybytes_len )
+YY_BUFFER_STATE yy_scan_bytes  (yyconst char * yybytes, int  _yybytes_len )
 {
        YY_BUFFER_STATE b;
        char *buf;
@@ -1968,7 +1989,7 @@ YY_BUFFER_STATE yy_scan_bytes  (yyconst char * yybytes, yy_size_t  _yybytes_len
        yy_size_t i;
     
        /* Get memory for full buffer, including space for trailing EOB's. */
-       n = _yybytes_len + 2;
+       n = (yy_size_t) _yybytes_len + 2;
        buf = (char *) yyalloc(n  );
        if ( ! buf )
                YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
@@ -1994,9 +2015,9 @@ YY_BUFFER_STATE yy_scan_bytes  (yyconst char * yybytes, yy_size_t  _yybytes_len
 #define YY_EXIT_FAILURE 2
 #endif
 
-static void yy_fatal_error (yyconst char* msg )
+static void yynoreturn yy_fatal_error (yyconst char* msg )
 {
-       (void) fprintf( stderr, "%s\n", msg );
+                       (void) fprintf( stderr, "%s\n", msg );
        exit( YY_EXIT_FAILURE );
 }
 
@@ -2024,7 +2045,7 @@ static void yy_fatal_error (yyconst char* msg )
  */
 int yyget_lineno  (void)
 {
-        
+    
     return yylineno;
 }
 
@@ -2047,7 +2068,7 @@ FILE *yyget_out  (void)
 /** Get the length of the current token.
  * 
  */
-yy_size_t yyget_leng  (void)
+int yyget_leng  (void)
 {
         return yyleng;
 }
@@ -2062,29 +2083,29 @@ char *yyget_text  (void)
 }
 
 /** Set the current line number.
- * @param line_number
+ * @param _line_number line number
  * 
  */
-void yyset_lineno (int  line_number )
+void yyset_lineno (int  _line_number )
 {
     
-    yylineno = line_number;
+    yylineno = _line_number;
 }
 
 /** Set the input stream. This does not discard the current
  * input buffer.
- * @param in_str A readable stream.
+ * @param _in_str A readable stream.
  * 
  * @see yy_switch_to_buffer
  */
-void yyset_in (FILE *  in_str )
+void yyset_in (FILE *  _in_str )
 {
-        yyin = in_str ;
+        yyin = _in_str ;
 }
 
-void yyset_out (FILE *  out_str )
+void yyset_out (FILE *  _out_str )
 {
-        yyout = out_str ;
+        yyout = _out_str ;
 }
 
 int yyget_debug  (void)
@@ -2092,9 +2113,9 @@ int yyget_debug  (void)
         return yy_flex_debug;
 }
 
-void yyset_debug (int  bdebug )
+void yyset_debug (int  _bdebug )
 {
-        yy_flex_debug = bdebug ;
+        yy_flex_debug = _bdebug ;
 }
 
 static int yy_init_globals (void)
@@ -2103,10 +2124,10 @@ static int yy_init_globals (void)
      * This function is called from yylex_destroy(), so don't allocate here.
      */
 
-    (yy_buffer_stack) = 0;
+    (yy_buffer_stack) = NULL;
     (yy_buffer_stack_top) = 0;
     (yy_buffer_stack_max) = 0;
-    (yy_c_buf_p) = (char *) 0;
+    (yy_c_buf_p) = NULL;
     (yy_init) = 0;
     (yy_start) = 0;
 
@@ -2115,8 +2136,8 @@ static int yy_init_globals (void)
     yyin = stdin;
     yyout = stdout;
 #else
-    yyin = (FILE *) 0;
-    yyout = (FILE *) 0;
+    yyin = NULL;
+    yyout = NULL;
 #endif
 
     /* For future reference: Set errno on error, since we are called by
@@ -2154,7 +2175,8 @@ int yylex_destroy  (void)
 #ifndef yytext_ptr
 static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
 {
-       register int i;
+               
+       int i;
        for ( i = 0; i < n; ++i )
                s1[i] = s2[i];
 }
@@ -2163,7 +2185,7 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
 #ifdef YY_NEED_STRLEN
 static int yy_flex_strlen (yyconst char * s )
 {
-       register int n;
+       int n;
        for ( n = 0; s[n]; ++n )
                ;
 
@@ -2173,11 +2195,12 @@ static int yy_flex_strlen (yyconst char * s )
 
 void *yyalloc (yy_size_t  size )
 {
-       return (void *) malloc( size );
+                       return malloc(size);
 }
 
 void *yyrealloc  (void * ptr, yy_size_t  size )
 {
+               
        /* The cast to (char *) in the following accommodates both
         * implementations that use char* generic pointers, and those
         * that use void* generic pointers.  It works with the latter
@@ -2185,17 +2208,17 @@ void *yyrealloc  (void * ptr, yy_size_t  size )
         * any pointer type to void*, and deal with argument conversions
         * as though doing an assignment.
         */
-       return (void *) realloc( (char *) ptr, size );
+       return realloc(ptr, size);
 }
 
 void yyfree (void * ptr )
 {
-       free( (char *) ptr );   /* see yyrealloc() for (char *) cast */
+                       free( (char *) ptr );   /* see yyrealloc() for (char *) cast */
 }
 
 #define YYTABLES_NAME "yytables"
 
-#line 254 "dtc-lexer.l"
+#line 271 "dtc-lexer.l"
 
 
 
index 116458c..2965227 100644 (file)
@@ -1,8 +1,8 @@
-/* A Bison parser, made by GNU Bison 3.0.2.  */
+/* A Bison parser, made by GNU Bison 3.0.4.  */
 
 /* Bison implementation for Yacc-like parsers in C
 
-   Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
+   Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -44,7 +44,7 @@
 #define YYBISON 1
 
 /* Bison version.  */
-#define YYBISON_VERSION "3.0.2"
+#define YYBISON_VERSION "3.0.4"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
@@ -65,6 +65,7 @@
 #line 20 "dtc-parser.y" /* yacc.c:339  */
 
 #include <stdio.h>
+#include <inttypes.h>
 
 #include "dtc.h"
 #include "srcpos.h"
@@ -77,10 +78,10 @@ extern void yyerror(char const *s);
                treesource_error = true; \
        } while (0)
 
-extern struct boot_info *the_boot_info;
+extern struct dt_info *parser_output;
 extern bool treesource_error;
 
-#line 84 "dtc-parser.tab.c" /* yacc.c:339  */
+#line 85 "dtc-parser.tab.c" /* yacc.c:339  */
 
 # ifndef YY_NULLPTR
 #  if defined __cplusplus && 201103L <= __cplusplus
@@ -116,35 +117,36 @@ extern int yydebug;
   enum yytokentype
   {
     DT_V1 = 258,
-    DT_MEMRESERVE = 259,
-    DT_LSHIFT = 260,
-    DT_RSHIFT = 261,
-    DT_LE = 262,
-    DT_GE = 263,
-    DT_EQ = 264,
-    DT_NE = 265,
-    DT_AND = 266,
-    DT_OR = 267,
-    DT_BITS = 268,
-    DT_DEL_PROP = 269,
-    DT_DEL_NODE = 270,
-    DT_PROPNODENAME = 271,
-    DT_LITERAL = 272,
-    DT_CHAR_LITERAL = 273,
-    DT_BYTE = 274,
-    DT_STRING = 275,
-    DT_LABEL = 276,
-    DT_REF = 277,
-    DT_INCBIN = 278
+    DT_PLUGIN = 259,
+    DT_MEMRESERVE = 260,
+    DT_LSHIFT = 261,
+    DT_RSHIFT = 262,
+    DT_LE = 263,
+    DT_GE = 264,
+    DT_EQ = 265,
+    DT_NE = 266,
+    DT_AND = 267,
+    DT_OR = 268,
+    DT_BITS = 269,
+    DT_DEL_PROP = 270,
+    DT_DEL_NODE = 271,
+    DT_PROPNODENAME = 272,
+    DT_LITERAL = 273,
+    DT_CHAR_LITERAL = 274,
+    DT_BYTE = 275,
+    DT_STRING = 276,
+    DT_LABEL = 277,
+    DT_REF = 278,
+    DT_INCBIN = 279
   };
 #endif
 
 /* Value type.  */
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE YYSTYPE;
+
 union YYSTYPE
 {
-#line 38 "dtc-parser.y" /* yacc.c:355  */
+#line 39 "dtc-parser.y" /* yacc.c:355  */
 
        char *propnodename;
        char *labelref;
@@ -162,9 +164,12 @@ union YYSTYPE
        struct node *nodelist;
        struct reserve_info *re;
        uint64_t integer;
+       unsigned int flags;
 
-#line 167 "dtc-parser.tab.c" /* yacc.c:355  */
+#line 170 "dtc-parser.tab.c" /* yacc.c:355  */
 };
+
+typedef union YYSTYPE YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define YYSTYPE_IS_DECLARED 1
 #endif
@@ -192,7 +197,7 @@ int yyparse (void);
 
 /* Copy the second part of user declarations.  */
 
-#line 196 "dtc-parser.tab.c" /* yacc.c:358  */
+#line 201 "dtc-parser.tab.c" /* yacc.c:358  */
 
 #ifdef short
 # undef short
@@ -434,23 +439,23 @@ union yyalloc
 #endif /* !YYCOPY_NEEDED */
 
 /* YYFINAL -- State number of the termination state.  */
-#define YYFINAL  4
+#define YYFINAL  6
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   136
+#define YYLAST   138
 
 /* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  47
+#define YYNTOKENS  48
 /* YYNNTS -- Number of nonterminals.  */
-#define YYNNTS  28
+#define YYNNTS  30
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  80
+#define YYNRULES  84
 /* YYNSTATES -- Number of states.  */
-#define YYNSTATES  144
+#define YYNSTATES  149
 
 /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
    by yylex, with out-of-bounds checking.  */
 #define YYUNDEFTOK  2
-#define YYMAXUTOK   278
+#define YYMAXUTOK   279
 
 #define YYTRANSLATE(YYX)                                                \
   ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
@@ -462,16 +467,16 @@ static const yytype_uint8 yytranslate[] =
        0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,    46,     2,     2,     2,    44,    40,     2,
-      32,    34,    43,    41,    33,    42,     2,    25,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,    37,    24,
-      35,    28,    29,    36,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,    47,     2,     2,     2,    45,    41,     2,
+      33,    35,    44,    42,    34,    43,     2,    26,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,    38,    25,
+      36,    29,    30,    37,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,    30,     2,    31,    39,     2,     2,     2,     2,     2,
+       2,    31,     2,    32,    40,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,    26,    38,    27,    45,     2,     2,     2,
+       2,     2,     2,    27,    39,    28,    46,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -486,22 +491,22 @@ static const yytype_uint8 yytranslate[] =
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
        5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
-      15,    16,    17,    18,    19,    20,    21,    22,    23
+      15,    16,    17,    18,    19,    20,    21,    22,    23,    24
 };
 
 #if YYDEBUG
   /* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   104,   104,   113,   116,   123,   127,   135,   139,   144,
-     155,   165,   180,   188,   191,   198,   202,   206,   210,   218,
-     222,   226,   230,   234,   250,   260,   268,   271,   275,   282,
-     298,   303,   322,   336,   343,   344,   345,   352,   356,   357,
-     361,   362,   366,   367,   371,   372,   376,   377,   381,   382,
-     386,   387,   388,   392,   393,   394,   395,   396,   400,   401,
-     402,   406,   407,   408,   412,   413,   414,   415,   419,   420,
-     421,   422,   427,   430,   434,   442,   445,   449,   457,   461,
-     465
+       0,   109,   109,   117,   121,   128,   129,   139,   142,   149,
+     153,   161,   165,   170,   181,   191,   206,   214,   217,   224,
+     228,   232,   236,   244,   248,   252,   256,   260,   276,   286,
+     294,   297,   301,   308,   324,   329,   348,   362,   369,   370,
+     371,   378,   382,   383,   387,   388,   392,   393,   397,   398,
+     402,   403,   407,   408,   412,   413,   414,   418,   419,   420,
+     421,   422,   426,   427,   428,   432,   433,   434,   438,   439,
+     448,   457,   461,   462,   463,   464,   469,   472,   476,   484,
+     487,   491,   499,   503,   507
 };
 #endif
 
@@ -510,19 +515,20 @@ static const yytype_uint16 yyrline[] =
    First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
 static const char *const yytname[] =
 {
-  "$end", "error", "$undefined", "DT_V1", "DT_MEMRESERVE", "DT_LSHIFT",
-  "DT_RSHIFT", "DT_LE", "DT_GE", "DT_EQ", "DT_NE", "DT_AND", "DT_OR",
-  "DT_BITS", "DT_DEL_PROP", "DT_DEL_NODE", "DT_PROPNODENAME", "DT_LITERAL",
-  "DT_CHAR_LITERAL", "DT_BYTE", "DT_STRING", "DT_LABEL", "DT_REF",
-  "DT_INCBIN", "';'", "'/'", "'{'", "'}'", "'='", "'>'", "'['", "']'",
-  "'('", "','", "')'", "'<'", "'?'", "':'", "'|'", "'^'", "'&'", "'+'",
-  "'-'", "'*'", "'%'", "'~'", "'!'", "$accept", "sourcefile",
-  "memreserves", "memreserve", "devicetree", "nodedef", "proplist",
-  "propdef", "propdata", "propdataprefix", "arrayprefix", "integer_prim",
-  "integer_expr", "integer_trinary", "integer_or", "integer_and",
-  "integer_bitor", "integer_bitxor", "integer_bitand", "integer_eq",
-  "integer_rela", "integer_shift", "integer_add", "integer_mul",
-  "integer_unary", "bytestring", "subnodes", "subnode", YY_NULLPTR
+  "$end", "error", "$undefined", "DT_V1", "DT_PLUGIN", "DT_MEMRESERVE",
+  "DT_LSHIFT", "DT_RSHIFT", "DT_LE", "DT_GE", "DT_EQ", "DT_NE", "DT_AND",
+  "DT_OR", "DT_BITS", "DT_DEL_PROP", "DT_DEL_NODE", "DT_PROPNODENAME",
+  "DT_LITERAL", "DT_CHAR_LITERAL", "DT_BYTE", "DT_STRING", "DT_LABEL",
+  "DT_REF", "DT_INCBIN", "';'", "'/'", "'{'", "'}'", "'='", "'>'", "'['",
+  "']'", "'('", "','", "')'", "'<'", "'?'", "':'", "'|'", "'^'", "'&'",
+  "'+'", "'-'", "'*'", "'%'", "'~'", "'!'", "$accept", "sourcefile",
+  "header", "headers", "memreserves", "memreserve", "devicetree",
+  "nodedef", "proplist", "propdef", "propdata", "propdataprefix",
+  "arrayprefix", "integer_prim", "integer_expr", "integer_trinary",
+  "integer_or", "integer_and", "integer_bitor", "integer_bitxor",
+  "integer_bitand", "integer_eq", "integer_rela", "integer_shift",
+  "integer_add", "integer_mul", "integer_unary", "bytestring", "subnodes",
+  "subnode", YY_NULLPTR
 };
 #endif
 
@@ -533,16 +539,16 @@ static const yytype_uint16 yytoknum[] =
 {
        0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
      265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
-     275,   276,   277,   278,    59,    47,   123,   125,    61,    62,
-      91,    93,    40,    44,    41,    60,    63,    58,   124,    94,
-      38,    43,    45,    42,    37,   126,    33
+     275,   276,   277,   278,   279,    59,    47,   123,   125,    61,
+      62,    91,    93,    40,    44,    41,    60,    63,    58,   124,
+      94,    38,    43,    45,    42,    37,   126,    33
 };
 # endif
 
-#define YYPACT_NINF -81
+#define YYPACT_NINF -44
 
 #define yypact_value_is_default(Yystate) \
-  (!!((Yystate) == (-81)))
+  (!!((Yystate) == (-44)))
 
 #define YYTABLE_NINF -1
 
@@ -553,21 +559,21 @@ static const yytype_uint16 yytoknum[] =
      STATE-NUM.  */
 static const yytype_int8 yypact[] =
 {
-      16,   -11,    21,    10,   -81,    25,    10,    19,    10,   -81,
-     -81,    -9,    25,   -81,     2,    51,   -81,    -9,    -9,    -9,
-     -81,     1,   -81,    -6,    50,    14,    28,    29,    36,     3,
-      58,    44,    -3,   -81,    47,   -81,   -81,    65,    68,     2,
-       2,   -81,   -81,   -81,   -81,    -9,    -9,    -9,    -9,    -9,
-      -9,    -9,    -9,    -9,    -9,    -9,    -9,    -9,    -9,    -9,
-      -9,    -9,    -9,    -9,   -81,    63,    69,     2,   -81,   -81,
-      50,    57,    14,    28,    29,    36,     3,     3,    58,    58,
-      58,    58,    44,    44,    -3,    -3,   -81,   -81,   -81,    79,
-      80,    -8,    63,   -81,    72,    63,   -81,   -81,    -9,    76,
-      77,   -81,   -81,   -81,   -81,   -81,    78,   -81,   -81,   -81,
-     -81,   -81,    35,     4,   -81,   -81,   -81,   -81,    86,   -81,
-     -81,   -81,    73,   -81,   -81,    33,    71,    84,    39,   -81,
-     -81,   -81,   -81,   -81,    41,   -81,   -81,   -81,    25,   -81,
-      74,    25,    75,   -81
+      14,    27,    61,    14,     8,    18,   -44,   -44,    37,     8,
+      40,     8,    64,   -44,   -44,   -12,    37,   -44,    50,    52,
+     -44,   -44,   -12,   -12,   -12,   -44,    51,   -44,    -4,    78,
+      53,    54,    55,    17,     2,    30,    38,    -3,   -44,    66,
+     -44,   -44,    70,    72,    50,    50,   -44,   -44,   -44,   -44,
+     -12,   -12,   -12,   -12,   -12,   -12,   -12,   -12,   -12,   -12,
+     -12,   -12,   -12,   -12,   -12,   -12,   -12,   -12,   -12,   -44,
+       3,    73,    50,   -44,   -44,    78,    59,    53,    54,    55,
+      17,     2,     2,    30,    30,    30,    30,    38,    38,    -3,
+      -3,   -44,   -44,   -44,    82,    83,    44,     3,   -44,    74,
+       3,   -44,   -44,   -12,    76,    79,   -44,   -44,   -44,   -44,
+     -44,    80,   -44,   -44,   -44,   -44,   -44,   -10,    36,   -44,
+     -44,   -44,   -44,    85,   -44,   -44,   -44,    75,   -44,   -44,
+      21,    71,    88,    -6,   -44,   -44,   -44,   -44,   -44,    11,
+     -44,   -44,   -44,    37,   -44,    77,    37,    81,   -44
 };
 
   /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
@@ -575,37 +581,37 @@ static const yytype_int8 yypact[] =
      means the default is an error.  */
 static const yytype_uint8 yydefact[] =
 {
-       0,     0,     0,     3,     1,     0,     0,     0,     3,    34,
-      35,     0,     0,     6,     0,     2,     4,     0,     0,     0,
-      68,     0,    37,    38,    40,    42,    44,    46,    48,    50,
-      53,    60,    63,    67,     0,    13,     7,     0,     0,     0,
-       0,    69,    70,    71,    36,     0,     0,     0,     0,     0,
+       0,     0,     0,     5,     7,     3,     1,     6,     0,     0,
+       0,     7,     0,    38,    39,     0,     0,    10,     0,     2,
+       8,     4,     0,     0,     0,    72,     0,    41,    42,    44,
+      46,    48,    50,    52,    54,    57,    64,    67,    71,     0,
+      17,    11,     0,     0,     0,     0,    73,    74,    75,    40,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     5,    75,     0,     0,    10,     8,
-      41,     0,    43,    45,    47,    49,    51,    52,    56,    57,
-      55,    54,    58,    59,    61,    62,    65,    64,    66,     0,
-       0,     0,     0,    14,     0,    75,    11,     9,     0,     0,
-       0,    16,    26,    78,    18,    80,     0,    77,    76,    39,
-      17,    79,     0,     0,    12,    25,    15,    27,     0,    19,
-      28,    22,     0,    72,    30,     0,     0,     0,     0,    33,
-      32,    20,    31,    29,     0,    73,    74,    21,     0,    24,
-       0,     0,     0,    23
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     9,
+      79,     0,     0,    14,    12,    45,     0,    47,    49,    51,
+      53,    55,    56,    60,    61,    59,    58,    62,    63,    65,
+      66,    69,    68,    70,     0,     0,     0,     0,    18,     0,
+      79,    15,    13,     0,     0,     0,    20,    30,    82,    22,
+      84,     0,    81,    80,    43,    21,    83,     0,     0,    16,
+      29,    19,    31,     0,    23,    32,    26,     0,    76,    34,
+       0,     0,     0,     0,    37,    36,    24,    35,    33,     0,
+      77,    78,    25,     0,    28,     0,     0,     0,    27
 };
 
   /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int8 yypgoto[] =
 {
-     -81,   -81,   100,   104,   -81,   -38,   -81,   -80,   -81,   -81,
-     -81,    -5,    66,    13,   -81,    70,    67,    81,    64,    82,
-      37,    27,    34,    38,   -14,   -81,    22,    24
+     -44,   -44,   -44,   103,    99,   104,   -44,   -43,   -44,   -21,
+     -44,   -44,   -44,    -8,    63,     9,   -44,    65,    67,    68,
+      69,    62,    26,     4,    22,    23,   -19,   -44,    20,    28
 };
 
   /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int16 yydefgoto[] =
 {
-      -1,     2,     7,     8,    15,    36,    65,    93,   112,   113,
-     125,    20,    21,    22,    23,    24,    25,    26,    27,    28,
-      29,    30,    31,    32,    33,   128,    94,    95
+      -1,     2,     3,     4,    10,    11,    19,    41,    70,    98,
+     117,   118,   130,    25,    26,    27,    28,    29,    30,    31,
+      32,    33,    34,    35,    36,    37,    38,   133,    99,   100
 };
 
   /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM.  If
@@ -613,87 +619,87 @@ static const yytype_int16 yydefgoto[] =
      number is the opposite.  If YYTABLE_NINF, syntax error.  */
 static const yytype_uint8 yytable[] =
 {
-      12,    68,    69,    41,    42,    43,    45,    34,     9,    10,
-      53,    54,   104,     3,     5,   107,   101,   118,    35,     1,
-     102,     4,    61,    11,   119,   120,   121,   122,    35,    97,
-      46,     6,    55,    17,   123,    44,    18,    19,    56,   124,
-      62,    63,     9,    10,    14,    51,    52,    86,    87,    88,
-       9,    10,    48,   103,   129,   130,   115,    11,   135,   116,
-     136,    47,   131,    57,    58,    11,    37,    49,   117,    50,
-     137,    64,    38,    39,   138,   139,    40,    89,    90,    91,
-      78,    79,    80,    81,    92,    59,    60,    66,    76,    77,
-      67,    82,    83,    96,    98,    99,   100,    84,    85,   106,
-     110,   111,   114,   126,   134,   127,   133,   141,    16,   143,
-      13,   109,    71,    74,    72,    70,   105,   108,     0,     0,
-     132,     0,     0,     0,     0,     0,     0,     0,     0,    73,
-       0,     0,    75,   140,     0,     0,   142
+      16,    73,    74,    46,    47,    48,    13,    14,    39,    50,
+      58,    59,   120,     8,   140,   121,   141,     1,    94,    95,
+      96,    15,    12,    66,   122,    97,   142,    56,    57,   102,
+       9,    22,    60,    51,    23,    24,    62,    63,    61,    13,
+      14,    67,    68,   134,   135,   143,   144,    91,    92,    93,
+     123,   136,     5,   108,    15,    13,    14,   124,   125,   126,
+     127,     6,    83,    84,    85,    86,    18,   128,    42,   106,
+      15,    40,   129,   107,    43,    44,   109,    40,    45,   112,
+      64,    65,    81,    82,    87,    88,    49,    89,    90,    21,
+      52,    69,    53,    71,    54,    72,    55,   103,   101,   104,
+     105,   115,   111,   131,   116,   119,     7,   138,   132,   139,
+      20,   146,   114,    17,    76,    75,   148,    80,     0,    77,
+     113,    78,   137,    79,     0,   110,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,   145,     0,     0,   147
 };
 
 static const yytype_int16 yycheck[] =
 {
-       5,    39,    40,    17,    18,    19,    12,    12,    17,    18,
-       7,     8,    92,    24,     4,    95,    24,    13,    26,     3,
-      28,     0,    25,    32,    20,    21,    22,    23,    26,    67,
-      36,    21,    29,    42,    30,    34,    45,    46,    35,    35,
-      43,    44,    17,    18,    25,     9,    10,    61,    62,    63,
-      17,    18,    38,    91,    21,    22,    21,    32,    19,    24,
-      21,    11,    29,     5,     6,    32,    15,    39,    33,    40,
-      31,    24,    21,    22,    33,    34,    25,    14,    15,    16,
-      53,    54,    55,    56,    21,    41,    42,    22,    51,    52,
-      22,    57,    58,    24,    37,    16,    16,    59,    60,    27,
-      24,    24,    24,    17,    20,    32,    35,    33,     8,    34,
-       6,    98,    46,    49,    47,    45,    92,    95,    -1,    -1,
-     125,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    48,
-      -1,    -1,    50,   138,    -1,    -1,   141
+       8,    44,    45,    22,    23,    24,    18,    19,    16,    13,
+       8,     9,    22,     5,    20,    25,    22,     3,    15,    16,
+      17,    33,     4,    26,    34,    22,    32,    10,    11,    72,
+      22,    43,    30,    37,    46,    47,     6,     7,    36,    18,
+      19,    44,    45,    22,    23,    34,    35,    66,    67,    68,
+      14,    30,    25,    96,    33,    18,    19,    21,    22,    23,
+      24,     0,    58,    59,    60,    61,    26,    31,    16,    25,
+      33,    27,    36,    29,    22,    23,    97,    27,    26,   100,
+      42,    43,    56,    57,    62,    63,    35,    64,    65,    25,
+      12,    25,    39,    23,    40,    23,    41,    38,    25,    17,
+      17,    25,    28,    18,    25,    25,     3,    36,    33,    21,
+      11,    34,   103,     9,    51,    50,    35,    55,    -1,    52,
+     100,    53,   130,    54,    -1,    97,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,   143,    -1,    -1,   146
 };
 
   /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
      symbol of state STATE-NUM.  */
 static const yytype_uint8 yystos[] =
 {
-       0,     3,    48,    24,     0,     4,    21,    49,    50,    17,
-      18,    32,    58,    50,    25,    51,    49,    42,    45,    46,
-      58,    59,    60,    61,    62,    63,    64,    65,    66,    67,
-      68,    69,    70,    71,    58,    26,    52,    15,    21,    22,
-      25,    71,    71,    71,    34,    12,    36,    11,    38,    39,
-      40,     9,    10,     7,     8,    29,    35,     5,     6,    41,
-      42,    25,    43,    44,    24,    53,    22,    22,    52,    52,
-      62,    59,    63,    64,    65,    66,    67,    67,    68,    68,
-      68,    68,    69,    69,    70,    70,    71,    71,    71,    14,
-      15,    16,    21,    54,    73,    74,    24,    52,    37,    16,
-      16,    24,    28,    52,    54,    74,    27,    54,    73,    60,
-      24,    24,    55,    56,    24,    21,    24,    33,    13,    20,
-      21,    22,    23,    30,    35,    57,    17,    32,    72,    21,
-      22,    29,    58,    35,    20,    19,    21,    31,    33,    34,
-      58,    33,    58,    34
+       0,     3,    49,    50,    51,    25,     0,    51,     5,    22,
+      52,    53,     4,    18,    19,    33,    61,    53,    26,    54,
+      52,    25,    43,    46,    47,    61,    62,    63,    64,    65,
+      66,    67,    68,    69,    70,    71,    72,    73,    74,    61,
+      27,    55,    16,    22,    23,    26,    74,    74,    74,    35,
+      13,    37,    12,    39,    40,    41,    10,    11,     8,     9,
+      30,    36,     6,     7,    42,    43,    26,    44,    45,    25,
+      56,    23,    23,    55,    55,    65,    62,    66,    67,    68,
+      69,    70,    70,    71,    71,    71,    71,    72,    72,    73,
+      73,    74,    74,    74,    15,    16,    17,    22,    57,    76,
+      77,    25,    55,    38,    17,    17,    25,    29,    55,    57,
+      77,    28,    57,    76,    63,    25,    25,    58,    59,    25,
+      22,    25,    34,    14,    21,    22,    23,    24,    31,    36,
+      60,    18,    33,    75,    22,    23,    30,    61,    36,    21,
+      20,    22,    32,    34,    35,    61,    34,    61,    35
 };
 
   /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
 static const yytype_uint8 yyr1[] =
 {
-       0,    47,    48,    49,    49,    50,    50,    51,    51,    51,
-      51,    51,    52,    53,    53,    54,    54,    54,    54,    55,
-      55,    55,    55,    55,    55,    55,    56,    56,    56,    57,
-      57,    57,    57,    57,    58,    58,    58,    59,    60,    60,
-      61,    61,    62,    62,    63,    63,    64,    64,    65,    65,
-      66,    66,    66,    67,    67,    67,    67,    67,    68,    68,
-      68,    69,    69,    69,    70,    70,    70,    70,    71,    71,
-      71,    71,    72,    72,    72,    73,    73,    73,    74,    74,
-      74
+       0,    48,    49,    50,    50,    51,    51,    52,    52,    53,
+      53,    54,    54,    54,    54,    54,    55,    56,    56,    57,
+      57,    57,    57,    58,    58,    58,    58,    58,    58,    58,
+      59,    59,    59,    60,    60,    60,    60,    60,    61,    61,
+      61,    62,    63,    63,    64,    64,    65,    65,    66,    66,
+      67,    67,    68,    68,    69,    69,    69,    70,    70,    70,
+      70,    70,    71,    71,    71,    72,    72,    72,    73,    73,
+      73,    73,    74,    74,    74,    74,    75,    75,    75,    76,
+      76,    76,    77,    77,    77
 };
 
   /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN.  */
 static const yytype_uint8 yyr2[] =
 {
-       0,     2,     4,     0,     2,     4,     2,     2,     3,     4,
-       3,     4,     5,     0,     2,     4,     2,     3,     2,     2,
-       3,     4,     2,     9,     5,     2,     0,     2,     2,     3,
-       1,     2,     2,     2,     1,     1,     3,     1,     1,     5,
-       1,     3,     1,     3,     1,     3,     1,     3,     1,     3,
-       1,     3,     3,     1,     3,     3,     3,     3,     3,     3,
-       1,     3,     3,     1,     3,     3,     3,     1,     1,     2,
-       2,     2,     0,     2,     2,     0,     2,     2,     2,     3,
-       2
+       0,     2,     3,     2,     4,     1,     2,     0,     2,     4,
+       2,     2,     3,     4,     3,     4,     5,     0,     2,     4,
+       2,     3,     2,     2,     3,     4,     2,     9,     5,     2,
+       0,     2,     2,     3,     1,     2,     2,     2,     1,     1,
+       3,     1,     1,     5,     1,     3,     1,     3,     1,     3,
+       1,     3,     1,     3,     1,     3,     3,     1,     3,     3,
+       3,     3,     3,     3,     1,     3,     3,     1,     3,     3,
+       3,     1,     1,     2,     2,     2,     0,     2,     2,     0,
+       2,     2,     2,     3,     2
 };
 
 
@@ -1463,65 +1469,91 @@ yyreduce:
   switch (yyn)
     {
         case 2:
-#line 105 "dtc-parser.y" /* yacc.c:1646  */
+#line 110 "dtc-parser.y" /* yacc.c:1646  */
     {
-                       the_boot_info = build_boot_info((yyvsp[-1].re), (yyvsp[0].node),
-                                                       guess_boot_cpuid((yyvsp[0].node)));
+                       parser_output = build_dt_info((yyvsp[-2].flags), (yyvsp[-1].re), (yyvsp[0].node),
+                                                     guess_boot_cpuid((yyvsp[0].node)));
                }
-#line 1472 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1478 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
   case 3:
-#line 113 "dtc-parser.y" /* yacc.c:1646  */
+#line 118 "dtc-parser.y" /* yacc.c:1646  */
     {
-                       (yyval.re) = NULL;
+                       (yyval.flags) = DTSF_V1;
                }
-#line 1480 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1486 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
   case 4:
-#line 117 "dtc-parser.y" /* yacc.c:1646  */
+#line 122 "dtc-parser.y" /* yacc.c:1646  */
+    {
+                       (yyval.flags) = DTSF_V1 | DTSF_PLUGIN;
+               }
+#line 1494 "dtc-parser.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 6:
+#line 130 "dtc-parser.y" /* yacc.c:1646  */
+    {
+                       if ((yyvsp[0].flags) != (yyvsp[-1].flags))
+                               ERROR(&(yylsp[0]), "Header flags don't match earlier ones");
+                       (yyval.flags) = (yyvsp[-1].flags);
+               }
+#line 1504 "dtc-parser.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 7:
+#line 139 "dtc-parser.y" /* yacc.c:1646  */
+    {
+                       (yyval.re) = NULL;
+               }
+#line 1512 "dtc-parser.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 8:
+#line 143 "dtc-parser.y" /* yacc.c:1646  */
     {
                        (yyval.re) = chain_reserve_entry((yyvsp[-1].re), (yyvsp[0].re));
                }
-#line 1488 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1520 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 5:
-#line 124 "dtc-parser.y" /* yacc.c:1646  */
+  case 9:
+#line 150 "dtc-parser.y" /* yacc.c:1646  */
     {
                        (yyval.re) = build_reserve_entry((yyvsp[-2].integer), (yyvsp[-1].integer));
                }
-#line 1496 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1528 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 6:
-#line 128 "dtc-parser.y" /* yacc.c:1646  */
+  case 10:
+#line 154 "dtc-parser.y" /* yacc.c:1646  */
     {
                        add_label(&(yyvsp[0].re)->labels, (yyvsp[-1].labelref));
                        (yyval.re) = (yyvsp[0].re);
                }
-#line 1505 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1537 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 7:
-#line 136 "dtc-parser.y" /* yacc.c:1646  */
+  case 11:
+#line 162 "dtc-parser.y" /* yacc.c:1646  */
     {
                        (yyval.node) = name_node((yyvsp[0].node), "");
                }
-#line 1513 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1545 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 8:
-#line 140 "dtc-parser.y" /* yacc.c:1646  */
+  case 12:
+#line 166 "dtc-parser.y" /* yacc.c:1646  */
     {
                        (yyval.node) = merge_nodes((yyvsp[-2].node), (yyvsp[0].node));
                }
-#line 1521 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1553 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 9:
-#line 145 "dtc-parser.y" /* yacc.c:1646  */
+  case 13:
+#line 171 "dtc-parser.y" /* yacc.c:1646  */
     {
                        struct node *target = get_node_by_ref((yyvsp[-3].node), (yyvsp[-1].labelref));
 
@@ -1532,11 +1564,11 @@ yyreduce:
                                ERROR(&(yylsp[-1]), "Label or path %s not found", (yyvsp[-1].labelref));
                        (yyval.node) = (yyvsp[-3].node);
                }
-#line 1536 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1568 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 10:
-#line 156 "dtc-parser.y" /* yacc.c:1646  */
+  case 14:
+#line 182 "dtc-parser.y" /* yacc.c:1646  */
     {
                        struct node *target = get_node_by_ref((yyvsp[-2].node), (yyvsp[-1].labelref));
 
@@ -1546,11 +1578,11 @@ yyreduce:
                                ERROR(&(yylsp[-1]), "Label or path %s not found", (yyvsp[-1].labelref));
                        (yyval.node) = (yyvsp[-2].node);
                }
-#line 1550 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1582 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 11:
-#line 166 "dtc-parser.y" /* yacc.c:1646  */
+  case 15:
+#line 192 "dtc-parser.y" /* yacc.c:1646  */
     {
                        struct node *target = get_node_by_ref((yyvsp[-3].node), (yyvsp[-1].labelref));
 
@@ -1562,100 +1594,100 @@ yyreduce:
 
                        (yyval.node) = (yyvsp[-3].node);
                }
-#line 1566 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1598 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 12:
-#line 181 "dtc-parser.y" /* yacc.c:1646  */
+  case 16:
+#line 207 "dtc-parser.y" /* yacc.c:1646  */
     {
                        (yyval.node) = build_node((yyvsp[-3].proplist), (yyvsp[-2].nodelist));
                }
-#line 1574 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1606 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 13:
-#line 188 "dtc-parser.y" /* yacc.c:1646  */
+  case 17:
+#line 214 "dtc-parser.y" /* yacc.c:1646  */
     {
                        (yyval.proplist) = NULL;
                }
-#line 1582 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1614 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 14:
-#line 192 "dtc-parser.y" /* yacc.c:1646  */
+  case 18:
+#line 218 "dtc-parser.y" /* yacc.c:1646  */
     {
                        (yyval.proplist) = chain_property((yyvsp[0].prop), (yyvsp[-1].proplist));
                }
-#line 1590 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1622 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 15:
-#line 199 "dtc-parser.y" /* yacc.c:1646  */
+  case 19:
+#line 225 "dtc-parser.y" /* yacc.c:1646  */
     {
                        (yyval.prop) = build_property((yyvsp[-3].propnodename), (yyvsp[-1].data));
                }
-#line 1598 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1630 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 16:
-#line 203 "dtc-parser.y" /* yacc.c:1646  */
+  case 20:
+#line 229 "dtc-parser.y" /* yacc.c:1646  */
     {
                        (yyval.prop) = build_property((yyvsp[-1].propnodename), empty_data);
                }
-#line 1606 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1638 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 17:
-#line 207 "dtc-parser.y" /* yacc.c:1646  */
+  case 21:
+#line 233 "dtc-parser.y" /* yacc.c:1646  */
     {
                        (yyval.prop) = build_property_delete((yyvsp[-1].propnodename));
                }
-#line 1614 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1646 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 18:
-#line 211 "dtc-parser.y" /* yacc.c:1646  */
+  case 22:
+#line 237 "dtc-parser.y" /* yacc.c:1646  */
     {
                        add_label(&(yyvsp[0].prop)->labels, (yyvsp[-1].labelref));
                        (yyval.prop) = (yyvsp[0].prop);
                }
-#line 1623 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1655 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 19:
-#line 219 "dtc-parser.y" /* yacc.c:1646  */
+  case 23:
+#line 245 "dtc-parser.y" /* yacc.c:1646  */
     {
                        (yyval.data) = data_merge((yyvsp[-1].data), (yyvsp[0].data));
                }
-#line 1631 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1663 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 20:
-#line 223 "dtc-parser.y" /* yacc.c:1646  */
+  case 24:
+#line 249 "dtc-parser.y" /* yacc.c:1646  */
     {
                        (yyval.data) = data_merge((yyvsp[-2].data), (yyvsp[-1].array).data);
                }
-#line 1639 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1671 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 21:
-#line 227 "dtc-parser.y" /* yacc.c:1646  */
+  case 25:
+#line 253 "dtc-parser.y" /* yacc.c:1646  */
     {
                        (yyval.data) = data_merge((yyvsp[-3].data), (yyvsp[-1].data));
                }
-#line 1647 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1679 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 22:
-#line 231 "dtc-parser.y" /* yacc.c:1646  */
+  case 26:
+#line 257 "dtc-parser.y" /* yacc.c:1646  */
     {
                        (yyval.data) = data_add_marker((yyvsp[-1].data), REF_PATH, (yyvsp[0].labelref));
                }
-#line 1655 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1687 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 23:
-#line 235 "dtc-parser.y" /* yacc.c:1646  */
+  case 27:
+#line 261 "dtc-parser.y" /* yacc.c:1646  */
     {
                        FILE *f = srcfile_relative_open((yyvsp[-5].data).val, NULL);
                        struct data d;
@@ -1671,11 +1703,11 @@ yyreduce:
                        (yyval.data) = data_merge((yyvsp[-8].data), d);
                        fclose(f);
                }
-#line 1675 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1707 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 24:
-#line 251 "dtc-parser.y" /* yacc.c:1646  */
+  case 28:
+#line 277 "dtc-parser.y" /* yacc.c:1646  */
     {
                        FILE *f = srcfile_relative_open((yyvsp[-1].data).val, NULL);
                        struct data d = empty_data;
@@ -1685,43 +1717,43 @@ yyreduce:
                        (yyval.data) = data_merge((yyvsp[-4].data), d);
                        fclose(f);
                }
-#line 1689 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1721 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 25:
-#line 261 "dtc-parser.y" /* yacc.c:1646  */
+  case 29:
+#line 287 "dtc-parser.y" /* yacc.c:1646  */
     {
                        (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref));
                }
-#line 1697 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1729 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 26:
-#line 268 "dtc-parser.y" /* yacc.c:1646  */
+  case 30:
+#line 294 "dtc-parser.y" /* yacc.c:1646  */
     {
                        (yyval.data) = empty_data;
                }
-#line 1705 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1737 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 27:
-#line 272 "dtc-parser.y" /* yacc.c:1646  */
+  case 31:
+#line 298 "dtc-parser.y" /* yacc.c:1646  */
     {
                        (yyval.data) = (yyvsp[-1].data);
                }
-#line 1713 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1745 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 28:
-#line 276 "dtc-parser.y" /* yacc.c:1646  */
+  case 32:
+#line 302 "dtc-parser.y" /* yacc.c:1646  */
     {
                        (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref));
                }
-#line 1721 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1753 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 29:
-#line 283 "dtc-parser.y" /* yacc.c:1646  */
+  case 33:
+#line 309 "dtc-parser.y" /* yacc.c:1646  */
     {
                        unsigned long long bits;
 
@@ -1737,20 +1769,20 @@ yyreduce:
                        (yyval.array).data = empty_data;
                        (yyval.array).bits = bits;
                }
-#line 1741 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1773 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 30:
-#line 299 "dtc-parser.y" /* yacc.c:1646  */
+  case 34:
+#line 325 "dtc-parser.y" /* yacc.c:1646  */
     {
                        (yyval.array).data = empty_data;
                        (yyval.array).bits = 32;
                }
-#line 1750 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1782 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 31:
-#line 304 "dtc-parser.y" /* yacc.c:1646  */
+  case 35:
+#line 330 "dtc-parser.y" /* yacc.c:1646  */
     {
                        if ((yyvsp[-1].array).bits < 64) {
                                uint64_t mask = (1ULL << (yyvsp[-1].array).bits) - 1;
@@ -1769,11 +1801,11 @@ yyreduce:
 
                        (yyval.array).data = data_append_integer((yyvsp[-1].array).data, (yyvsp[0].integer), (yyvsp[-1].array).bits);
                }
-#line 1773 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1805 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 32:
-#line 323 "dtc-parser.y" /* yacc.c:1646  */
+  case 36:
+#line 349 "dtc-parser.y" /* yacc.c:1646  */
     {
                        uint64_t val = ~0ULL >> (64 - (yyvsp[-1].array).bits);
 
@@ -1787,233 +1819,247 @@ yyreduce:
 
                        (yyval.array).data = data_append_integer((yyvsp[-1].array).data, val, (yyvsp[-1].array).bits);
                }
-#line 1791 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1823 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 33:
-#line 337 "dtc-parser.y" /* yacc.c:1646  */
+  case 37:
+#line 363 "dtc-parser.y" /* yacc.c:1646  */
     {
                        (yyval.array).data = data_add_marker((yyvsp[-1].array).data, LABEL, (yyvsp[0].labelref));
                }
-#line 1799 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1831 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 36:
-#line 346 "dtc-parser.y" /* yacc.c:1646  */
+  case 40:
+#line 372 "dtc-parser.y" /* yacc.c:1646  */
     {
                        (yyval.integer) = (yyvsp[-1].integer);
                }
-#line 1807 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1839 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 39:
-#line 357 "dtc-parser.y" /* yacc.c:1646  */
+  case 43:
+#line 383 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-4].integer) ? (yyvsp[-2].integer) : (yyvsp[0].integer); }
-#line 1813 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1845 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 41:
-#line 362 "dtc-parser.y" /* yacc.c:1646  */
+  case 45:
+#line 388 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) || (yyvsp[0].integer); }
-#line 1819 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1851 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 43:
-#line 367 "dtc-parser.y" /* yacc.c:1646  */
+  case 47:
+#line 393 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) && (yyvsp[0].integer); }
-#line 1825 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1857 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 45:
-#line 372 "dtc-parser.y" /* yacc.c:1646  */
+  case 49:
+#line 398 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) | (yyvsp[0].integer); }
-#line 1831 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1863 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 47:
-#line 377 "dtc-parser.y" /* yacc.c:1646  */
+  case 51:
+#line 403 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) ^ (yyvsp[0].integer); }
-#line 1837 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1869 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 49:
-#line 382 "dtc-parser.y" /* yacc.c:1646  */
+  case 53:
+#line 408 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) & (yyvsp[0].integer); }
-#line 1843 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1875 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 51:
-#line 387 "dtc-parser.y" /* yacc.c:1646  */
+  case 55:
+#line 413 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) == (yyvsp[0].integer); }
-#line 1849 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1881 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 52:
-#line 388 "dtc-parser.y" /* yacc.c:1646  */
+  case 56:
+#line 414 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) != (yyvsp[0].integer); }
-#line 1855 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1887 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 54:
-#line 393 "dtc-parser.y" /* yacc.c:1646  */
+  case 58:
+#line 419 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) < (yyvsp[0].integer); }
-#line 1861 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1893 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 55:
-#line 394 "dtc-parser.y" /* yacc.c:1646  */
+  case 59:
+#line 420 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) > (yyvsp[0].integer); }
-#line 1867 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1899 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 56:
-#line 395 "dtc-parser.y" /* yacc.c:1646  */
+  case 60:
+#line 421 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) <= (yyvsp[0].integer); }
-#line 1873 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1905 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 57:
-#line 396 "dtc-parser.y" /* yacc.c:1646  */
+  case 61:
+#line 422 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) >= (yyvsp[0].integer); }
-#line 1879 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1911 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 58:
-#line 400 "dtc-parser.y" /* yacc.c:1646  */
+  case 62:
+#line 426 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) << (yyvsp[0].integer); }
-#line 1885 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1917 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 59:
-#line 401 "dtc-parser.y" /* yacc.c:1646  */
+  case 63:
+#line 427 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) >> (yyvsp[0].integer); }
-#line 1891 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1923 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 61:
-#line 406 "dtc-parser.y" /* yacc.c:1646  */
+  case 65:
+#line 432 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) + (yyvsp[0].integer); }
-#line 1897 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1929 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 62:
-#line 407 "dtc-parser.y" /* yacc.c:1646  */
+  case 66:
+#line 433 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) - (yyvsp[0].integer); }
-#line 1903 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1935 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 64:
-#line 412 "dtc-parser.y" /* yacc.c:1646  */
+  case 68:
+#line 438 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) * (yyvsp[0].integer); }
-#line 1909 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1941 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 65:
-#line 413 "dtc-parser.y" /* yacc.c:1646  */
-    { (yyval.integer) = (yyvsp[-2].integer) / (yyvsp[0].integer); }
-#line 1915 "dtc-parser.tab.c" /* yacc.c:1646  */
+  case 69:
+#line 440 "dtc-parser.y" /* yacc.c:1646  */
+    {
+                       if ((yyvsp[0].integer) != 0) {
+                               (yyval.integer) = (yyvsp[-2].integer) / (yyvsp[0].integer);
+                       } else {
+                               ERROR(&(yyloc), "Division by zero");
+                               (yyval.integer) = 0;
+                       }
+               }
+#line 1954 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 66:
-#line 414 "dtc-parser.y" /* yacc.c:1646  */
-    { (yyval.integer) = (yyvsp[-2].integer) % (yyvsp[0].integer); }
-#line 1921 "dtc-parser.tab.c" /* yacc.c:1646  */
+  case 70:
+#line 449 "dtc-parser.y" /* yacc.c:1646  */
+    {
+                       if ((yyvsp[0].integer) != 0) {
+                               (yyval.integer) = (yyvsp[-2].integer) % (yyvsp[0].integer);
+                       } else {
+                               ERROR(&(yyloc), "Division by zero");
+                               (yyval.integer) = 0;
+                       }
+               }
+#line 1967 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 69:
-#line 420 "dtc-parser.y" /* yacc.c:1646  */
+  case 73:
+#line 462 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = -(yyvsp[0].integer); }
-#line 1927 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1973 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 70:
-#line 421 "dtc-parser.y" /* yacc.c:1646  */
+  case 74:
+#line 463 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = ~(yyvsp[0].integer); }
-#line 1933 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1979 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 71:
-#line 422 "dtc-parser.y" /* yacc.c:1646  */
+  case 75:
+#line 464 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = !(yyvsp[0].integer); }
-#line 1939 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1985 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 72:
-#line 427 "dtc-parser.y" /* yacc.c:1646  */
+  case 76:
+#line 469 "dtc-parser.y" /* yacc.c:1646  */
     {
                        (yyval.data) = empty_data;
                }
-#line 1947 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1993 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 73:
-#line 431 "dtc-parser.y" /* yacc.c:1646  */
+  case 77:
+#line 473 "dtc-parser.y" /* yacc.c:1646  */
     {
                        (yyval.data) = data_append_byte((yyvsp[-1].data), (yyvsp[0].byte));
                }
-#line 1955 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 2001 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 74:
-#line 435 "dtc-parser.y" /* yacc.c:1646  */
+  case 78:
+#line 477 "dtc-parser.y" /* yacc.c:1646  */
     {
                        (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref));
                }
-#line 1963 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 2009 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 75:
-#line 442 "dtc-parser.y" /* yacc.c:1646  */
+  case 79:
+#line 484 "dtc-parser.y" /* yacc.c:1646  */
     {
                        (yyval.nodelist) = NULL;
                }
-#line 1971 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 2017 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 76:
-#line 446 "dtc-parser.y" /* yacc.c:1646  */
+  case 80:
+#line 488 "dtc-parser.y" /* yacc.c:1646  */
     {
                        (yyval.nodelist) = chain_node((yyvsp[-1].node), (yyvsp[0].nodelist));
                }
-#line 1979 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 2025 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 77:
-#line 450 "dtc-parser.y" /* yacc.c:1646  */
+  case 81:
+#line 492 "dtc-parser.y" /* yacc.c:1646  */
     {
                        ERROR(&(yylsp[0]), "Properties must precede subnodes");
                        YYERROR;
                }
-#line 1988 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 2034 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 78:
-#line 458 "dtc-parser.y" /* yacc.c:1646  */
+  case 82:
+#line 500 "dtc-parser.y" /* yacc.c:1646  */
     {
                        (yyval.node) = name_node((yyvsp[0].node), (yyvsp[-1].propnodename));
                }
-#line 1996 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 2042 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 79:
-#line 462 "dtc-parser.y" /* yacc.c:1646  */
+  case 83:
+#line 504 "dtc-parser.y" /* yacc.c:1646  */
     {
                        (yyval.node) = name_node(build_node_delete(), (yyvsp[-1].propnodename));
                }
-#line 2004 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 2050 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 80:
-#line 466 "dtc-parser.y" /* yacc.c:1646  */
+  case 84:
+#line 508 "dtc-parser.y" /* yacc.c:1646  */
     {
                        add_label(&(yyvsp[0].node)->labels, (yyvsp[-1].labelref));
                        (yyval.node) = (yyvsp[0].node);
                }
-#line 2013 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 2059 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
 
-#line 2017 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 2063 "dtc-parser.tab.c" /* yacc.c:1646  */
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
@@ -2248,7 +2294,7 @@ yyreturn:
 #endif
   return yyresult;
 }
-#line 472 "dtc-parser.y" /* yacc.c:1906  */
+#line 514 "dtc-parser.y" /* yacc.c:1906  */
 
 
 void yyerror(char const *s)
index 30867c6..6aa512c 100644 (file)
@@ -1,8 +1,8 @@
-/* A Bison parser, made by GNU Bison 3.0.2.  */
+/* A Bison parser, made by GNU Bison 3.0.4.  */
 
 /* Bison interface for Yacc-like parsers in C
 
-   Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
+   Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -46,35 +46,36 @@ extern int yydebug;
   enum yytokentype
   {
     DT_V1 = 258,
-    DT_MEMRESERVE = 259,
-    DT_LSHIFT = 260,
-    DT_RSHIFT = 261,
-    DT_LE = 262,
-    DT_GE = 263,
-    DT_EQ = 264,
-    DT_NE = 265,
-    DT_AND = 266,
-    DT_OR = 267,
-    DT_BITS = 268,
-    DT_DEL_PROP = 269,
-    DT_DEL_NODE = 270,
-    DT_PROPNODENAME = 271,
-    DT_LITERAL = 272,
-    DT_CHAR_LITERAL = 273,
-    DT_BYTE = 274,
-    DT_STRING = 275,
-    DT_LABEL = 276,
-    DT_REF = 277,
-    DT_INCBIN = 278
+    DT_PLUGIN = 259,
+    DT_MEMRESERVE = 260,
+    DT_LSHIFT = 261,
+    DT_RSHIFT = 262,
+    DT_LE = 263,
+    DT_GE = 264,
+    DT_EQ = 265,
+    DT_NE = 266,
+    DT_AND = 267,
+    DT_OR = 268,
+    DT_BITS = 269,
+    DT_DEL_PROP = 270,
+    DT_DEL_NODE = 271,
+    DT_PROPNODENAME = 272,
+    DT_LITERAL = 273,
+    DT_CHAR_LITERAL = 274,
+    DT_BYTE = 275,
+    DT_STRING = 276,
+    DT_LABEL = 277,
+    DT_REF = 278,
+    DT_INCBIN = 279
   };
 #endif
 
 /* Value type.  */
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE YYSTYPE;
+
 union YYSTYPE
 {
-#line 38 "dtc-parser.y" /* yacc.c:1909  */
+#line 39 "dtc-parser.y" /* yacc.c:1909  */
 
        char *propnodename;
        char *labelref;
@@ -92,9 +93,12 @@ union YYSTYPE
        struct node *nodelist;
        struct reserve_info *re;
        uint64_t integer;
+       unsigned int flags;
 
-#line 97 "dtc-parser.tab.h" /* yacc.c:1909  */
+#line 99 "dtc-parser.tab.h" /* yacc.c:1909  */
 };
+
+typedef union YYSTYPE YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define YYSTYPE_IS_DECLARED 1
 #endif
index 5a897e3..b2fd4d1 100644 (file)
@@ -19,6 +19,7 @@
  */
 %{
 #include <stdio.h>
+#include <inttypes.h>
 
 #include "dtc.h"
 #include "srcpos.h"
@@ -31,7 +32,7 @@ extern void yyerror(char const *s);
                treesource_error = true; \
        } while (0)
 
-extern struct boot_info *the_boot_info;
+extern struct dt_info *parser_output;
 extern bool treesource_error;
 %}
 
@@ -52,9 +53,11 @@ extern bool treesource_error;
        struct node *nodelist;
        struct reserve_info *re;
        uint64_t integer;
+       unsigned int flags;
 }
 
 %token DT_V1
+%token DT_PLUGIN
 %token DT_MEMRESERVE
 %token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR
 %token DT_BITS
@@ -71,6 +74,8 @@ extern bool treesource_error;
 
 %type <data> propdata
 %type <data> propdataprefix
+%type <flags> header
+%type <flags> headers
 %type <re> memreserve
 %type <re> memreserves
 %type <array> arrayprefix
@@ -101,10 +106,31 @@ extern bool treesource_error;
 %%
 
 sourcefile:
-         DT_V1 ';' memreserves devicetree
+         headers memreserves devicetree
                {
-                       the_boot_info = build_boot_info($3, $4,
-                                                       guess_boot_cpuid($4));
+                       parser_output = build_dt_info($1, $2, $3,
+                                                     guess_boot_cpuid($3));
+               }
+       ;
+
+header:
+         DT_V1 ';'
+               {
+                       $$ = DTSF_V1;
+               }
+       | DT_V1 ';' DT_PLUGIN ';'
+               {
+                       $$ = DTSF_V1 | DTSF_PLUGIN;
+               }
+       ;
+
+headers:
+         header
+       | header headers
+               {
+                       if ($2 != $1)
+                               ERROR(&@2, "Header flags don't match earlier ones");
+                       $$ = $1;
                }
        ;
 
@@ -410,8 +436,24 @@ integer_add:
 
 integer_mul:
          integer_mul '*' integer_unary { $$ = $1 * $3; }
-       | integer_mul '/' integer_unary { $$ = $1 / $3; }
-       | integer_mul '%' integer_unary { $$ = $1 % $3; }
+       | integer_mul '/' integer_unary
+               {
+                       if ($3 != 0) {
+                               $$ = $1 / $3;
+                       } else {
+                               ERROR(&@$, "Division by zero");
+                               $$ = 0;
+                       }
+               }
+       | integer_mul '%' integer_unary
+               {
+                       if ($3 != 0) {
+                               $$ = $1 % $3;
+                       } else {
+                               ERROR(&@$, "Division by zero");
+                               $$ = 0;
+                       }
+               }
        | integer_unary
        ;
 
index 8c4add6..a4edf4c 100644 (file)
@@ -18,6 +18,8 @@
  *                                                                   USA
  */
 
+#include <sys/stat.h>
+
 #include "dtc.h"
 #include "srcpos.h"
 
@@ -28,7 +30,16 @@ int quiet;           /* Level of quietness */
 int reservenum;                /* Number of memory reservation slots */
 int minsize;           /* Minimum blob size */
 int padsize;           /* Additional padding to blob */
+int alignsize;         /* Additional padding to blob accroding to the alignsize */
 int phandle_format = PHANDLE_BOTH;     /* Use linux,phandle or phandle properties */
+int generate_symbols;  /* enable symbols & fixup support */
+int generate_fixups;           /* suppress generation of fixups on symbol support */
+int auto_label_aliases;                /* auto generate labels -> aliases */
+
+static int is_power_of_2(int x)
+{
+       return (x > 0) && ((x & (x - 1)) == 0);
+}
 
 static void fill_fullpaths(struct node *tree, const char *prefix)
 {
@@ -51,7 +62,7 @@ static void fill_fullpaths(struct node *tree, const char *prefix)
 #define FDT_VERSION(version)   _FDT_VERSION(version)
 #define _FDT_VERSION(version)  #version
 static const char usage_synopsis[] = "dtc [options] <input file>";
-static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:hv";
+static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@Ahv";
 static struct option const usage_long_opts[] = {
        {"quiet",            no_argument, NULL, 'q'},
        {"in-format",         a_argument, NULL, 'I'},
@@ -62,6 +73,7 @@ static struct option const usage_long_opts[] = {
        {"reserve",           a_argument, NULL, 'R'},
        {"space",             a_argument, NULL, 'S'},
        {"pad",               a_argument, NULL, 'p'},
+       {"align",             a_argument, NULL, 'a'},
        {"boot-cpu",          a_argument, NULL, 'b'},
        {"force",            no_argument, NULL, 'f'},
        {"include",           a_argument, NULL, 'i'},
@@ -69,6 +81,8 @@ static struct option const usage_long_opts[] = {
        {"phandle",           a_argument, NULL, 'H'},
        {"warning",           a_argument, NULL, 'W'},
        {"error",             a_argument, NULL, 'E'},
+       {"symbols",          no_argument, NULL, '@'},
+       {"auto-alias",       no_argument, NULL, 'A'},
        {"help",             no_argument, NULL, 'h'},
        {"version",          no_argument, NULL, 'v'},
        {NULL,               no_argument, NULL, 0x0},
@@ -89,6 +103,7 @@ static const char * const usage_opts_help[] = {
        "\n\tMake space for <number> reserve map entries (for dtb and asm output)",
        "\n\tMake the blob at least <bytes> long (extra space)",
        "\n\tAdd padding to the blob of <bytes> long (extra space)",
+       "\n\tMake the blob align to the <bytes> (extra space)",
        "\n\tSet the physical boot cpu",
        "\n\tTry to produce output even if the input tree has errors",
        "\n\tAdd a path to search for include files",
@@ -99,16 +114,63 @@ static const char * const usage_opts_help[] = {
         "\t\tboth   - Both \"linux,phandle\" and \"phandle\" properties",
        "\n\tEnable/disable warnings (prefix with \"no-\")",
        "\n\tEnable/disable errors (prefix with \"no-\")",
+       "\n\tEnable generation of symbols",
+       "\n\tEnable auto-alias of labels",
        "\n\tPrint this help and exit",
        "\n\tPrint version and exit",
        NULL,
 };
 
+static const char *guess_type_by_name(const char *fname, const char *fallback)
+{
+       const char *s;
+
+       s = strrchr(fname, '.');
+       if (s == NULL)
+               return fallback;
+       if (!strcasecmp(s, ".dts"))
+               return "dts";
+       if (!strcasecmp(s, ".dtb"))
+               return "dtb";
+       return fallback;
+}
+
+static const char *guess_input_format(const char *fname, const char *fallback)
+{
+       struct stat statbuf;
+       uint32_t magic;
+       FILE *f;
+
+       if (stat(fname, &statbuf) != 0)
+               return fallback;
+
+       if (S_ISDIR(statbuf.st_mode))
+               return "fs";
+
+       if (!S_ISREG(statbuf.st_mode))
+               return fallback;
+
+       f = fopen(fname, "r");
+       if (f == NULL)
+               return fallback;
+       if (fread(&magic, 4, 1, f) != 1) {
+               fclose(f);
+               return fallback;
+       }
+       fclose(f);
+
+       magic = fdt32_to_cpu(magic);
+       if (magic == FDT_MAGIC)
+               return "dtb";
+
+       return guess_type_by_name(fname, fallback);
+}
+
 int main(int argc, char *argv[])
 {
-       struct boot_info *bi;
-       const char *inform = "dts";
-       const char *outform = "dts";
+       struct dt_info *dti;
+       const char *inform = NULL;
+       const char *outform = NULL;
        const char *outname = "-";
        const char *depname = NULL;
        bool force = false, sort = false;
@@ -122,6 +184,7 @@ int main(int argc, char *argv[])
        reservenum = 0;
        minsize    = 0;
        padsize    = 0;
+       alignsize  = 0;
 
        while ((opt = util_getopt_long()) != EOF) {
                switch (opt) {
@@ -149,6 +212,12 @@ int main(int argc, char *argv[])
                case 'p':
                        padsize = strtol(optarg, NULL, 0);
                        break;
+               case 'a':
+                       alignsize = strtol(optarg, NULL, 0);
+                       if (!is_power_of_2(alignsize))
+                               die("Invalid argument \"%d\" to -a option\n",
+                                   optarg);
+                       break;
                case 'f':
                        force = true;
                        break;
@@ -187,6 +256,13 @@ int main(int argc, char *argv[])
                        parse_checks_option(false, true, optarg);
                        break;
 
+               case '@':
+                       generate_symbols = 1;
+                       break;
+               case 'A':
+                       auto_label_aliases = 1;
+                       break;
+
                case 'h':
                        usage(NULL);
                default:
@@ -213,12 +289,23 @@ int main(int argc, char *argv[])
                fprintf(depfile, "%s:", outname);
        }
 
+       if (inform == NULL)
+               inform = guess_input_format(arg, "dts");
+       if (outform == NULL) {
+               outform = guess_type_by_name(outname, NULL);
+               if (outform == NULL) {
+                       if (streq(inform, "dts"))
+                               outform = "dtb";
+                       else
+                               outform = "dts";
+               }
+       }
        if (streq(inform, "dts"))
-               bi = dt_from_source(arg);
+               dti = dt_from_source(arg);
        else if (streq(inform, "fs"))
-               bi = dt_from_fs(arg);
+               dti = dt_from_fs(arg);
        else if(streq(inform, "dtb"))
-               bi = dt_from_blob(arg);
+               dti = dt_from_blob(arg);
        else
                die("Unknown input format \"%s\"\n", inform);
 
@@ -228,13 +315,29 @@ int main(int argc, char *argv[])
        }
 
        if (cmdline_boot_cpuid != -1)
-               bi->boot_cpuid_phys = cmdline_boot_cpuid;
+               dti->boot_cpuid_phys = cmdline_boot_cpuid;
+
+       fill_fullpaths(dti->dt, "");
+       process_checks(force, dti);
+
+       /* on a plugin, generate by default */
+       if (dti->dtsflags & DTSF_PLUGIN) {
+               generate_fixups = 1;
+       }
+
+       if (auto_label_aliases)
+               generate_label_tree(dti, "aliases", false);
 
-       fill_fullpaths(bi->dt, "");
-       process_checks(force, bi);
+       if (generate_symbols)
+               generate_label_tree(dti, "__symbols__", true);
+
+       if (generate_fixups) {
+               generate_fixups_tree(dti, "__fixups__");
+               generate_local_fixups_tree(dti, "__local_fixups__");
+       }
 
        if (sort)
-               sort_tree(bi);
+               sort_tree(dti);
 
        if (streq(outname, "-")) {
                outf = stdout;
@@ -246,11 +349,11 @@ int main(int argc, char *argv[])
        }
 
        if (streq(outform, "dts")) {
-               dt_to_source(outf, bi);
+               dt_to_source(outf, dti);
        } else if (streq(outform, "dtb")) {
-               dt_to_blob(outf, bi, outversion);
+               dt_to_blob(outf, dti, outversion);
        } else if (streq(outform, "asm")) {
-               dt_to_asm(outf, bi, outversion);
+               dt_to_asm(outf, dti, outversion);
        } else if (streq(outform, "null")) {
                /* do nothing */
        } else {
index 56212c8..c6f125c 100644 (file)
@@ -53,7 +53,11 @@ extern int quiet;            /* Level of quietness */
 extern int reservenum;         /* Number of memory reservation slots */
 extern int minsize;            /* Minimum blob size */
 extern int padsize;            /* Additional padding to blob */
+extern int alignsize;          /* Additional padding to blob accroding to the alignsize */
 extern int phandle_format;     /* Use linux,phandle or phandle properties */
+extern int generate_symbols;   /* generate symbols for nodes with labels */
+extern int generate_fixups;    /* generate fixups */
+extern int auto_label_aliases; /* auto generate labels -> aliases */
 
 #define PHANDLE_LEGACY 0x1
 #define PHANDLE_EPAPR  0x2
@@ -201,6 +205,8 @@ void delete_property(struct property *prop);
 void add_child(struct node *parent, struct node *child);
 void delete_node_by_name(struct node *parent, char *name);
 void delete_node(struct node *node);
+void append_to_property(struct node *node,
+                       char *name, const void *data, int len);
 
 const char *get_unitname(struct node *node);
 struct property *get_property(struct node *node, const char *propname);
@@ -235,35 +241,44 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list,
                                       struct reserve_info *new);
 
 
-struct boot_info {
+struct dt_info {
+       unsigned int dtsflags;
        struct reserve_info *reservelist;
-       struct node *dt;                /* the device tree */
        uint32_t boot_cpuid_phys;
+       struct node *dt;                /* the device tree */
 };
 
-struct boot_info *build_boot_info(struct reserve_info *reservelist,
-                                 struct node *tree, uint32_t boot_cpuid_phys);
-void sort_tree(struct boot_info *bi);
+/* DTS version flags definitions */
+#define DTSF_V1                0x0001  /* /dts-v1/ */
+#define DTSF_PLUGIN    0x0002  /* /plugin/ */
+
+struct dt_info *build_dt_info(unsigned int dtsflags,
+                             struct reserve_info *reservelist,
+                             struct node *tree, uint32_t boot_cpuid_phys);
+void sort_tree(struct dt_info *dti);
+void generate_label_tree(struct dt_info *dti, char *name, bool allocph);
+void generate_fixups_tree(struct dt_info *dti, char *name);
+void generate_local_fixups_tree(struct dt_info *dti, char *name);
 
 /* Checks */
 
 void parse_checks_option(bool warn, bool error, const char *arg);
-void process_checks(bool force, struct boot_info *bi);
+void process_checks(bool force, struct dt_info *dti);
 
 /* Flattened trees */
 
-void dt_to_blob(FILE *f, struct boot_info *bi, int version);
-void dt_to_asm(FILE *f, struct boot_info *bi, int version);
+void dt_to_blob(FILE *f, struct dt_info *dti, int version);
+void dt_to_asm(FILE *f, struct dt_info *dti, int version);
 
-struct boot_info *dt_from_blob(const char *fname);
+struct dt_info *dt_from_blob(const char *fname);
 
 /* Tree source */
 
-void dt_to_source(FILE *f, struct boot_info *bi);
-struct boot_info *dt_from_source(const char *f);
+void dt_to_source(FILE *f, struct dt_info *dti);
+struct dt_info *dt_from_source(const char *f);
 
 /* FS trees */
 
-struct boot_info *dt_from_fs(const char *dirname);
+struct dt_info *dt_from_fs(const char *dirname);
 
 #endif /* _DTC_H */
diff --git a/scripts/dtc/dtx_diff b/scripts/dtc/dtx_diff
new file mode 100755 (executable)
index 0000000..ec47f95
--- /dev/null
@@ -0,0 +1,349 @@
+#! /bin/bash
+
+# Copyright (C) 2015 Frank Rowand
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+
+
+usage() {
+
+       # use spaces instead of tabs in the usage message
+       cat >&2 <<eod
+
+Usage:
+
+   `basename $0` DTx
+        decompile DTx
+
+   `basename $0` DTx_1 DTx_2
+        diff DTx_1 and DTx_2
+
+
+       -f           print full dts in diff (--unified=99999)
+       -h           synonym for --help
+       -help        synonym for --help
+      --help        print this message and exit
+       -s SRCTREE   linux kernel source tree is at path SRCTREE
+                        (default is current directory)
+       -S           linux kernel source tree is at root of current git repo
+       -u           unsorted, do not sort DTx
+
+
+Each DTx is processed by the dtc compiler to produce a sorted dts source
+file.  If DTx is a dts source file then it is pre-processed in the same
+manner as done for the compile of the dts source file in the Linux kernel
+build system ('#include' and '/include/' directives are processed).
+
+If two DTx are provided, the resulting dts source files are diffed.
+
+If DTx is a directory, it is treated as a DT subtree, such as
+  /proc/device-tree.
+
+If DTx contains the binary blob magic value in the first four bytes,
+  it is treated as a binary blob (aka .dtb or FDT).
+
+Otherwise DTx is treated as a dts source file (aka .dts).
+
+   If this script is not run from the root of the linux source tree,
+   and DTx utilizes '#include' or '/include/' then the path of the
+   linux source tree can be provided by '-s SRCTREE' or '-S' so that
+   include paths will be set properly.
+
+   The shell variable \${ARCH} must provide the architecture containing
+   the dts source file for include paths to be set properly for '#include'
+   or '/include/' to be processed.
+
+   If DTx_1 and DTx_2 are in different architectures, then this script
+   may not work since \${ARCH} is part of the include path.  Two possible
+   workarounds:
+
+      `basename $0` \\
+          <(ARCH=arch_of_dtx_1 `basename $0` DTx_1) \\
+          <(ARCH=arch_of_dtx_2 `basename $0` DTx_2)
+
+      `basename $0` ARCH=arch_of_dtx_1 DTx_1 >tmp_dtx_1.dts
+      `basename $0` ARCH=arch_of_dtx_2 DTx_2 >tmp_dtx_2.dts
+      `basename $0` tmp_dtx_1.dts tmp_dtx_2.dts
+      rm tmp_dtx_1.dts tmp_dtx_2.dts
+
+   If DTx_1 and DTx_2 are in different directories, then this script will
+   add the path of DTx_1 and DTx_2 to the include paths.  If DTx_2 includes
+   a local file that exists in both the path of DTx_1 and DTx_2 then the
+   file in the path of DTx_1 will incorrectly be included.  Possible
+   workaround:
+
+      `basename $0` DTx_1 >tmp_dtx_1.dts
+      `basename $0` DTx_2 >tmp_dtx_2.dts
+      `basename $0` tmp_dtx_1.dts tmp_dtx_2.dts
+      rm tmp_dtx_1.dts tmp_dtx_2.dts
+
+eod
+}
+
+
+compile_to_dts() {
+
+       dtx="$1"
+
+       if [ -d "${dtx}" ] ; then
+
+               # -----  input is file tree
+
+               if ( ! ${DTC} -I fs ${dtx} ) ; then
+                       exit 3
+               fi
+
+       elif [ -f "${dtx}" ] && [ -r "${dtx}" ] ; then
+
+               magic=`hexdump -n 4 -e '/1 "%02x"' ${dtx}`
+               if [ "${magic}" = "d00dfeed" ] ; then
+
+                       # -----  input is FDT (binary blob)
+
+                       if ( ! ${DTC} -I dtb ${dtx} ) ; then
+                               exit 3
+                       fi
+
+                       return
+
+               fi
+
+               # -----  input is DTS (source)
+
+               if ( cpp ${cpp_flags} -x assembler-with-cpp ${dtx} \
+                       | ${DTC} -I dts ) ; then
+                       return
+               fi
+
+               echo ""                                                      >&2
+               echo "Possible hints to resolve the above error:"            >&2
+               echo "  (hints might not fix the problem)"                   >&2
+
+               hint_given=0
+
+               if [ "${ARCH}" = "" ] ; then
+                       hint_given=1
+                       echo ""                                              >&2
+                       echo "  shell variable \$ARCH not set"               >&2
+               fi
+
+               dtx_arch=`echo "/${dtx}" | sed -e 's|.*/arch/||' -e 's|/.*||'`
+
+               if [ "${dtx_arch}" != ""  -a "${dtx_arch}" != "${ARCH}" ] ; then
+                       hint_given=1
+                       echo ""                                              >&2
+                       echo "  architecture ${dtx_arch} is in file path,"   >&2
+                       echo "  but does not match shell variable \$ARCH"    >&2
+                       echo "  >>\$ARCH<< is: >>${ARCH}<<"                  >&2
+               fi
+
+               if [ ! -d ${srctree}/arch/${ARCH} ] ; then
+                       hint_given=1
+                       echo ""                                              >&2
+                       echo "  ${srctree}/arch/${ARCH}/ does not exist"     >&2
+                       echo "  Is \$ARCH='${ARCH}' correct?"                >&2
+                       echo "  Possible fix: use '-s' option"               >&2
+
+                       git_root=`git rev-parse --show-toplevel 2>/dev/null`
+                       if [ -d ${git_root}/arch/ ] ; then
+                               echo "  Possible fix: use '-S' option"       >&2
+                       fi
+               fi
+
+               if [ $hint_given = 0 ] ; then
+                       echo ""                                              >&2
+                       echo "  No hints available."                         >&2
+               fi
+
+               echo ""                                                      >&2
+
+               exit 3
+
+       else
+               echo ""                                                     >&2
+               echo "ERROR: ${dtx} does not exist or is not readable"      >&2
+               echo ""                                                     >&2
+               exit 2
+       fi
+
+}
+
+
+# -----  start of script
+
+cmd_diff=0
+diff_flags="-u"
+dtx_file_1=""
+dtx_file_2=""
+dtc_sort="-s"
+help=0
+srctree=""
+
+
+while [ $# -gt 0 ] ; do
+
+       case $1 in
+
+       -f )
+               diff_flags="--unified=999999"
+               shift
+               ;;
+
+       -h | -help | --help )
+               help=1
+               shift
+               ;;
+
+       -s )
+               srctree="$2"
+               shift 2
+               ;;
+
+       -S )
+               git_root=`git rev-parse --show-toplevel 2>/dev/null`
+               srctree="${git_root}"
+               shift
+               ;;
+
+       -u )
+               dtc_sort=""
+               shift
+               ;;
+
+       *)
+               if [ "${dtx_file_1}"  = "" ] ; then
+                       dtx_file_1="$1"
+               elif [ "${dtx_file_2}" = "" ] ; then
+                       dtx_file_2="$1"
+               else
+                       echo ""                                             >&2
+                       echo "ERROR: Unexpected parameter: $1"              >&2
+                       echo ""                                             >&2
+                       exit 2
+               fi
+               shift
+               ;;
+
+       esac
+
+done
+
+if [ "${srctree}" = "" ] ; then
+       srctree="."
+fi
+
+if [ "${dtx_file_2}" != "" ]; then
+       cmd_diff=1
+fi
+
+if (( ${help} )) ; then
+       usage
+       exit 1
+fi
+
+# this must follow check for ${help}
+if [ "${dtx_file_1}" = "" ]; then
+       echo ""                                                             >&2
+       echo "ERROR: parameter DTx required"                                >&2
+       echo ""                                                             >&2
+       exit 2
+fi
+
+
+# -----  prefer dtc from linux kernel, allow fallback to dtc in $PATH
+
+if [ "${KBUILD_OUTPUT:0:2}" = ".." ] ; then
+       __KBUILD_OUTPUT="${srctree}/${KBUILD_OUTPUT}"
+elif [ "${KBUILD_OUTPUT}" = "" ] ; then
+       __KBUILD_OUTPUT="."
+else
+       __KBUILD_OUTPUT="${KBUILD_OUTPUT}"
+fi
+
+DTC="${__KBUILD_OUTPUT}/scripts/dtc/dtc"
+
+if [ ! -x ${DTC} ] ; then
+       __DTC="dtc"
+       if grep -q "^CONFIG_DTC=y" ${__KBUILD_OUTPUT}/.config 2>/dev/null; then
+               make_command='
+         make scripts'
+       else
+               make_command='
+         Enable CONFIG_DTC in the kernel configuration
+         make scripts'
+       fi
+       if ( ! which ${__DTC} >/dev/null ) ; then
+
+               # use spaces instead of tabs in the error message
+               cat >&2 <<eod
+
+ERROR: unable to find a 'dtc' program
+
+   Preferred 'dtc' (built from Linux kernel source tree) was not found or
+   is not executable.
+
+      'dtc' is: ${DTC}
+
+      If it does not exist, create it from the root of the Linux source tree:
+${make_command}
+
+      If not at the root of the Linux kernel source tree -s SRCTREE or -S
+      may need to be specified to find 'dtc'.
+
+      If 'O=\${dir}' is specified in your Linux builds, this script requires
+      'export KBUILD_OUTPUT=\${dir}' or add \${dir}/scripts/dtc to \$PATH
+      before running.
+
+      If \${KBUILD_OUTPUT} is a relative path, then '-s SRCDIR', -S, or run
+      this script from the root of the Linux kernel source tree is required.
+
+   Fallback '${__DTC}' was also not in \${PATH} or is not executable.
+
+eod
+               exit 2
+       fi
+       DTC=${__DTC}
+fi
+
+
+# -----  cpp and dtc flags same as for linux source tree build of .dtb files,
+#        plus directories of the dtx file(s)
+
+dtx_path_1_dtc_include="-i `dirname ${dtx_file_1}`"
+
+dtx_path_2_dtc_include=""
+if (( ${cmd_diff} )) ; then
+       dtx_path_2_dtc_include="-i `dirname ${dtx_file_2}`"
+fi
+
+cpp_flags="\
+       -nostdinc                                  \
+       -I${srctree}/arch/${ARCH}/boot/dts         \
+       -I${srctree}/arch/${ARCH}/boot/dts/include \
+       -I${srctree}/drivers/of/testcase-data      \
+       -undef -D__DTS__"
+
+dtc_flags="\
+       -i ${srctree}/arch/${ARCH}/boot/dts/ \
+       -i ${srctree}/kernel/dts             \
+       ${dtx_path_1_dtc_include}            \
+       ${dtx_path_2_dtc_include}"
+
+DTC="${DTC} ${dtc_flags} -O dts -qq -f ${dtc_sort} -o -"
+
+
+# -----  do the diff or decompile
+
+if (( ${cmd_diff} )) ; then
+
+       diff ${diff_flags} \
+               <(compile_to_dts "${dtx_file_1}") \
+               <(compile_to_dts "${dtx_file_2}")
+
+else
+
+       compile_to_dts "${dtx_file_1}"
+
+fi
index bd99fa2..ebac548 100644 (file)
@@ -366,7 +366,7 @@ static void make_fdt_header(struct fdt_header *fdt,
                fdt->size_dt_struct = cpu_to_fdt32(dtsize);
 }
 
-void dt_to_blob(FILE *f, struct boot_info *bi, int version)
+void dt_to_blob(FILE *f, struct dt_info *dti, int version)
 {
        struct version_info *vi = NULL;
        int i;
@@ -384,29 +384,36 @@ void dt_to_blob(FILE *f, struct boot_info *bi, int version)
        if (!vi)
                die("Unknown device tree blob version %d\n", version);
 
-       flatten_tree(bi->dt, &bin_emitter, &dtbuf, &strbuf, vi);
+       flatten_tree(dti->dt, &bin_emitter, &dtbuf, &strbuf, vi);
        bin_emit_cell(&dtbuf, FDT_END);
 
-       reservebuf = flatten_reserve_list(bi->reservelist, vi);
+       reservebuf = flatten_reserve_list(dti->reservelist, vi);
 
        /* Make header */
        make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len,
-                       bi->boot_cpuid_phys);
+                       dti->boot_cpuid_phys);
 
        /*
         * If the user asked for more space than is used, adjust the totalsize.
         */
        if (minsize > 0) {
                padlen = minsize - fdt32_to_cpu(fdt.totalsize);
-               if ((padlen < 0) && (quiet < 1))
-                       fprintf(stderr,
-                               "Warning: blob size %d >= minimum size %d\n",
-                               fdt32_to_cpu(fdt.totalsize), minsize);
+               if (padlen < 0) {
+                       padlen = 0;
+                       if (quiet < 1)
+                               fprintf(stderr,
+                                       "Warning: blob size %d >= minimum size %d\n",
+                                       fdt32_to_cpu(fdt.totalsize), minsize);
+               }
        }
 
        if (padsize > 0)
                padlen = padsize;
 
+       if (alignsize > 0)
+               padlen = ALIGN(fdt32_to_cpu(fdt.totalsize) + padlen, alignsize)
+                       - fdt32_to_cpu(fdt.totalsize);
+
        if (padlen > 0) {
                int tsize = fdt32_to_cpu(fdt.totalsize);
                tsize += padlen;
@@ -460,7 +467,7 @@ static void dump_stringtable_asm(FILE *f, struct data strbuf)
        }
 }
 
-void dt_to_asm(FILE *f, struct boot_info *bi, int version)
+void dt_to_asm(FILE *f, struct dt_info *dti, int version)
 {
        struct version_info *vi = NULL;
        int i;
@@ -500,7 +507,7 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version)
 
        if (vi->flags & FTF_BOOTCPUID) {
                fprintf(f, "\t/* boot_cpuid_phys */\n");
-               asm_emit_cell(f, bi->boot_cpuid_phys);
+               asm_emit_cell(f, dti->boot_cpuid_phys);
        }
 
        if (vi->flags & FTF_STRTABSIZE) {
@@ -530,7 +537,7 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version)
         * Use .long on high and low halfs of u64s to avoid .quad
         * as it appears .quad isn't available in some assemblers.
         */
-       for (re = bi->reservelist; re; re = re->next) {
+       for (re = dti->reservelist; re; re = re->next) {
                struct label *l;
 
                for_each_label(re->labels, l) {
@@ -550,7 +557,7 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version)
        fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");
 
        emit_label(f, symprefix, "struct_start");
-       flatten_tree(bi->dt, &asm_emitter, f, &strbuf, vi);
+       flatten_tree(dti->dt, &asm_emitter, f, &strbuf, vi);
 
        fprintf(f, "\t/* FDT_END */\n");
        asm_emit_cell(f, FDT_END);
@@ -572,6 +579,8 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version)
        if (padsize > 0) {
                fprintf(f, "\t.space\t%d, 0\n", padsize);
        }
+       if (alignsize > 0)
+               asm_emit_align(f, alignsize);
        emit_label(f, symprefix, "blob_abs_end");
 
        data_free(strbuf);
@@ -797,11 +806,15 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
                }
        } while (val != FDT_END_NODE);
 
+       if (node->name != flatname) {
+               free(flatname);
+       }
+
        return node;
 }
 
 
-struct boot_info *dt_from_blob(const char *fname)
+struct dt_info *dt_from_blob(const char *fname)
 {
        FILE *f;
        uint32_t magic, totalsize, version, size_dt, boot_cpuid_phys;
@@ -889,7 +902,7 @@ struct boot_info *dt_from_blob(const char *fname)
 
        if (version >= 3) {
                uint32_t size_str = fdt32_to_cpu(fdt->size_dt_strings);
-               if (off_str+size_str > totalsize)
+               if ((off_str+size_str < off_str) || (off_str+size_str > totalsize))
                        die("String table extends past total size\n");
                inbuf_init(&strbuf, blob + off_str, blob + off_str + size_str);
        } else {
@@ -898,7 +911,7 @@ struct boot_info *dt_from_blob(const char *fname)
 
        if (version >= 17) {
                size_dt = fdt32_to_cpu(fdt->size_dt_struct);
-               if (off_dt+size_dt > totalsize)
+               if ((off_dt+size_dt < off_dt) || (off_dt+size_dt > totalsize))
                        die("Structure block extends past total size\n");
        }
 
@@ -929,5 +942,5 @@ struct boot_info *dt_from_blob(const char *fname)
 
        fclose(f);
 
-       return build_boot_info(reservelist, tree, boot_cpuid_phys);
+       return build_dt_info(DTSF_V1, reservelist, tree, boot_cpuid_phys);
 }
index 6d1beec..ae7d06c 100644 (file)
@@ -79,13 +79,12 @@ static struct node *read_fstree(const char *dirname)
        return tree;
 }
 
-struct boot_info *dt_from_fs(const char *dirname)
+struct dt_info *dt_from_fs(const char *dirname)
 {
        struct node *tree;
 
        tree = read_fstree(dirname);
        tree = name_node(tree, "");
 
-       return build_boot_info(NULL, tree, guess_boot_cpuid(tree));
+       return build_dt_info(DTSF_V1, NULL, tree, guess_boot_cpuid(tree));
 }
-
index 09c322e..098b3f3 100644 (file)
@@ -7,5 +7,5 @@ LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1
 LIBFDT_INCLUDES = fdt.h libfdt.h libfdt_env.h
 LIBFDT_VERSION = version.lds
 LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c \
-       fdt_addresses.c
+       fdt_addresses.c fdt_overlay.c
 LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o)
index d96ed24..14fb793 100644 (file)
@@ -90,18 +90,19 @@ int fdt_check_header(const void *fdt)
 
 const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
 {
-       const char *p;
+       unsigned absoffset = offset + fdt_off_dt_struct(fdt);
+
+       if ((absoffset < offset)
+           || ((absoffset + len) < absoffset)
+           || (absoffset + len) > fdt_totalsize(fdt))
+               return NULL;
 
        if (fdt_version(fdt) >= 0x11)
                if (((offset + len) < offset)
                    || ((offset + len) > fdt_size_dt_struct(fdt)))
                        return NULL;
 
-       p = _fdt_offset_ptr(fdt, offset);
-
-       if (p + len < p)
-               return NULL;
-       return p;
+       return _fdt_offset_ptr(fdt, offset);
 }
 
 uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
index a65e4b5..3d00d2e 100644 (file)
@@ -88,6 +88,32 @@ static int _fdt_string_eq(const void *fdt, int stroffset,
        return (strlen(p) == len) && (memcmp(p, s, len) == 0);
 }
 
+uint32_t fdt_get_max_phandle(const void *fdt)
+{
+       uint32_t max_phandle = 0;
+       int offset;
+
+       for (offset = fdt_next_node(fdt, -1, NULL);;
+            offset = fdt_next_node(fdt, offset, NULL)) {
+               uint32_t phandle;
+
+               if (offset == -FDT_ERR_NOTFOUND)
+                       return max_phandle;
+
+               if (offset < 0)
+                       return (uint32_t)-1;
+
+               phandle = fdt_get_phandle(fdt, offset);
+               if (phandle == (uint32_t)-1)
+                       continue;
+
+               if (phandle > max_phandle)
+                       max_phandle = phandle;
+       }
+
+       return 0;
+}
+
 int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
 {
        FDT_CHECK_HEADER(fdt);
@@ -538,6 +564,106 @@ int fdt_stringlist_contains(const char *strlist, int listlen, const char *str)
        return 0;
 }
 
+int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property)
+{
+       const char *list, *end;
+       int length, count = 0;
+
+       list = fdt_getprop(fdt, nodeoffset, property, &length);
+       if (!list)
+               return length;
+
+       end = list + length;
+
+       while (list < end) {
+               length = strnlen(list, end - list) + 1;
+
+               /* Abort if the last string isn't properly NUL-terminated. */
+               if (list + length > end)
+                       return -FDT_ERR_BADVALUE;
+
+               list += length;
+               count++;
+       }
+
+       return count;
+}
+
+int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
+                         const char *string)
+{
+       int length, len, idx = 0;
+       const char *list, *end;
+
+       list = fdt_getprop(fdt, nodeoffset, property, &length);
+       if (!list)
+               return length;
+
+       len = strlen(string) + 1;
+       end = list + length;
+
+       while (list < end) {
+               length = strnlen(list, end - list) + 1;
+
+               /* Abort if the last string isn't properly NUL-terminated. */
+               if (list + length > end)
+                       return -FDT_ERR_BADVALUE;
+
+               if (length == len && memcmp(list, string, length) == 0)
+                       return idx;
+
+               list += length;
+               idx++;
+       }
+
+       return -FDT_ERR_NOTFOUND;
+}
+
+const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
+                              const char *property, int idx,
+                              int *lenp)
+{
+       const char *list, *end;
+       int length;
+
+       list = fdt_getprop(fdt, nodeoffset, property, &length);
+       if (!list) {
+               if (lenp)
+                       *lenp = length;
+
+               return NULL;
+       }
+
+       end = list + length;
+
+       while (list < end) {
+               length = strnlen(list, end - list) + 1;
+
+               /* Abort if the last string isn't properly NUL-terminated. */
+               if (list + length > end) {
+                       if (lenp)
+                               *lenp = -FDT_ERR_BADVALUE;
+
+                       return NULL;
+               }
+
+               if (idx == 0) {
+                       if (lenp)
+                               *lenp = length - 1;
+
+                       return list;
+               }
+
+               list += length;
+               idx--;
+       }
+
+       if (lenp)
+               *lenp = -FDT_ERR_NOTFOUND;
+
+       return NULL;
+}
+
 int fdt_node_check_compatible(const void *fdt, int nodeoffset,
                              const char *compatible)
 {
@@ -547,10 +673,8 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset,
        prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
        if (!prop)
                return len;
-       if (fdt_stringlist_contains(prop, len, compatible))
-               return 0;
-       else
-               return 1;
+
+       return !fdt_stringlist_contains(prop, len, compatible);
 }
 
 int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
index 4463c10..55fc932 100644 (file)
@@ -101,6 +101,8 @@ static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen)
 
        if (((p + oldlen) < p) || ((p + oldlen) > end))
                return -FDT_ERR_BADOFFSET;
+       if ((p < (char *)fdt) || ((end - oldlen + newlen) < (char *)fdt))
+               return -FDT_ERR_BADOFFSET;
        if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt)))
                return -FDT_ERR_NOSPACE;
        memmove(p + newlen, p + oldlen, end - p - oldlen);
@@ -189,17 +191,13 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
 int fdt_del_mem_rsv(void *fdt, int n)
 {
        struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n);
-       int err;
 
        FDT_RW_CHECK_HEADER(fdt);
 
        if (n >= fdt_num_mem_rsv(fdt))
                return -FDT_ERR_NOTFOUND;
 
-       err = _fdt_splice_mem_rsv(fdt, re, 1, 0);
-       if (err)
-               return err;
-       return 0;
+       return _fdt_splice_mem_rsv(fdt, re, 1, 0);
 }
 
 static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
index e6c3cee..9677a18 100644 (file)
@@ -69,6 +69,7 @@ static struct fdt_errtabent fdt_errtable[] = {
 
        FDT_ERRTABENT(FDT_ERR_BADOFFSET),
        FDT_ERRTABENT(FDT_ERR_BADPATH),
+       FDT_ERRTABENT(FDT_ERR_BADPHANDLE),
        FDT_ERRTABENT(FDT_ERR_BADSTATE),
 
        FDT_ERRTABENT(FDT_ERR_TRUNCATED),
@@ -76,6 +77,11 @@ static struct fdt_errtabent fdt_errtable[] = {
        FDT_ERRTABENT(FDT_ERR_BADVERSION),
        FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE),
        FDT_ERRTABENT(FDT_ERR_BADLAYOUT),
+       FDT_ERRTABENT(FDT_ERR_INTERNAL),
+       FDT_ERRTABENT(FDT_ERR_BADNCELLS),
+       FDT_ERRTABENT(FDT_ERR_BADVALUE),
+       FDT_ERRTABENT(FDT_ERR_BADOVERLAY),
+       FDT_ERRTABENT(FDT_ERR_NOPHANDLES),
 };
 #define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))
 
index c5bbb68..6aaab39 100644 (file)
 
 #include "libfdt_internal.h"
 
+int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
+                                       const char *name, int namelen,
+                                       uint32_t idx, const void *val,
+                                       int len)
+{
+       void *propval;
+       int proplen;
+
+       propval = fdt_getprop_namelen_w(fdt, nodeoffset, name, namelen,
+                                       &proplen);
+       if (!propval)
+               return proplen;
+
+       if (proplen < (len + idx))
+               return -FDT_ERR_NOSPACE;
+
+       memcpy((char *)propval + idx, val, len);
+       return 0;
+}
+
 int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
                        const void *val, int len)
 {
-       void *propval;
+       const void *propval;
        int proplen;
 
-       propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen);
+       propval = fdt_getprop(fdt, nodeoffset, name, &proplen);
        if (! propval)
                return proplen;
 
        if (proplen != len)
                return -FDT_ERR_NOSPACE;
 
-       memcpy(propval, val, len);
-       return 0;
+       return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name,
+                                                  strlen(name), 0,
+                                                  val, len);
 }
 
 static void _fdt_nop_region(void *start, int len)
index ea35ac3..b842b15 100644 (file)
@@ -61,7 +61,7 @@
 #define FDT_ERR_NOTFOUND       1
        /* FDT_ERR_NOTFOUND: The requested node or property does not exist */
 #define FDT_ERR_EXISTS         2
-       /* FDT_ERR_EXISTS: Attemped to create a node or property which
+       /* FDT_ERR_EXISTS: Attempted to create a node or property which
         * already exists */
 #define FDT_ERR_NOSPACE                3
        /* FDT_ERR_NOSPACE: Operation needed to expand the device
         * (e.g. missing a leading / for a function which requires an
         * absolute path) */
 #define FDT_ERR_BADPHANDLE     6
-       /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle
-        * value.  phandle values of 0 and -1 are not permitted. */
+       /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle.
+        * This can be caused either by an invalid phandle property
+        * length, or the phandle value was either 0 or -1, which are
+        * not permitted. */
 #define FDT_ERR_BADSTATE       7
        /* FDT_ERR_BADSTATE: Function was passed an incomplete device
         * tree created by the sequential-write functions, which is
        /* FDT_ERR_BADNCELLS: Device tree has a #address-cells, #size-cells
         * or similar property with a bad format or value */
 
-#define FDT_ERR_MAX            14
+#define FDT_ERR_BADVALUE       15
+       /* FDT_ERR_BADVALUE: Device tree has a property with an unexpected
+        * value. For example: a property expected to contain a string list
+        * is not NUL-terminated within the length of its value. */
+
+#define FDT_ERR_BADOVERLAY     16
+       /* FDT_ERR_BADOVERLAY: The device tree overlay, while
+        * correctly structured, cannot be applied due to some
+        * unexpected or missing value, property or node. */
+
+#define FDT_ERR_NOPHANDLES     17
+       /* FDT_ERR_NOPHANDLES: The device tree doesn't have any
+        * phandle available anymore without causing an overflow */
+
+#define FDT_ERR_MAX            17
 
 /**********************************************************************/
 /* Low-level functions (you probably don't need these)                */
@@ -163,27 +179,55 @@ int fdt_first_subnode(const void *fdt, int offset);
  */
 int fdt_next_subnode(const void *fdt, int offset);
 
+/**
+ * fdt_for_each_subnode - iterate over all subnodes of a parent
+ *
+ * @node:      child node (int, lvalue)
+ * @fdt:       FDT blob (const void *)
+ * @parent:    parent node (int)
+ *
+ * This is actually a wrapper around a for loop and would be used like so:
+ *
+ *     fdt_for_each_subnode(node, fdt, parent) {
+ *             Use node
+ *             ...
+ *     }
+ *
+ *     if ((node < 0) && (node != -FDT_ERR_NOT_FOUND)) {
+ *             Error handling
+ *     }
+ *
+ * Note that this is implemented as a macro and @node is used as
+ * iterator in the loop. The parent variable be constant or even a
+ * literal.
+ *
+ */
+#define fdt_for_each_subnode(node, fdt, parent)                \
+       for (node = fdt_first_subnode(fdt, parent);     \
+            node >= 0;                                 \
+            node = fdt_next_subnode(fdt, node))
+
 /**********************************************************************/
 /* General functions                                                  */
 /**********************************************************************/
 
 #define fdt_get_header(fdt, field) \
        (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field))
-#define fdt_magic(fdt)                         (fdt_get_header(fdt, magic))
+#define fdt_magic(fdt)                 (fdt_get_header(fdt, magic))
 #define fdt_totalsize(fdt)             (fdt_get_header(fdt, totalsize))
 #define fdt_off_dt_struct(fdt)         (fdt_get_header(fdt, off_dt_struct))
 #define fdt_off_dt_strings(fdt)                (fdt_get_header(fdt, off_dt_strings))
 #define fdt_off_mem_rsvmap(fdt)                (fdt_get_header(fdt, off_mem_rsvmap))
 #define fdt_version(fdt)               (fdt_get_header(fdt, version))
-#define fdt_last_comp_version(fdt)     (fdt_get_header(fdt, last_comp_version))
-#define fdt_boot_cpuid_phys(fdt)       (fdt_get_header(fdt, boot_cpuid_phys))
-#define fdt_size_dt_strings(fdt)       (fdt_get_header(fdt, size_dt_strings))
+#define fdt_last_comp_version(fdt)     (fdt_get_header(fdt, last_comp_version))
+#define fdt_boot_cpuid_phys(fdt)       (fdt_get_header(fdt, boot_cpuid_phys))
+#define fdt_size_dt_strings(fdt)       (fdt_get_header(fdt, size_dt_strings))
 #define fdt_size_dt_struct(fdt)                (fdt_get_header(fdt, size_dt_struct))
 
 #define __fdt_set_hdr(name) \
        static inline void fdt_set_##name(void *fdt, uint32_t val) \
        { \
-               struct fdt_header *fdth = (struct fdt_header*)fdt; \
+               struct fdt_header *fdth = (struct fdt_header *)fdt; \
                fdth->name = cpu_to_fdt32(val); \
        }
 __fdt_set_hdr(magic);
@@ -254,6 +298,21 @@ int fdt_move(const void *fdt, void *buf, int bufsize);
 const char *fdt_string(const void *fdt, int stroffset);
 
 /**
+ * fdt_get_max_phandle - retrieves the highest phandle in a tree
+ * @fdt: pointer to the device tree blob
+ *
+ * fdt_get_max_phandle retrieves the highest phandle in the given
+ * device tree. This will ignore badly formatted phandles, or phandles
+ * with a value of 0 or -1.
+ *
+ * returns:
+ *      the highest phandle on success
+ *      0, if no phandle was found in the device tree
+ *      -1, if an error occurred
+ */
+uint32_t fdt_get_max_phandle(const void *fdt);
+
+/**
  * fdt_num_mem_rsv - retrieve the number of memory reserve map entries
  * @fdt: pointer to the device tree blob
  *
@@ -313,8 +372,9 @@ int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
  * returns:
  *     structure block offset of the requested subnode (>=0), on success
  *     -FDT_ERR_NOTFOUND, if the requested subnode does not exist
- *     -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
- *      -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE
+ *             tag
+ *     -FDT_ERR_BADMAGIC,
  *     -FDT_ERR_BADVERSION,
  *     -FDT_ERR_BADSTATE,
  *     -FDT_ERR_BADSTRUCTURE,
@@ -346,7 +406,8 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen);
  * address).
  *
  * returns:
- *     structure block offset of the node with the requested path (>=0), on success
+ *     structure block offset of the node with the requested path (>=0), on
+ *             success
  *     -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid
  *     -FDT_ERR_NOTFOUND, if the requested node does not exist
  *      -FDT_ERR_BADMAGIC,
@@ -370,10 +431,12 @@ int fdt_path_offset(const void *fdt, const char *path);
  *
  * returns:
  *     pointer to the node's name, on success
- *             If lenp is non-NULL, *lenp contains the length of that name (>=0)
+ *             If lenp is non-NULL, *lenp contains the length of that name
+ *                     (>=0)
  *     NULL, on error
  *             if lenp is non-NULL *lenp contains an error code (<0):
- *             -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *             -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE
+ *                     tag
  *             -FDT_ERR_BADMAGIC,
  *             -FDT_ERR_BADVERSION,
  *             -FDT_ERR_BADSTATE, standard meanings
@@ -422,6 +485,33 @@ int fdt_first_property_offset(const void *fdt, int nodeoffset);
 int fdt_next_property_offset(const void *fdt, int offset);
 
 /**
+ * fdt_for_each_property_offset - iterate over all properties of a node
+ *
+ * @property_offset:   property offset (int, lvalue)
+ * @fdt:               FDT blob (const void *)
+ * @node:              node offset (int)
+ *
+ * This is actually a wrapper around a for loop and would be used like so:
+ *
+ *     fdt_for_each_property_offset(property, fdt, node) {
+ *             Use property
+ *             ...
+ *     }
+ *
+ *     if ((property < 0) && (property != -FDT_ERR_NOT_FOUND)) {
+ *             Error handling
+ *     }
+ *
+ * Note that this is implemented as a macro and property is used as
+ * iterator in the loop. The node variable can be constant or even a
+ * literal.
+ */
+#define fdt_for_each_property_offset(property, fdt, node)      \
+       for (property = fdt_first_property_offset(fdt, node);   \
+            property >= 0;                                     \
+            property = fdt_next_property_offset(fdt, property))
+
+/**
  * fdt_get_property_by_offset - retrieve the property at a given offset
  * @fdt: pointer to the device tree blob
  * @offset: offset of the property to retrieve
@@ -457,8 +547,8 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
  * @namelen: number of characters of name to consider
  * @lenp: pointer to an integer variable (will be overwritten) or NULL
  *
- * Identical to fdt_get_property_namelen(), but only examine the first
- * namelen characters of name for matching the property name.
+ * Identical to fdt_get_property(), but only examine the first namelen
+ * characters of name for matching the property name.
  */
 const struct fdt_property *fdt_get_property_namelen(const void *fdt,
                                                    int nodeoffset,
@@ -485,7 +575,8 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt,
  *     NULL, on error
  *             if lenp is non-NULL, *lenp contains an error code (<0):
  *             -FDT_ERR_NOTFOUND, node does not have named property
- *             -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *             -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE
+ *                     tag
  *             -FDT_ERR_BADMAGIC,
  *             -FDT_ERR_BADVERSION,
  *             -FDT_ERR_BADSTATE,
@@ -549,6 +640,13 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset,
  */
 const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
                                const char *name, int namelen, int *lenp);
+static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset,
+                                         const char *name, int namelen,
+                                         int *lenp)
+{
+       return (void *)(uintptr_t)fdt_getprop_namelen(fdt, nodeoffset, name,
+                                                     namelen, lenp);
+}
 
 /**
  * fdt_getprop - retrieve the value of a given property
@@ -570,7 +668,8 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
  *     NULL, on error
  *             if lenp is non-NULL, *lenp contains an error code (<0):
  *             -FDT_ERR_NOTFOUND, node does not have named property
- *             -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *             -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE
+ *                     tag
  *             -FDT_ERR_BADMAGIC,
  *             -FDT_ERR_BADVERSION,
  *             -FDT_ERR_BADSTATE,
@@ -612,7 +711,7 @@ const char *fdt_get_alias_namelen(const void *fdt,
                                  const char *name, int namelen);
 
 /**
- * fdt_get_alias - retreive the path referenced by a given alias
+ * fdt_get_alias - retrieve the path referenced by a given alias
  * @fdt: pointer to the device tree blob
  * @name: name of the alias th look up
  *
@@ -642,7 +741,7 @@ const char *fdt_get_alias(const void *fdt, const char *name);
  *     0, on success
  *             buf contains the absolute path of the node at
  *             nodeoffset, as a NUL-terminated string.
- *     -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *     -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
  *     -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1)
  *             characters and will not fit in the given buffer.
  *     -FDT_ERR_BADMAGIC,
@@ -672,11 +771,11 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen);
  * structure from the start to nodeoffset.
  *
  * returns:
-
  *     structure block offset of the node at node offset's ancestor
  *             of depth supernodedepth (>=0), on success
- *     -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
-*      -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset
+ *     -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *     -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of
+ *             nodeoffset
  *     -FDT_ERR_BADMAGIC,
  *     -FDT_ERR_BADVERSION,
  *     -FDT_ERR_BADSTATE,
@@ -698,7 +797,7 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
  *
  * returns:
  *     depth of the node at nodeoffset (>=0), on success
- *     -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *     -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
  *     -FDT_ERR_BADMAGIC,
  *     -FDT_ERR_BADVERSION,
  *     -FDT_ERR_BADSTATE,
@@ -721,7 +820,7 @@ int fdt_node_depth(const void *fdt, int nodeoffset);
  * returns:
  *     structure block offset of the parent of the node at nodeoffset
  *             (>=0), on success
- *     -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *     -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
  *     -FDT_ERR_BADMAGIC,
  *     -FDT_ERR_BADVERSION,
  *     -FDT_ERR_BADSTATE,
@@ -761,7 +860,7 @@ int fdt_parent_offset(const void *fdt, int nodeoffset);
  *              on success
  *     -FDT_ERR_NOTFOUND, no node matching the criterion exists in the
  *             tree after startoffset
- *     -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *     -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
  *     -FDT_ERR_BADMAGIC,
  *     -FDT_ERR_BADVERSION,
  *     -FDT_ERR_BADSTATE,
@@ -808,7 +907,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle);
  *     1, if the node has a 'compatible' property, but it does not list
  *             the given string
  *     -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property
- *     -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag
+ *     -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag
  *     -FDT_ERR_BADMAGIC,
  *     -FDT_ERR_BADVERSION,
  *     -FDT_ERR_BADSTATE,
@@ -845,7 +944,7 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset,
  *              on success
  *     -FDT_ERR_NOTFOUND, no node matching the criterion exists in the
  *             tree after startoffset
- *     -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *     -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
  *     -FDT_ERR_BADMAGIC,
  *     -FDT_ERR_BADVERSION,
  *     -FDT_ERR_BADSTATE,
@@ -868,6 +967,68 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
  */
 int fdt_stringlist_contains(const char *strlist, int listlen, const char *str);
 
+/**
+ * fdt_stringlist_count - count the number of strings in a string list
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @property: name of the property containing the string list
+ * @return:
+ *   the number of strings in the given property
+ *   -FDT_ERR_BADVALUE if the property value is not NUL-terminated
+ *   -FDT_ERR_NOTFOUND if the property does not exist
+ */
+int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property);
+
+/**
+ * fdt_stringlist_search - find a string in a string list and return its index
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @property: name of the property containing the string list
+ * @string: string to look up in the string list
+ *
+ * Note that it is possible for this function to succeed on property values
+ * that are not NUL-terminated. That's because the function will stop after
+ * finding the first occurrence of @string. This can for example happen with
+ * small-valued cell properties, such as #address-cells, when searching for
+ * the empty string.
+ *
+ * @return:
+ *   the index of the string in the list of strings
+ *   -FDT_ERR_BADVALUE if the property value is not NUL-terminated
+ *   -FDT_ERR_NOTFOUND if the property does not exist or does not contain
+ *                     the given string
+ */
+int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
+                         const char *string);
+
+/**
+ * fdt_stringlist_get() - obtain the string at a given index in a string list
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @property: name of the property containing the string list
+ * @index: index of the string to return
+ * @lenp: return location for the string length or an error code on failure
+ *
+ * Note that this will successfully extract strings from properties with
+ * non-NUL-terminated values. For example on small-valued cell properties
+ * this function will return the empty string.
+ *
+ * If non-NULL, the length of the string (on success) or a negative error-code
+ * (on failure) will be stored in the integer pointer to by lenp.
+ *
+ * @return:
+ *   A pointer to the string at the given index in the string list or NULL on
+ *   failure. On success the length of the string will be stored in the memory
+ *   location pointed to by the lenp parameter, if non-NULL. On failure one of
+ *   the following negative error codes will be returned in the lenp parameter
+ *   (if non-NULL):
+ *     -FDT_ERR_BADVALUE if the property value is not NUL-terminated
+ *     -FDT_ERR_NOTFOUND if the property does not exist
+ */
+const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
+                              const char *property, int index,
+                              int *lenp);
+
 /**********************************************************************/
 /* Read-only functions (addressing related)                           */
 /**********************************************************************/
@@ -893,7 +1054,8 @@ int fdt_stringlist_contains(const char *strlist, int listlen, const char *str);
  * returns:
  *     0 <= n < FDT_MAX_NCELLS, on success
  *      2, if the node has no #address-cells property
- *      -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid #address-cells property
+ *      -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
+ *             #address-cells property
  *     -FDT_ERR_BADMAGIC,
  *     -FDT_ERR_BADVERSION,
  *     -FDT_ERR_BADSTATE,
@@ -913,7 +1075,8 @@ int fdt_address_cells(const void *fdt, int nodeoffset);
  * returns:
  *     0 <= n < FDT_MAX_NCELLS, on success
  *      2, if the node has no #address-cells property
- *      -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid #size-cells property
+ *      -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
+ *             #size-cells property
  *     -FDT_ERR_BADMAGIC,
  *     -FDT_ERR_BADVERSION,
  *     -FDT_ERR_BADSTATE,
@@ -928,6 +1091,27 @@ int fdt_size_cells(const void *fdt, int nodeoffset);
 /**********************************************************************/
 
 /**
+ * fdt_setprop_inplace_namelen_partial - change a property's value,
+ *                                       but not its size
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @namelen: number of characters of name to consider
+ * @idx: index of the property to change in the array
+ * @val: pointer to data to replace the property value with
+ * @len: length of the property value
+ *
+ * Identical to fdt_setprop_inplace(), but modifies the given property
+ * starting from the given index, and using only the first characters
+ * of the name. It is useful when you want to manipulate only one value of
+ * an array and you have a string that doesn't end with \0.
+ */
+int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
+                                       const char *name, int namelen,
+                                       uint32_t idx, const void *val,
+                                       int len);
+
+/**
  * fdt_setprop_inplace - change a property's value, but not its size
  * @fdt: pointer to the device tree blob
  * @nodeoffset: offset of the node whose property to change
@@ -1537,9 +1721,11 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
  * change the offsets of some existing nodes.
 
  * returns:
- *     structure block offset of the created nodeequested subnode (>=0), on success
+ *     structure block offset of the created nodeequested subnode (>=0), on
+ *             success
  *     -FDT_ERR_NOTFOUND, if the requested subnode does not exist
- *     -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
+ *     -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE
+ *             tag
  *     -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of
  *             the given name
  *     -FDT_ERR_NOSPACE, if there is insufficient free space in the
@@ -1577,6 +1763,37 @@ int fdt_add_subnode(void *fdt, int parentoffset, const char *name);
  */
 int fdt_del_node(void *fdt, int nodeoffset);
 
+/**
+ * fdt_overlay_apply - Applies a DT overlay on a base DT
+ * @fdt: pointer to the base device tree blob
+ * @fdto: pointer to the device tree overlay blob
+ *
+ * fdt_overlay_apply() will apply the given device tree overlay on the
+ * given base device tree.
+ *
+ * Expect the base device tree to be modified, even if the function
+ * returns an error.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, there's not enough space in the base device tree
+ *     -FDT_ERR_NOTFOUND, the overlay points to some inexistant nodes or
+ *             properties in the base DT
+ *     -FDT_ERR_BADPHANDLE,
+ *     -FDT_ERR_BADOVERLAY,
+ *     -FDT_ERR_NOPHANDLES,
+ *     -FDT_ERR_INTERNAL,
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADOFFSET,
+ *     -FDT_ERR_BADPATH,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_overlay_apply(void *fdt, void *fdto);
+
 /**********************************************************************/
 /* Debugging / informational functions                                */
 /**********************************************************************/
index 9dea97d..99f936d 100644 (file)
@@ -54,6 +54,7 @@
 
 #include <stddef.h>
 #include <stdint.h>
+#include <stdlib.h>
 #include <string.h>
 
 #ifdef __CHECKER__
index e229b84..afa2f67 100644 (file)
@@ -204,7 +204,7 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
                        }
                }
 
-               /* if no collision occured, add child to the old node. */
+               /* if no collision occurred, add child to the old node. */
                if (new_child)
                        add_child(old_node, new_child);
        }
@@ -296,6 +296,23 @@ void delete_node(struct node *node)
        delete_labels(&node->labels);
 }
 
+void append_to_property(struct node *node,
+                                   char *name, const void *data, int len)
+{
+       struct data d;
+       struct property *p;
+
+       p = get_property(node, name);
+       if (p) {
+               d = data_append_data(p->val, data, len);
+               p->val = d;
+       } else {
+               d = data_append_data(empty_data, data, len);
+               p = build_property(name, d);
+               add_property(node, p);
+       }
+}
+
 struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size)
 {
        struct reserve_info *new = xmalloc(sizeof(*new));
@@ -335,17 +352,19 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list,
        return list;
 }
 
-struct boot_info *build_boot_info(struct reserve_info *reservelist,
-                                 struct node *tree, uint32_t boot_cpuid_phys)
+struct dt_info *build_dt_info(unsigned int dtsflags,
+                             struct reserve_info *reservelist,
+                             struct node *tree, uint32_t boot_cpuid_phys)
 {
-       struct boot_info *bi;
+       struct dt_info *dti;
 
-       bi = xmalloc(sizeof(*bi));
-       bi->reservelist = reservelist;
-       bi->dt = tree;
-       bi->boot_cpuid_phys = boot_cpuid_phys;
+       dti = xmalloc(sizeof(*dti));
+       dti->dtsflags = dtsflags;
+       dti->reservelist = reservelist;
+       dti->dt = tree;
+       dti->boot_cpuid_phys = boot_cpuid_phys;
 
-       return bi;
+       return dti;
 }
 
 /*
@@ -592,12 +611,12 @@ static int cmp_reserve_info(const void *ax, const void *bx)
                return 0;
 }
 
-static void sort_reserve_entries(struct boot_info *bi)
+static void sort_reserve_entries(struct dt_info *dti)
 {
        struct reserve_info *ri, **tbl;
        int n = 0, i = 0;
 
-       for (ri = bi->reservelist;
+       for (ri = dti->reservelist;
             ri;
             ri = ri->next)
                n++;
@@ -607,14 +626,14 @@ static void sort_reserve_entries(struct boot_info *bi)
 
        tbl = xmalloc(n * sizeof(*tbl));
 
-       for (ri = bi->reservelist;
+       for (ri = dti->reservelist;
             ri;
             ri = ri->next)
                tbl[i++] = ri;
 
        qsort(tbl, n, sizeof(*tbl), cmp_reserve_info);
 
-       bi->reservelist = tbl[0];
+       dti->reservelist = tbl[0];
        for (i = 0; i < (n-1); i++)
                tbl[i]->next = tbl[i+1];
        tbl[n-1]->next = NULL;
@@ -704,8 +723,256 @@ static void sort_node(struct node *node)
                sort_node(c);
 }
 
-void sort_tree(struct boot_info *bi)
+void sort_tree(struct dt_info *dti)
+{
+       sort_reserve_entries(dti);
+       sort_node(dti->dt);
+}
+
+/* utility helper to avoid code duplication */
+static struct node *build_and_name_child_node(struct node *parent, char *name)
+{
+       struct node *node;
+
+       node = build_node(NULL, NULL);
+       name_node(node, xstrdup(name));
+       add_child(parent, node);
+
+       return node;
+}
+
+static struct node *build_root_node(struct node *dt, char *name)
+{
+       struct node *an;
+
+       an = get_subnode(dt, name);
+       if (!an)
+               an = build_and_name_child_node(dt, name);
+
+       if (!an)
+               die("Could not build root node /%s\n", name);
+
+       return an;
+}
+
+static bool any_label_tree(struct dt_info *dti, struct node *node)
+{
+       struct node *c;
+
+       if (node->labels)
+               return true;
+
+       for_each_child(node, c)
+               if (any_label_tree(dti, c))
+                       return true;
+
+       return false;
+}
+
+static void generate_label_tree_internal(struct dt_info *dti,
+                                        struct node *an, struct node *node,
+                                        bool allocph)
+{
+       struct node *dt = dti->dt;
+       struct node *c;
+       struct property *p;
+       struct label *l;
+
+       /* if there are labels */
+       if (node->labels) {
+
+               /* now add the label in the node */
+               for_each_label(node->labels, l) {
+
+                       /* check whether the label already exists */
+                       p = get_property(an, l->label);
+                       if (p) {
+                               fprintf(stderr, "WARNING: label %s already"
+                                       " exists in /%s", l->label,
+                                       an->name);
+                               continue;
+                       }
+
+                       /* insert it */
+                       p = build_property(l->label,
+                               data_copy_mem(node->fullpath,
+                                               strlen(node->fullpath) + 1));
+                       add_property(an, p);
+               }
+
+               /* force allocation of a phandle for this node */
+               if (allocph)
+                       (void)get_node_phandle(dt, node);
+       }
+
+       for_each_child(node, c)
+               generate_label_tree_internal(dti, an, c, allocph);
+}
+
+static bool any_fixup_tree(struct dt_info *dti, struct node *node)
+{
+       struct node *c;
+       struct property *prop;
+       struct marker *m;
+
+       for_each_property(node, prop) {
+               m = prop->val.markers;
+               for_each_marker_of_type(m, REF_PHANDLE) {
+                       if (!get_node_by_ref(dti->dt, m->ref))
+                               return true;
+               }
+       }
+
+       for_each_child(node, c) {
+               if (any_fixup_tree(dti, c))
+                       return true;
+       }
+
+       return false;
+}
+
+static void add_fixup_entry(struct dt_info *dti, struct node *fn,
+                           struct node *node, struct property *prop,
+                           struct marker *m)
 {
-       sort_reserve_entries(bi);
-       sort_node(bi->dt);
+       char *entry;
+
+       /* m->ref can only be a REF_PHANDLE, but check anyway */
+       assert(m->type == REF_PHANDLE);
+
+       /* there shouldn't be any ':' in the arguments */
+       if (strchr(node->fullpath, ':') || strchr(prop->name, ':'))
+               die("arguments should not contain ':'\n");
+
+       xasprintf(&entry, "%s:%s:%u",
+                       node->fullpath, prop->name, m->offset);
+       append_to_property(fn, m->ref, entry, strlen(entry) + 1);
+}
+
+static void generate_fixups_tree_internal(struct dt_info *dti,
+                                         struct node *fn,
+                                         struct node *node)
+{
+       struct node *dt = dti->dt;
+       struct node *c;
+       struct property *prop;
+       struct marker *m;
+       struct node *refnode;
+
+       for_each_property(node, prop) {
+               m = prop->val.markers;
+               for_each_marker_of_type(m, REF_PHANDLE) {
+                       refnode = get_node_by_ref(dt, m->ref);
+                       if (!refnode)
+                               add_fixup_entry(dti, fn, node, prop, m);
+               }
+       }
+
+       for_each_child(node, c)
+               generate_fixups_tree_internal(dti, fn, c);
+}
+
+static bool any_local_fixup_tree(struct dt_info *dti, struct node *node)
+{
+       struct node *c;
+       struct property *prop;
+       struct marker *m;
+
+       for_each_property(node, prop) {
+               m = prop->val.markers;
+               for_each_marker_of_type(m, REF_PHANDLE) {
+                       if (get_node_by_ref(dti->dt, m->ref))
+                               return true;
+               }
+       }
+
+       for_each_child(node, c) {
+               if (any_local_fixup_tree(dti, c))
+                       return true;
+       }
+
+       return false;
+}
+
+static void add_local_fixup_entry(struct dt_info *dti,
+               struct node *lfn, struct node *node,
+               struct property *prop, struct marker *m,
+               struct node *refnode)
+{
+       struct node *wn, *nwn;  /* local fixup node, walk node, new */
+       uint32_t value_32;
+       char **compp;
+       int i, depth;
+
+       /* walk back retreiving depth */
+       depth = 0;
+       for (wn = node; wn; wn = wn->parent)
+               depth++;
+
+       /* allocate name array */
+       compp = xmalloc(sizeof(*compp) * depth);
+
+       /* store names in the array */
+       for (wn = node, i = depth - 1; wn; wn = wn->parent, i--)
+               compp[i] = wn->name;
+
+       /* walk the path components creating nodes if they don't exist */
+       for (wn = lfn, i = 1; i < depth; i++, wn = nwn) {
+               /* if no node exists, create it */
+               nwn = get_subnode(wn, compp[i]);
+               if (!nwn)
+                       nwn = build_and_name_child_node(wn, compp[i]);
+       }
+
+       free(compp);
+
+       value_32 = cpu_to_fdt32(m->offset);
+       append_to_property(wn, prop->name, &value_32, sizeof(value_32));
+}
+
+static void generate_local_fixups_tree_internal(struct dt_info *dti,
+                                               struct node *lfn,
+                                               struct node *node)
+{
+       struct node *dt = dti->dt;
+       struct node *c;
+       struct property *prop;
+       struct marker *m;
+       struct node *refnode;
+
+       for_each_property(node, prop) {
+               m = prop->val.markers;
+               for_each_marker_of_type(m, REF_PHANDLE) {
+                       refnode = get_node_by_ref(dt, m->ref);
+                       if (refnode)
+                               add_local_fixup_entry(dti, lfn, node, prop, m, refnode);
+               }
+       }
+
+       for_each_child(node, c)
+               generate_local_fixups_tree_internal(dti, lfn, c);
+}
+
+void generate_label_tree(struct dt_info *dti, char *name, bool allocph)
+{
+       if (!any_label_tree(dti, dti->dt))
+               return;
+       generate_label_tree_internal(dti, build_root_node(dti->dt, name),
+                                    dti->dt, allocph);
+}
+
+void generate_fixups_tree(struct dt_info *dti, char *name)
+{
+       if (!any_fixup_tree(dti, dti->dt))
+               return;
+       generate_fixups_tree_internal(dti, build_root_node(dti->dt, name),
+                                     dti->dt);
+}
+
+void generate_local_fixups_tree(struct dt_info *dti, char *name)
+{
+       if (!any_local_fixup_tree(dti, dti->dt))
+               return;
+       generate_local_fixups_tree_internal(dti, build_root_node(dti->dt, name),
+                                           dti->dt);
 }
index f534c22..aa3aad0 100644 (file)
@@ -246,46 +246,27 @@ srcpos_copy(struct srcpos *pos)
        return pos_new;
 }
 
-
-
-void
-srcpos_dump(struct srcpos *pos)
-{
-       printf("file        : \"%s\"\n",
-              pos->file ? (char *) pos->file : "<no file>");
-       printf("first_line  : %d\n", pos->first_line);
-       printf("first_column: %d\n", pos->first_column);
-       printf("last_line   : %d\n", pos->last_line);
-       printf("last_column : %d\n", pos->last_column);
-       printf("file        : %s\n", pos->file->name);
-}
-
-
 char *
 srcpos_string(struct srcpos *pos)
 {
        const char *fname = "<no-file>";
        char *pos_str;
-       int rc;
 
        if (pos)
                fname = pos->file->name;
 
 
        if (pos->first_line != pos->last_line)
-               rc = asprintf(&pos_str, "%s:%d.%d-%d.%d", fname,
-                             pos->first_line, pos->first_column,
-                             pos->last_line, pos->last_column);
+               xasprintf(&pos_str, "%s:%d.%d-%d.%d", fname,
+                         pos->first_line, pos->first_column,
+                         pos->last_line, pos->last_column);
        else if (pos->first_column != pos->last_column)
-               rc = asprintf(&pos_str, "%s:%d.%d-%d", fname,
-                             pos->first_line, pos->first_column,
-                             pos->last_column);
+               xasprintf(&pos_str, "%s:%d.%d-%d", fname,
+                         pos->first_line, pos->first_column,
+                         pos->last_column);
        else
-               rc = asprintf(&pos_str, "%s:%d.%d", fname,
-                             pos->first_line, pos->first_column);
-
-       if (rc == -1)
-               die("Couldn't allocate in srcpos string");
+               xasprintf(&pos_str, "%s:%d.%d", fname,
+                         pos->first_line, pos->first_column);
 
        return pos_str;
 }
index f81827b..2cdfcd8 100644 (file)
@@ -105,7 +105,6 @@ extern struct srcpos srcpos_empty;
 extern void srcpos_update(struct srcpos *pos, const char *text, int len);
 extern struct srcpos *srcpos_copy(struct srcpos *pos);
 extern char *srcpos_string(struct srcpos *pos);
-extern void srcpos_dump(struct srcpos *pos);
 
 extern void srcpos_verror(struct srcpos *pos, const char *prefix,
                          const char *fmt, va_list va)
index a55d1d1..c9d8967 100644 (file)
@@ -25,12 +25,12 @@ extern FILE *yyin;
 extern int yyparse(void);
 extern YYLTYPE yylloc;
 
-struct boot_info *the_boot_info;
+struct dt_info *parser_output;
 bool treesource_error;
 
-struct boot_info *dt_from_source(const char *fname)
+struct dt_info *dt_from_source(const char *fname)
 {
-       the_boot_info = NULL;
+       parser_output = NULL;
        treesource_error = false;
 
        srcfile_push(fname);
@@ -43,7 +43,7 @@ struct boot_info *dt_from_source(const char *fname)
        if (treesource_error)
                die("Syntax error parsing input tree\n");
 
-       return the_boot_info;
+       return parser_output;
 }
 
 static void write_prefix(FILE *f, int level)
@@ -263,13 +263,13 @@ static void write_tree_source_node(FILE *f, struct node *tree, int level)
 }
 
 
-void dt_to_source(FILE *f, struct boot_info *bi)
+void dt_to_source(FILE *f, struct dt_info *dti)
 {
        struct reserve_info *re;
 
        fprintf(f, "/dts-v1/;\n\n");
 
-       for (re = bi->reservelist; re; re = re->next) {
+       for (re = dti->reservelist; re; re = re->next) {
                struct label *l;
 
                for_each_label(re->labels, l)
@@ -279,6 +279,6 @@ void dt_to_source(FILE *f, struct boot_info *bi)
                        (unsigned long long)re->re.size);
        }
 
-       write_tree_source_node(f, bi->dt, 0);
+       write_tree_source_node(f, dti->dt, 0);
 }
 
index 9d65226..3550f86 100644 (file)
@@ -46,6 +46,36 @@ char *xstrdup(const char *s)
        return d;
 }
 
+/* based in part from (3) vsnprintf */
+int xasprintf(char **strp, const char *fmt, ...)
+{
+       int n, size = 128;      /* start with 128 bytes */
+       char *p;
+       va_list ap;
+
+       /* initial pointer is NULL making the fist realloc to be malloc */
+       p = NULL;
+       while (1) {
+               p = xrealloc(p, size);
+
+               /* Try to print in the allocated space. */
+               va_start(ap, fmt);
+               n = vsnprintf(p, size, fmt, ap);
+               va_end(ap);
+
+               /* If that worked, return the string. */
+               if (n > -1 && n < size)
+                       break;
+               /* Else try again with more space. */
+               if (n > -1)     /* glibc 2.1 */
+                       size = n + 1; /* precisely what is needed */
+               else            /* glibc 2.0 */
+                       size *= 2; /* twice the old size */
+       }
+       *strp = p;
+       return strlen(p);
+}
+
 char *join_path(const char *path, const char *name)
 {
        int lenp = strlen(path);
@@ -152,7 +182,6 @@ char get_escape_char(const char *s, int *i)
        int     j = *i + 1;
        char    val;
 
-       assert(c);
        switch (c) {
        case 'a':
                val = '\a';
@@ -349,7 +378,6 @@ int utilfdt_decode_type(const char *fmt, int *type, int *size)
 void utilfdt_print_data(const char *data, int len)
 {
        int i;
-       const char *p = data;
        const char *s;
 
        /* no data, don't print */
@@ -376,6 +404,7 @@ void utilfdt_print_data(const char *data, int len)
                               i < (len - 1) ? " " : "");
                printf(">");
        } else {
+               const unsigned char *p = (const unsigned char *)data;
                printf(" = [");
                for (i = 0; i < len; i++)
                        printf("%02x%s", *p++, i < len - 1 ? " " : "");
index f800b60..f5c4f1b 100644 (file)
@@ -59,6 +59,7 @@ static inline void *xrealloc(void *p, size_t len)
 }
 
 extern char *xstrdup(const char *s);
+extern int xasprintf(char **strp, const char *fmt, ...);
 extern char *join_path(const char *path, const char *name);
 
 /**
index 5b8c7d5..16c2e53 100644 (file)
@@ -1 +1 @@
-#define DTC_VERSION "DTC 1.4.1-g9d3649bd"
+#define DTC_VERSION "DTC 1.4.2-g0931cea3"
index 99950b5..632f6d6 100644 (file)
@@ -1,19 +1,19 @@
-/* A Bison parser, made by GNU Bison 2.7.  */
+/* A Bison parser, made by GNU Bison 3.0.4.  */
 
 /* Bison implementation for Yacc-like parsers in C
-   
-      Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
-   
+
+   Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
+
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
-   
+
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-   
+
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
@@ -26,7 +26,7 @@
    special exception, which will cause the skeleton and the resulting
    Bison output files to be licensed under the GNU General Public
    License without this special exception.
-   
+
    This special exception was added by the Free Software Foundation in
    version 2.2 of Bison.  */
 
@@ -44,7 +44,7 @@
 #define YYBISON 1
 
 /* Bison version.  */
-#define YYBISON_VERSION "2.7"
+#define YYBISON_VERSION "3.0.4"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
@@ -62,7 +62,7 @@
 
 
 /* Copy the first part of user declarations.  */
-
+#line 24 "parse.y" /* yacc.c:339  */
 
 
 #include <assert.h>
@@ -113,13 +113,13 @@ static void record_compound(struct string_list **keyw,
 }
 
 
+#line 117 "parse.tab.c" /* yacc.c:339  */
 
-
-# ifndef YY_NULL
+# ifndef YY_NULLPTR
 #  if defined __cplusplus && 201103L <= __cplusplus
-#   define YY_NULL nullptr
+#   define YY_NULLPTR nullptr
 #  else
-#   define YY_NULL 0
+#   define YY_NULLPTR 0
 #  endif
 # endif
 
@@ -131,8 +131,11 @@ static void record_compound(struct string_list **keyw,
 # define YYERROR_VERBOSE 0
 #endif
 
-
-/* Enabling traces.  */
+/* In a future release of Bison, this section will be replaced
+   by #include "parse.tab.h".  */
+#ifndef YY_YY_PARSE_TAB_H_INCLUDED
+# define YY_YY_PARSE_TAB_H_INCLUDED
+/* Debug traces.  */
 #ifndef YYDEBUG
 # define YYDEBUG 1
 #endif
@@ -140,86 +143,73 @@ static void record_compound(struct string_list **keyw,
 extern int yydebug;
 #endif
 
-/* Tokens.  */
+/* Token type.  */
 #ifndef YYTOKENTYPE
 # define YYTOKENTYPE
-   /* Put the tokens into the symbol table, so that GDB and other debuggers
-      know about them.  */
-   enum yytokentype {
-     ASM_KEYW = 258,
-     ATTRIBUTE_KEYW = 259,
-     AUTO_KEYW = 260,
-     BOOL_KEYW = 261,
-     CHAR_KEYW = 262,
-     CONST_KEYW = 263,
-     DOUBLE_KEYW = 264,
-     ENUM_KEYW = 265,
-     EXTERN_KEYW = 266,
-     EXTENSION_KEYW = 267,
-     FLOAT_KEYW = 268,
-     INLINE_KEYW = 269,
-     INT_KEYW = 270,
-     LONG_KEYW = 271,
-     REGISTER_KEYW = 272,
-     RESTRICT_KEYW = 273,
-     SHORT_KEYW = 274,
-     SIGNED_KEYW = 275,
-     STATIC_KEYW = 276,
-     STRUCT_KEYW = 277,
-     TYPEDEF_KEYW = 278,
-     UNION_KEYW = 279,
-     UNSIGNED_KEYW = 280,
-     VOID_KEYW = 281,
-     VOLATILE_KEYW = 282,
-     TYPEOF_KEYW = 283,
-     EXPORT_SYMBOL_KEYW = 284,
-     ASM_PHRASE = 285,
-     ATTRIBUTE_PHRASE = 286,
-     TYPEOF_PHRASE = 287,
-     BRACE_PHRASE = 288,
-     BRACKET_PHRASE = 289,
-     EXPRESSION_PHRASE = 290,
-     CHAR = 291,
-     DOTS = 292,
-     IDENT = 293,
-     INT = 294,
-     REAL = 295,
-     STRING = 296,
-     TYPE = 297,
-     OTHER = 298,
-     FILENAME = 299
-   };
+  enum yytokentype
+  {
+    ASM_KEYW = 258,
+    ATTRIBUTE_KEYW = 259,
+    AUTO_KEYW = 260,
+    BOOL_KEYW = 261,
+    CHAR_KEYW = 262,
+    CONST_KEYW = 263,
+    DOUBLE_KEYW = 264,
+    ENUM_KEYW = 265,
+    EXTERN_KEYW = 266,
+    EXTENSION_KEYW = 267,
+    FLOAT_KEYW = 268,
+    INLINE_KEYW = 269,
+    INT_KEYW = 270,
+    LONG_KEYW = 271,
+    REGISTER_KEYW = 272,
+    RESTRICT_KEYW = 273,
+    SHORT_KEYW = 274,
+    SIGNED_KEYW = 275,
+    STATIC_KEYW = 276,
+    STRUCT_KEYW = 277,
+    TYPEDEF_KEYW = 278,
+    UNION_KEYW = 279,
+    UNSIGNED_KEYW = 280,
+    VOID_KEYW = 281,
+    VOLATILE_KEYW = 282,
+    TYPEOF_KEYW = 283,
+    EXPORT_SYMBOL_KEYW = 284,
+    ASM_PHRASE = 285,
+    ATTRIBUTE_PHRASE = 286,
+    TYPEOF_PHRASE = 287,
+    BRACE_PHRASE = 288,
+    BRACKET_PHRASE = 289,
+    EXPRESSION_PHRASE = 290,
+    CHAR = 291,
+    DOTS = 292,
+    IDENT = 293,
+    INT = 294,
+    REAL = 295,
+    STRING = 296,
+    TYPE = 297,
+    OTHER = 298,
+    FILENAME = 299
+  };
 #endif
 
-
+/* Value type.  */
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef int YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
 #endif
 
+
 extern YYSTYPE yylval;
 
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void *YYPARSE_PARAM);
-#else
-int yyparse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
 int yyparse (void);
-#else
-int yyparse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
-
 
+#endif /* !YY_YY_PARSE_TAB_H_INCLUDED  */
 
 /* Copy the second part of user declarations.  */
 
-
+#line 213 "parse.tab.c" /* yacc.c:358  */
 
 #ifdef short
 # undef short
@@ -233,11 +223,8 @@ typedef unsigned char yytype_uint8;
 
 #ifdef YYTYPE_INT8
 typedef YYTYPE_INT8 yytype_int8;
-#elif (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-typedef signed char yytype_int8;
 #else
-typedef short int yytype_int8;
+typedef signed char yytype_int8;
 #endif
 
 #ifdef YYTYPE_UINT16
@@ -257,8 +244,7 @@ typedef short int yytype_int16;
 #  define YYSIZE_T __SIZE_TYPE__
 # elif defined size_t
 #  define YYSIZE_T size_t
-# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
+# elif ! defined YYSIZE_T
 #  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
 #  define YYSIZE_T size_t
 # else
@@ -280,6 +266,33 @@ typedef short int yytype_int16;
 # endif
 #endif
 
+#ifndef YY_ATTRIBUTE
+# if (defined __GNUC__                                               \
+      && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__)))  \
+     || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C
+#  define YY_ATTRIBUTE(Spec) __attribute__(Spec)
+# else
+#  define YY_ATTRIBUTE(Spec) /* empty */
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE_PURE
+# define YY_ATTRIBUTE_PURE   YY_ATTRIBUTE ((__pure__))
+#endif
+
+#ifndef YY_ATTRIBUTE_UNUSED
+# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__))
+#endif
+
+#if !defined _Noreturn \
+     && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112)
+# if defined _MSC_VER && 1200 <= _MSC_VER
+#  define _Noreturn __declspec (noreturn)
+# else
+#  define _Noreturn YY_ATTRIBUTE ((__noreturn__))
+# endif
+#endif
+
 /* Suppress unused-variable warnings by "using" E.  */
 #if ! defined lint || defined __GNUC__
 # define YYUSE(E) ((void) (E))
@@ -287,24 +300,26 @@ typedef short int yytype_int16;
 # define YYUSE(E) /* empty */
 #endif
 
-/* Identity function, used to suppress warnings about constant conditions.  */
-#ifndef lint
-# define YYID(N) (N)
-#else
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static int
-YYID (int yyi)
+#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
+/* Suppress an incorrect diagnostic about yylval being uninitialized.  */
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
+    _Pragma ("GCC diagnostic push") \
+    _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
+    _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+    _Pragma ("GCC diagnostic pop")
 #else
-static int
-YYID (yyi)
-    int yyi;
+# define YY_INITIAL_VALUE(Value) Value
 #endif
-{
-  return yyi;
-}
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
 #endif
 
+
 #if ! defined yyoverflow || YYERROR_VERBOSE
 
 /* The parser invokes alloca or malloc; define the necessary symbols.  */
@@ -322,8 +337,7 @@ YYID (yyi)
 #    define alloca _alloca
 #   else
 #    define YYSTACK_ALLOC alloca
-#    if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
+#    if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS
 #     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
       /* Use EXIT_SUCCESS as a witness for stdlib.h.  */
 #     ifndef EXIT_SUCCESS
@@ -335,8 +349,8 @@ YYID (yyi)
 # endif
 
 # ifdef YYSTACK_ALLOC
-   /* Pacify GCC's `empty if-body' warning.  */
-#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+   /* Pacify GCC's 'empty if-body' warning.  */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
 #  ifndef YYSTACK_ALLOC_MAXIMUM
     /* The OS might guarantee only one guard page at the bottom of the stack,
        and a page size can be as small as 4096 bytes.  So we cannot safely
@@ -352,7 +366,7 @@ YYID (yyi)
 #  endif
 #  if (defined __cplusplus && ! defined EXIT_SUCCESS \
        && ! ((defined YYMALLOC || defined malloc) \
-            && (defined YYFREE || defined free)))
+             && (defined YYFREE || defined free)))
 #   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
 #   ifndef EXIT_SUCCESS
 #    define EXIT_SUCCESS 0
@@ -360,15 +374,13 @@ YYID (yyi)
 #  endif
 #  ifndef YYMALLOC
 #   define YYMALLOC malloc
-#   if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
+#   if ! defined malloc && ! defined EXIT_SUCCESS
 void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
 #   endif
 #  endif
 #  ifndef YYFREE
 #   define YYFREE free
-#   if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
+#   if ! defined free && ! defined EXIT_SUCCESS
 void free (void *); /* INFRINGES ON USER NAME SPACE */
 #   endif
 #  endif
@@ -378,7 +390,7 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */
 
 #if (! defined yyoverflow \
      && (! defined __cplusplus \
-        || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+         || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
 
 /* A type that is properly aligned for any stack member.  */
 union yyalloc
@@ -403,16 +415,16 @@ union yyalloc
    elements in the stack, and YYPTR gives the new location of the
    stack.  Advance YYPTR to a properly aligned location for the next
    stack.  */
-# define YYSTACK_RELOCATE(Stack_alloc, Stack)                          \
-    do                                                                 \
-      {                                                                        \
-       YYSIZE_T yynewbytes;                                            \
-       YYCOPY (&yyptr->Stack_alloc, Stack, yysize);                    \
-       Stack = &yyptr->Stack_alloc;                                    \
-       yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
-       yyptr += yynewbytes / sizeof (*yyptr);                          \
-      }                                                                        \
-    while (YYID (0))
+# define YYSTACK_RELOCATE(Stack_alloc, Stack)                           \
+    do                                                                  \
+      {                                                                 \
+        YYSIZE_T yynewbytes;                                            \
+        YYCOPY (&yyptr->Stack_alloc, Stack, yysize);                    \
+        Stack = &yyptr->Stack_alloc;                                    \
+        yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+        yyptr += yynewbytes / sizeof (*yyptr);                          \
+      }                                                                 \
+    while (0)
 
 #endif
 
@@ -431,7 +443,7 @@ union yyalloc
           for (yyi = 0; yyi < (Count); yyi++)   \
             (Dst)[yyi] = (Src)[yyi];            \
         }                                       \
-      while (YYID (0))
+      while (0)
 #  endif
 # endif
 #endif /* !YYCOPY_NEEDED */
@@ -439,25 +451,27 @@ union yyalloc
 /* YYFINAL -- State number of the termination state.  */
 #define YYFINAL  4
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   515
+#define YYLAST   513
 
 /* YYNTOKENS -- Number of terminals.  */
 #define YYNTOKENS  54
 /* YYNNTS -- Number of nonterminals.  */
 #define YYNNTS  49
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  133
-/* YYNRULES -- Number of states.  */
-#define YYNSTATES  188
+#define YYNRULES  132
+/* YYNSTATES -- Number of states.  */
+#define YYNSTATES  186
 
-/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
+   by yylex, with out-of-bounds checking.  */
 #define YYUNDEFTOK  2
 #define YYMAXUTOK   299
 
-#define YYTRANSLATE(YYX)                                               \
+#define YYTRANSLATE(YYX)                                                \
   ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
 
-/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
+   as returned by yylex, without out-of-bounds checking.  */
 static const yytype_uint8 yytranslate[] =
 {
        0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -493,69 +507,7 @@ static const yytype_uint8 yytranslate[] =
 };
 
 #if YYDEBUG
-/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
-   YYRHS.  */
-static const yytype_uint16 yyprhs[] =
-{
-       0,     0,     3,     5,     8,     9,    12,    13,    18,    19,
-      23,    25,    27,    29,    31,    34,    37,    41,    42,    44,
-      46,    50,    55,    56,    58,    60,    63,    65,    67,    69,
-      71,    73,    75,    77,    79,    81,    86,    88,    91,    94,
-      97,   101,   105,   109,   112,   115,   118,   120,   122,   124,
-     126,   128,   130,   132,   134,   136,   138,   140,   143,   144,
-     146,   148,   151,   153,   155,   157,   159,   162,   164,   166,
-     168,   173,   178,   181,   185,   189,   192,   194,   196,   198,
-     203,   208,   211,   215,   219,   222,   224,   228,   229,   231,
-     233,   237,   240,   243,   245,   246,   248,   250,   255,   260,
-     263,   267,   271,   275,   276,   278,   281,   285,   289,   290,
-     292,   294,   297,   301,   304,   305,   307,   309,   313,   316,
-     319,   321,   324,   325,   328,   332,   337,   339,   343,   345,
-     349,   352,   353,   355
-};
-
-/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
-static const yytype_int8 yyrhs[] =
-{
-      55,     0,    -1,    56,    -1,    55,    56,    -1,    -1,    57,
-      58,    -1,    -1,    12,    23,    59,    61,    -1,    -1,    23,
-      60,    61,    -1,    61,    -1,    85,    -1,   100,    -1,   102,
-      -1,     1,    45,    -1,     1,    46,    -1,    65,    62,    45,
-      -1,    -1,    63,    -1,    64,    -1,    63,    47,    64,    -1,
-      75,   101,    96,    86,    -1,    -1,    66,    -1,    67,    -1,
-      66,    67,    -1,    68,    -1,    69,    -1,     5,    -1,    17,
-      -1,    21,    -1,    11,    -1,    14,    -1,    70,    -1,    74,
-      -1,    28,    48,    82,    49,    -1,    32,    -1,    22,    38,
-      -1,    24,    38,    -1,    10,    38,    -1,    22,    38,    88,
-      -1,    24,    38,    88,    -1,    10,    38,    97,    -1,    10,
-      97,    -1,    22,    88,    -1,    24,    88,    -1,     7,    -1,
-      19,    -1,    15,    -1,    16,    -1,    20,    -1,    25,    -1,
-      13,    -1,     9,    -1,    26,    -1,     6,    -1,    42,    -1,
-      50,    72,    -1,    -1,    73,    -1,    74,    -1,    73,    74,
-      -1,     8,    -1,    27,    -1,    31,    -1,    18,    -1,    71,
-      75,    -1,    76,    -1,    38,    -1,    42,    -1,    76,    48,
-      79,    49,    -1,    76,    48,     1,    49,    -1,    76,    34,
-      -1,    48,    75,    49,    -1,    48,     1,    49,    -1,    71,
-      77,    -1,    78,    -1,    38,    -1,    42,    -1,    78,    48,
-      79,    49,    -1,    78,    48,     1,    49,    -1,    78,    34,
-      -1,    48,    77,    49,    -1,    48,     1,    49,    -1,    80,
-      37,    -1,    80,    -1,    81,    47,    37,    -1,    -1,    81,
-      -1,    82,    -1,    81,    47,    82,    -1,    66,    83,    -1,
-      71,    83,    -1,    84,    -1,    -1,    38,    -1,    42,    -1,
-      84,    48,    79,    49,    -1,    84,    48,     1,    49,    -1,
-      84,    34,    -1,    48,    83,    49,    -1,    48,     1,    49,
-      -1,    65,    75,    33,    -1,    -1,    87,    -1,    51,    35,
-      -1,    52,    89,    46,    -1,    52,     1,    46,    -1,    -1,
-      90,    -1,    91,    -1,    90,    91,    -1,    65,    92,    45,
-      -1,     1,    45,    -1,    -1,    93,    -1,    94,    -1,    93,
-      47,    94,    -1,    77,    96,    -1,    38,    95,    -1,    95,
-      -1,    53,    35,    -1,    -1,    96,    31,    -1,    52,    98,
-      46,    -1,    52,    98,    47,    46,    -1,    99,    -1,    98,
-      47,    99,    -1,    38,    -1,    38,    51,    35,    -1,    30,
-      45,    -1,    -1,    30,    -1,    29,    48,    38,    49,    45,
-      -1
-};
-
-/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+  /* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
        0,   124,   124,   125,   129,   129,   135,   135,   137,   137,
@@ -565,13 +517,13 @@ static const yytype_uint16 yyrline[] =
      237,   239,   241,   246,   249,   250,   254,   255,   256,   257,
      258,   259,   260,   261,   262,   263,   264,   268,   273,   274,
      278,   279,   283,   283,   283,   284,   292,   293,   297,   306,
-     315,   317,   319,   321,   323,   330,   331,   335,   336,   337,
-     339,   341,   343,   345,   350,   351,   352,   356,   357,   361,
-     362,   367,   372,   374,   378,   379,   387,   391,   393,   395,
-     397,   399,   404,   413,   414,   419,   424,   425,   429,   430,
-     434,   435,   439,   441,   446,   447,   451,   452,   456,   457,
-     458,   462,   466,   467,   471,   472,   476,   477,   480,   485,
-     493,   497,   498,   502
+     315,   317,   319,   321,   328,   329,   333,   334,   335,   337,
+     339,   341,   343,   348,   349,   350,   354,   355,   359,   360,
+     365,   370,   372,   376,   377,   385,   389,   391,   393,   395,
+     397,   402,   411,   412,   417,   422,   423,   427,   428,   432,
+     433,   437,   439,   444,   445,   449,   450,   454,   455,   456,
+     460,   464,   465,   469,   470,   474,   475,   478,   483,   491,
+     495,   496,   500
 };
 #endif
 
@@ -606,13 +558,13 @@ static const char *const yytname[] =
   "member_declarator_list_opt", "member_declarator_list",
   "member_declarator", "member_bitfield_declarator", "attribute_opt",
   "enum_body", "enumerator_list", "enumerator", "asm_definition",
-  "asm_phrase_opt", "export_definition", YY_NULL
+  "asm_phrase_opt", "export_definition", YY_NULLPTR
 };
 #endif
 
 # ifdef YYPRINT
-/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
-   token YYLEX-NUM.  */
+/* YYTOKNUM[NUM] -- (External) token number corresponding to the
+   (internal) symbol number NUM (which must be that of a token).  */
 static const yytype_uint16 yytoknum[] =
 {
        0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
@@ -624,47 +576,44 @@ static const yytype_uint16 yytoknum[] =
 };
 # endif
 
-/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
-static const yytype_uint8 yyr1[] =
-{
-       0,    54,    55,    55,    57,    56,    59,    58,    60,    58,
-      58,    58,    58,    58,    58,    58,    61,    62,    62,    63,
-      63,    64,    65,    65,    66,    66,    67,    67,    68,    68,
-      68,    68,    68,    69,    69,    69,    69,    69,    69,    69,
-      69,    69,    69,    69,    69,    69,    70,    70,    70,    70,
-      70,    70,    70,    70,    70,    70,    70,    71,    72,    72,
-      73,    73,    74,    74,    74,    74,    75,    75,    76,    76,
-      76,    76,    76,    76,    76,    77,    77,    78,    78,    78,
-      78,    78,    78,    78,    79,    79,    79,    80,    80,    81,
-      81,    82,    83,    83,    84,    84,    84,    84,    84,    84,
-      84,    84,    85,    86,    86,    87,    88,    88,    89,    89,
-      90,    90,    91,    91,    92,    92,    93,    93,    94,    94,
-      94,    95,    96,    96,    97,    97,    98,    98,    99,    99,
-     100,   101,   101,   102
-};
+#define YYPACT_NINF -135
 
-/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
-static const yytype_uint8 yyr2[] =
+#define yypact_value_is_default(Yystate) \
+  (!!((Yystate) == (-135)))
+
+#define YYTABLE_NINF -109
+
+#define yytable_value_is_error(Yytable_value) \
+  0
+
+  /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+     STATE-NUM.  */
+static const yytype_int16 yypact[] =
 {
-       0,     2,     1,     2,     0,     2,     0,     4,     0,     3,
-       1,     1,     1,     1,     2,     2,     3,     0,     1,     1,
-       3,     4,     0,     1,     1,     2,     1,     1,     1,     1,
-       1,     1,     1,     1,     1,     4,     1,     2,     2,     2,
-       3,     3,     3,     2,     2,     2,     1,     1,     1,     1,
-       1,     1,     1,     1,     1,     1,     1,     2,     0,     1,
-       1,     2,     1,     1,     1,     1,     2,     1,     1,     1,
-       4,     4,     2,     3,     3,     2,     1,     1,     1,     4,
-       4,     2,     3,     3,     2,     1,     3,     0,     1,     1,
-       3,     2,     2,     1,     0,     1,     1,     4,     4,     2,
-       3,     3,     3,     0,     1,     2,     3,     3,     0,     1,
-       1,     2,     3,     2,     0,     1,     1,     3,     2,     2,
-       1,     2,     0,     2,     3,     4,     1,     3,     1,     3,
-       2,     0,     1,     5
+    -135,    38,  -135,   206,  -135,  -135,    22,  -135,  -135,  -135,
+    -135,  -135,   -24,  -135,    20,  -135,  -135,  -135,  -135,  -135,
+    -135,  -135,  -135,  -135,   -23,  -135,     6,  -135,  -135,  -135,
+      -2,    15,    24,  -135,  -135,  -135,  -135,  -135,    41,   471,
+    -135,  -135,  -135,  -135,  -135,  -135,  -135,  -135,  -135,  -135,
+      13,    36,  -135,  -135,    35,   106,  -135,   471,    35,  -135,
+     471,    44,  -135,  -135,  -135,    41,    39,    45,    48,  -135,
+      41,   -10,    25,  -135,  -135,    47,    34,  -135,   471,  -135,
+      26,   -26,    53,   156,  -135,  -135,    41,  -135,   387,    52,
+      57,    59,  -135,    39,  -135,  -135,    41,  -135,  -135,  -135,
+    -135,  -135,   252,    67,  -135,   -21,  -135,  -135,  -135,    51,
+    -135,    12,    83,    46,  -135,    27,    84,    88,  -135,  -135,
+    -135,    91,  -135,   109,  -135,  -135,     3,    55,  -135,    30,
+    -135,    95,  -135,  -135,  -135,   -20,    92,    93,   108,    96,
+    -135,  -135,  -135,  -135,  -135,    97,  -135,    98,  -135,  -135,
+     118,  -135,   297,  -135,   -26,   101,  -135,   104,  -135,  -135,
+     342,  -135,  -135,   120,  -135,  -135,  -135,  -135,  -135,   433,
+    -135,  -135,   111,   119,  -135,  -135,  -135,   130,   136,  -135,
+    -135,  -135,  -135,  -135,  -135,  -135
 };
 
-/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
-   Performed when YYTABLE doesn't specify something else to do.  Zero
-   means the default is an error.  */
+  /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
+     Performed when YYTABLE does not specify something else to do.  Zero
+     means the default is an error.  */
 static const yytype_uint8 yydefact[] =
 {
        4,     4,     2,     0,     1,     3,     0,    28,    55,    46,
@@ -673,191 +622,158 @@ static const yytype_uint8 yydefact[] =
        0,     0,     0,    64,    36,    56,     5,    10,    17,    23,
       24,    26,    27,    33,    34,    11,    12,    13,    14,    15,
       39,     0,    43,     6,    37,     0,    44,    22,    38,    45,
-       0,     0,   130,    68,    69,     0,    58,     0,    18,    19,
-       0,   131,    67,    25,    42,   128,     0,   126,    22,    40,
-       0,   114,     0,     0,   110,     9,    17,    41,    94,     0,
-       0,     0,     0,    57,    59,    60,    16,     0,    66,   132,
-     102,   122,    72,     0,     0,   124,     0,     7,   113,   107,
-      77,    78,     0,     0,     0,   122,    76,     0,   115,   116,
-     120,   106,     0,   111,   131,    95,    56,     0,    94,    91,
-      93,    35,     0,    74,    73,    61,    20,   103,     0,     0,
-      85,    88,    89,   129,   125,   127,   119,     0,    77,     0,
-     121,    75,   118,    81,     0,   112,     0,     0,    96,     0,
-      92,    99,     0,   133,   123,     0,    21,   104,    71,    70,
-      84,     0,    83,    82,     0,     0,   117,   101,   100,     0,
-       0,   105,    86,    90,    80,    79,    98,    97
-};
-
-/* YYDEFGOTO[NTERM-NUM].  */
-static const yytype_int16 yydefgoto[] =
-{
-      -1,     1,     2,     3,    36,    78,    57,    37,    67,    68,
-      69,    81,    39,    40,    41,    42,    43,    70,    93,    94,
-      44,   124,    72,   115,   116,   139,   140,   141,   142,   129,
-     130,    45,   166,   167,    56,    82,    83,    84,   117,   118,
-     119,   120,   137,    52,    76,    77,    46,   101,    47
+       0,     0,   129,    68,    69,     0,    58,     0,    18,    19,
+       0,   130,    67,    25,    42,   127,     0,   125,    22,    40,
+       0,   113,     0,     0,   109,     9,    17,    41,    93,     0,
+       0,     0,    57,    59,    60,    16,     0,    66,   131,   101,
+     121,    72,     0,     0,   123,     0,     7,   112,   106,    76,
+      77,     0,     0,     0,   121,    75,     0,   114,   115,   119,
+     105,     0,   110,   130,    94,    56,     0,    93,    90,    92,
+      35,     0,    73,    61,    20,   102,     0,     0,    84,    87,
+      88,   128,   124,   126,   118,     0,    76,     0,   120,    74,
+     117,    80,     0,   111,     0,     0,    95,     0,    91,    98,
+       0,   132,   122,     0,    21,   103,    71,    70,    83,     0,
+      82,    81,     0,     0,   116,   100,    99,     0,     0,   104,
+      85,    89,    79,    78,    97,    96
 };
 
-/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
-   STATE-NUM.  */
-#define YYPACT_NINF -92
-static const yytype_int16 yypact[] =
+  /* YYPGOTO[NTERM-NUM].  */
+static const yytype_int16 yypgoto[] =
 {
-     -92,    19,   -92,   208,   -92,   -92,    39,   -92,   -92,   -92,
-     -92,   -92,   -27,   -92,    23,   -92,   -92,   -92,   -92,   -92,
-     -92,   -92,   -92,   -92,   -22,   -92,     9,   -92,   -92,   -92,
-      -6,    16,    25,   -92,   -92,   -92,   -92,   -92,    31,   473,
-     -92,   -92,   -92,   -92,   -92,   -92,   -92,   -92,   -92,   -92,
-      49,    37,   -92,   -92,    51,   108,   -92,   473,    51,   -92,
-     473,    59,   -92,   -92,   -92,    12,    -3,    60,    57,   -92,
-      31,    -7,    24,   -92,   -92,    55,    42,   -92,   473,   -92,
-      46,   -21,    61,   158,   -92,   -92,    31,   -92,   389,    71,
-      82,    88,    89,   -92,    -3,   -92,   -92,    31,   -92,   -92,
-     -92,   -92,   -92,   254,    73,   -92,   -24,   -92,   -92,   -92,
-      90,   -92,    17,    75,    45,   -92,    32,    96,    95,   -92,
-     -92,   -92,    99,   -92,   115,   -92,   -92,     3,    48,   -92,
-      34,   -92,   102,   -92,   -92,   -92,   -92,   -11,   100,   103,
-     111,   104,   -92,   -92,   -92,   -92,   -92,   106,   -92,   113,
-     -92,   -92,   126,   -92,   299,   -92,   -21,   121,   -92,   132,
-     -92,   -92,   344,   -92,   -92,   125,   -92,   -92,   -92,   -92,
-     -92,   435,   -92,   -92,   138,   139,   -92,   -92,   -92,   142,
-     143,   -92,   -92,   -92,   -92,   -92,   -92,   -92
+    -135,  -135,   157,  -135,  -135,  -135,  -135,   -48,  -135,  -135,
+      90,    -1,   -60,   -33,  -135,  -135,  -135,   -78,  -135,  -135,
+     -61,   -31,  -135,   -92,  -135,  -134,  -135,  -135,   -59,   -41,
+    -135,  -135,  -135,  -135,   -18,  -135,  -135,   107,  -135,  -135,
+      37,    80,    78,   143,  -135,    94,  -135,  -135,  -135
 };
 
-/* YYPGOTO[NTERM-NUM].  */
-static const yytype_int16 yypgoto[] =
+  /* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int16 yydefgoto[] =
 {
-     -92,   -92,   192,   -92,   -92,   -92,   -92,   -47,   -92,   -92,
-      97,     0,   -60,   -32,   -92,   -92,   -92,   -79,   -92,   -92,
-     -58,   -26,   -92,   -38,   -92,   -91,   -92,   -92,   -59,   -28,
-     -92,   -92,   -92,   -92,   -20,   -92,   -92,   112,   -92,   -92,
-      41,    91,    83,   149,   -92,   101,   -92,   -92,   -92
+      -1,     1,     2,     3,    36,    78,    57,    37,    67,    68,
+      69,    81,    39,    40,    41,    42,    43,    70,    92,    93,
+      44,   123,    72,   114,   115,   137,   138,   139,   140,   128,
+     129,    45,   164,   165,    56,    82,    83,    84,   116,   117,
+     118,   119,   135,    52,    76,    77,    46,   100,    47
 };
 
-/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
-   positive, shift that token.  If negative, reduce the rule which
-   number is the opposite.  If YYTABLE_NINF, syntax error.  */
-#define YYTABLE_NINF -110
+  /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM.  If
+     positive, shift that token.  If negative, reduce the rule whose
+     number is the opposite.  If YYTABLE_NINF, syntax error.  */
 static const yytype_int16 yytable[] =
 {
-      88,    89,   114,    38,   157,    10,    59,    73,    95,   128,
-      85,    50,    71,    91,    75,    20,    54,   110,   147,     4,
-     164,   111,   144,    99,    29,    51,   100,   112,    33,    66,
-      55,   107,   113,   114,    79,   114,   135,   -94,    87,    92,
-     165,   125,    60,    88,    98,   158,    53,    58,   128,   128,
-      63,   127,   -94,    66,    64,   148,    73,    86,   102,   111,
-      65,    55,    66,   175,    61,   112,   153,    66,   161,    63,
-      62,   180,   103,    64,   149,    75,   151,   114,    86,    65,
-     154,    66,   162,   148,    48,    49,   125,   111,   105,   106,
-     158,   108,   109,   112,    88,    66,   127,    90,    66,   159,
-     160,    51,    88,    55,    97,    96,   104,   121,   143,    80,
-     150,    88,   183,     7,     8,     9,    10,    11,    12,    13,
-     131,    15,    16,    17,    18,    19,    20,    21,    22,    23,
-      24,   132,    26,    27,    28,    29,    30,   133,   134,    33,
-      34,   155,   156,   113,   108,    99,   -22,   163,   170,   168,
-      35,   171,   169,   -22,  -108,   172,   -22,   164,   -22,   122,
-     181,   -22,   173,     7,     8,     9,    10,    11,    12,    13,
-     177,    15,    16,    17,    18,    19,    20,    21,    22,    23,
-      24,   178,    26,    27,    28,    29,    30,   184,   185,    33,
-      34,   186,   187,     5,   136,   123,   -22,   176,   152,    74,
-      35,   146,     0,   -22,  -109,     0,   -22,   145,   -22,     6,
-       0,   -22,     0,     7,     8,     9,    10,    11,    12,    13,
-      14,    15,    16,    17,    18,    19,    20,    21,    22,    23,
-      24,    25,    26,    27,    28,    29,    30,    31,    32,    33,
-      34,     0,     0,     0,     0,     0,   -22,     0,     0,     0,
-      35,     0,     0,   -22,     0,   138,   -22,     0,   -22,     7,
-       8,     9,    10,    11,    12,    13,     0,    15,    16,    17,
-      18,    19,    20,    21,    22,    23,    24,     0,    26,    27,
-      28,    29,    30,     0,     0,    33,    34,     0,     0,     0,
-       0,   -87,     0,     0,     0,     0,    35,     0,     0,     0,
-     174,     0,     0,   -87,     7,     8,     9,    10,    11,    12,
-      13,     0,    15,    16,    17,    18,    19,    20,    21,    22,
-      23,    24,     0,    26,    27,    28,    29,    30,     0,     0,
-      33,    34,     0,     0,     0,     0,   -87,     0,     0,     0,
-       0,    35,     0,     0,     0,   179,     0,     0,   -87,     7,
-       8,     9,    10,    11,    12,    13,     0,    15,    16,    17,
-      18,    19,    20,    21,    22,    23,    24,     0,    26,    27,
-      28,    29,    30,     0,     0,    33,    34,     0,     0,     0,
-       0,   -87,     0,     0,     0,     0,    35,     0,     0,     0,
-       0,     0,     0,   -87,     7,     8,     9,    10,    11,    12,
-      13,     0,    15,    16,    17,    18,    19,    20,    21,    22,
-      23,    24,     0,    26,    27,    28,    29,    30,     0,     0,
-      33,    34,     0,     0,     0,     0,     0,   125,     0,     0,
-       0,   126,     0,     0,     0,     0,     0,   127,     0,    66,
-       7,     8,     9,    10,    11,    12,    13,     0,    15,    16,
-      17,    18,    19,    20,    21,    22,    23,    24,     0,    26,
-      27,    28,    29,    30,     0,     0,    33,    34,     0,     0,
-       0,     0,   182,     0,     0,     0,     0,    35,     7,     8,
+      88,    89,    38,   113,   155,    94,    73,    71,    59,    85,
+     127,   162,   109,   145,    50,    54,   110,    75,   173,   147,
+      98,   149,   111,    99,    66,   142,   178,   112,    51,    55,
+     106,   163,   133,   113,    91,   113,    79,   -93,     4,    97,
+      87,   124,    88,    53,    58,   156,    60,    10,   127,   127,
+     146,   126,   -93,    66,   110,    73,    86,    20,    55,   101,
+     111,   151,    66,    61,   159,    51,    29,    48,    49,    62,
+      33,   107,   108,   102,    75,   152,   113,    86,   160,    63,
+     104,   105,    90,    64,   146,   157,   158,    55,   110,    65,
+      95,    66,    88,   124,   111,    96,    66,   156,   103,   120,
+      88,   130,   141,   126,   112,    66,   131,    80,   132,    88,
+     181,     7,     8,     9,    10,    11,    12,    13,   148,    15,
+      16,    17,    18,    19,    20,    21,    22,    23,    24,   153,
+      26,    27,    28,    29,    30,   154,   107,    33,    34,    98,
+     161,   166,   167,   169,   -22,   168,   170,   171,    35,   162,
+     175,   -22,  -107,   176,   -22,   179,   -22,   121,     5,   -22,
+     182,     7,     8,     9,    10,    11,    12,    13,   183,    15,
+      16,    17,    18,    19,    20,    21,    22,    23,    24,   184,
+      26,    27,    28,    29,    30,   185,   134,    33,    34,   144,
+     122,   174,   150,    74,   -22,     0,     0,     0,    35,   143,
+       0,   -22,  -108,     0,   -22,     0,   -22,     6,     0,   -22,
+       0,     7,     8,     9,    10,    11,    12,    13,    14,    15,
+      16,    17,    18,    19,    20,    21,    22,    23,    24,    25,
+      26,    27,    28,    29,    30,    31,    32,    33,    34,     0,
+       0,     0,     0,     0,   -22,     0,     0,     0,    35,     0,
+       0,   -22,     0,   136,   -22,     0,   -22,     7,     8,     9,
+      10,    11,    12,    13,     0,    15,    16,    17,    18,    19,
+      20,    21,    22,    23,    24,     0,    26,    27,    28,    29,
+      30,     0,     0,    33,    34,     0,     0,     0,     0,   -86,
+       0,     0,     0,     0,    35,     0,     0,     0,   172,     0,
+       0,   -86,     7,     8,     9,    10,    11,    12,    13,     0,
+      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
+       0,    26,    27,    28,    29,    30,     0,     0,    33,    34,
+       0,     0,     0,     0,   -86,     0,     0,     0,     0,    35,
+       0,     0,     0,   177,     0,     0,   -86,     7,     8,     9,
+      10,    11,    12,    13,     0,    15,    16,    17,    18,    19,
+      20,    21,    22,    23,    24,     0,    26,    27,    28,    29,
+      30,     0,     0,    33,    34,     0,     0,     0,     0,   -86,
+       0,     0,     0,     0,    35,     0,     0,     0,     0,     0,
+       0,   -86,     7,     8,     9,    10,    11,    12,    13,     0,
+      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
+       0,    26,    27,    28,    29,    30,     0,     0,    33,    34,
+       0,     0,     0,     0,     0,   124,     0,     0,     0,   125,
+       0,     0,     0,     0,     0,   126,     0,    66,     7,     8,
        9,    10,    11,    12,    13,     0,    15,    16,    17,    18,
       19,    20,    21,    22,    23,    24,     0,    26,    27,    28,
       29,    30,     0,     0,    33,    34,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,    35
+     180,     0,     0,     0,     0,    35,     7,     8,     9,    10,
+      11,    12,    13,     0,    15,    16,    17,    18,    19,    20,
+      21,    22,    23,    24,     0,    26,    27,    28,    29,    30,
+       0,     0,    33,    34,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,    35
 };
 
-#define yypact_value_is_default(Yystate) \
-  (!!((Yystate) == (-92)))
-
-#define yytable_value_is_error(Yytable_value) \
-  YYID (0)
-
 static const yytype_int16 yycheck[] =
 {
-      60,    60,    81,     3,     1,     8,    26,    39,    66,    88,
-      57,    38,    38,     1,    38,    18,    38,    38,     1,     0,
-      31,    42,    46,    30,    27,    52,    33,    48,    31,    50,
-      52,    78,    53,   112,    54,   114,    94,    34,    58,    65,
-      51,    38,    48,   103,    70,    42,    23,    38,   127,   128,
-      38,    48,    49,    50,    42,    38,    88,    57,    34,    42,
-      48,    52,    50,   154,    48,    48,    34,    50,    34,    38,
-      45,   162,    48,    42,   112,    38,   114,   156,    78,    48,
-      48,    50,    48,    38,    45,    46,    38,    42,    46,    47,
-      42,    45,    46,    48,   154,    50,    48,    38,    50,   127,
-     128,    52,   162,    52,    47,    45,    51,    46,    35,     1,
-      35,   171,   171,     5,     6,     7,     8,     9,    10,    11,
-      49,    13,    14,    15,    16,    17,    18,    19,    20,    21,
-      22,    49,    24,    25,    26,    27,    28,    49,    49,    31,
-      32,    45,    47,    53,    45,    30,    38,    45,    37,    49,
-      42,    47,    49,    45,    46,    49,    48,    31,    50,     1,
-      35,    53,    49,     5,     6,     7,     8,     9,    10,    11,
-      49,    13,    14,    15,    16,    17,    18,    19,    20,    21,
-      22,    49,    24,    25,    26,    27,    28,    49,    49,    31,
-      32,    49,    49,     1,    97,    83,    38,   156,   115,    50,
-      42,   110,    -1,    45,    46,    -1,    48,   106,    50,     1,
-      -1,    53,    -1,     5,     6,     7,     8,     9,    10,    11,
-      12,    13,    14,    15,    16,    17,    18,    19,    20,    21,
-      22,    23,    24,    25,    26,    27,    28,    29,    30,    31,
-      32,    -1,    -1,    -1,    -1,    -1,    38,    -1,    -1,    -1,
-      42,    -1,    -1,    45,    -1,     1,    48,    -1,    50,     5,
-       6,     7,     8,     9,    10,    11,    -1,    13,    14,    15,
-      16,    17,    18,    19,    20,    21,    22,    -1,    24,    25,
-      26,    27,    28,    -1,    -1,    31,    32,    -1,    -1,    -1,
-      -1,    37,    -1,    -1,    -1,    -1,    42,    -1,    -1,    -1,
-       1,    -1,    -1,    49,     5,     6,     7,     8,     9,    10,
-      11,    -1,    13,    14,    15,    16,    17,    18,    19,    20,
-      21,    22,    -1,    24,    25,    26,    27,    28,    -1,    -1,
-      31,    32,    -1,    -1,    -1,    -1,    37,    -1,    -1,    -1,
-      -1,    42,    -1,    -1,    -1,     1,    -1,    -1,    49,     5,
-       6,     7,     8,     9,    10,    11,    -1,    13,    14,    15,
-      16,    17,    18,    19,    20,    21,    22,    -1,    24,    25,
-      26,    27,    28,    -1,    -1,    31,    32,    -1,    -1,    -1,
-      -1,    37,    -1,    -1,    -1,    -1,    42,    -1,    -1,    -1,
-      -1,    -1,    -1,    49,     5,     6,     7,     8,     9,    10,
-      11,    -1,    13,    14,    15,    16,    17,    18,    19,    20,
-      21,    22,    -1,    24,    25,    26,    27,    28,    -1,    -1,
-      31,    32,    -1,    -1,    -1,    -1,    -1,    38,    -1,    -1,
-      -1,    42,    -1,    -1,    -1,    -1,    -1,    48,    -1,    50,
-       5,     6,     7,     8,     9,    10,    11,    -1,    13,    14,
-      15,    16,    17,    18,    19,    20,    21,    22,    -1,    24,
-      25,    26,    27,    28,    -1,    -1,    31,    32,    -1,    -1,
-      -1,    -1,    37,    -1,    -1,    -1,    -1,    42,     5,     6,
+      60,    60,     3,    81,     1,    66,    39,    38,    26,    57,
+      88,    31,    38,     1,    38,    38,    42,    38,   152,   111,
+      30,   113,    48,    33,    50,    46,   160,    53,    52,    52,
+      78,    51,    93,   111,    65,   113,    54,    34,     0,    70,
+      58,    38,   102,    23,    38,    42,    48,     8,   126,   127,
+      38,    48,    49,    50,    42,    88,    57,    18,    52,    34,
+      48,    34,    50,    48,    34,    52,    27,    45,    46,    45,
+      31,    45,    46,    48,    38,    48,   154,    78,    48,    38,
+      46,    47,    38,    42,    38,   126,   127,    52,    42,    48,
+      45,    50,   152,    38,    48,    47,    50,    42,    51,    46,
+     160,    49,    35,    48,    53,    50,    49,     1,    49,   169,
+     169,     5,     6,     7,     8,     9,    10,    11,    35,    13,
+      14,    15,    16,    17,    18,    19,    20,    21,    22,    45,
+      24,    25,    26,    27,    28,    47,    45,    31,    32,    30,
+      45,    49,    49,    47,    38,    37,    49,    49,    42,    31,
+      49,    45,    46,    49,    48,    35,    50,     1,     1,    53,
+      49,     5,     6,     7,     8,     9,    10,    11,    49,    13,
+      14,    15,    16,    17,    18,    19,    20,    21,    22,    49,
+      24,    25,    26,    27,    28,    49,    96,    31,    32,   109,
+      83,   154,   114,    50,    38,    -1,    -1,    -1,    42,   105,
+      -1,    45,    46,    -1,    48,    -1,    50,     1,    -1,    53,
+      -1,     5,     6,     7,     8,     9,    10,    11,    12,    13,
+      14,    15,    16,    17,    18,    19,    20,    21,    22,    23,
+      24,    25,    26,    27,    28,    29,    30,    31,    32,    -1,
+      -1,    -1,    -1,    -1,    38,    -1,    -1,    -1,    42,    -1,
+      -1,    45,    -1,     1,    48,    -1,    50,     5,     6,     7,
+       8,     9,    10,    11,    -1,    13,    14,    15,    16,    17,
+      18,    19,    20,    21,    22,    -1,    24,    25,    26,    27,
+      28,    -1,    -1,    31,    32,    -1,    -1,    -1,    -1,    37,
+      -1,    -1,    -1,    -1,    42,    -1,    -1,    -1,     1,    -1,
+      -1,    49,     5,     6,     7,     8,     9,    10,    11,    -1,
+      13,    14,    15,    16,    17,    18,    19,    20,    21,    22,
+      -1,    24,    25,    26,    27,    28,    -1,    -1,    31,    32,
+      -1,    -1,    -1,    -1,    37,    -1,    -1,    -1,    -1,    42,
+      -1,    -1,    -1,     1,    -1,    -1,    49,     5,     6,     7,
+       8,     9,    10,    11,    -1,    13,    14,    15,    16,    17,
+      18,    19,    20,    21,    22,    -1,    24,    25,    26,    27,
+      28,    -1,    -1,    31,    32,    -1,    -1,    -1,    -1,    37,
+      -1,    -1,    -1,    -1,    42,    -1,    -1,    -1,    -1,    -1,
+      -1,    49,     5,     6,     7,     8,     9,    10,    11,    -1,
+      13,    14,    15,    16,    17,    18,    19,    20,    21,    22,
+      -1,    24,    25,    26,    27,    28,    -1,    -1,    31,    32,
+      -1,    -1,    -1,    -1,    -1,    38,    -1,    -1,    -1,    42,
+      -1,    -1,    -1,    -1,    -1,    48,    -1,    50,     5,     6,
        7,     8,     9,    10,    11,    -1,    13,    14,    15,    16,
       17,    18,    19,    20,    21,    22,    -1,    24,    25,    26,
       27,    28,    -1,    -1,    31,    32,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    42
+      37,    -1,    -1,    -1,    -1,    42,     5,     6,     7,     8,
+       9,    10,    11,    -1,    13,    14,    15,    16,    17,    18,
+      19,    20,    21,    22,    -1,    24,    25,    26,    27,    28,
+      -1,    -1,    31,    32,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    42
 };
 
-/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
-   symbol of state STATE-NUM.  */
+  /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+     symbol of state STATE-NUM.  */
 static const yytype_uint8 yystos[] =
 {
        0,    55,    56,    57,     0,    56,     1,     5,     6,     7,
@@ -869,42 +785,66 @@ static const yytype_uint8 yystos[] =
       48,    48,    45,    38,    42,    48,    50,    62,    63,    64,
       71,    75,    76,    67,    97,    38,    98,    99,    59,    88,
        1,    65,    89,    90,    91,    61,    65,    88,    66,    82,
-      38,     1,    75,    72,    73,    74,    45,    47,    75,    30,
-      33,   101,    34,    48,    51,    46,    47,    61,    45,    46,
-      38,    42,    48,    53,    71,    77,    78,    92,    93,    94,
-      95,    46,     1,    91,    75,    38,    42,    48,    71,    83,
-      84,    49,    49,    49,    49,    74,    64,    96,     1,    79,
-      80,    81,    82,    35,    46,    99,    95,     1,    38,    77,
-      35,    77,    96,    34,    48,    45,    47,     1,    42,    83,
-      83,    34,    48,    45,    31,    51,    86,    87,    49,    49,
-      37,    47,    49,    49,     1,    79,    94,    49,    49,     1,
-      79,    35,    37,    82,    49,    49,    49,    49
+      38,    75,    72,    73,    74,    45,    47,    75,    30,    33,
+     101,    34,    48,    51,    46,    47,    61,    45,    46,    38,
+      42,    48,    53,    71,    77,    78,    92,    93,    94,    95,
+      46,     1,    91,    75,    38,    42,    48,    71,    83,    84,
+      49,    49,    49,    74,    64,    96,     1,    79,    80,    81,
+      82,    35,    46,    99,    95,     1,    38,    77,    35,    77,
+      96,    34,    48,    45,    47,     1,    42,    83,    83,    34,
+      48,    45,    31,    51,    86,    87,    49,    49,    37,    47,
+      49,    49,     1,    79,    94,    49,    49,     1,    79,    35,
+      37,    82,    49,    49,    49,    49
 };
 
-#define yyerrok                (yyerrstatus = 0)
-#define yyclearin      (yychar = YYEMPTY)
-#define YYEMPTY                (-2)
-#define YYEOF          0
-
-#define YYACCEPT       goto yyacceptlab
-#define YYABORT                goto yyabortlab
-#define YYERROR                goto yyerrorlab
-
-
-/* Like YYERROR except do call yyerror.  This remains here temporarily
-   to ease the transition to the new meaning of YYERROR, for GCC.
-   Once GCC version 2 has supplanted version 1, this can go.  However,
-   YYFAIL appears to be in use.  Nevertheless, it is formally deprecated
-   in Bison 2.4.2's NEWS entry, where a plan to phase it out is
-   discussed.  */
-
-#define YYFAIL         goto yyerrlab
-#if defined YYFAIL
-  /* This is here to suppress warnings from the GCC cpp's
-     -Wunused-macros.  Normally we don't worry about that warning, but
-     some users do, and we want to make it easy for users to remove
-     YYFAIL uses, which will produce warnings from Bison 2.5.  */
-#endif
+  /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint8 yyr1[] =
+{
+       0,    54,    55,    55,    57,    56,    59,    58,    60,    58,
+      58,    58,    58,    58,    58,    58,    61,    62,    62,    63,
+      63,    64,    65,    65,    66,    66,    67,    67,    68,    68,
+      68,    68,    68,    69,    69,    69,    69,    69,    69,    69,
+      69,    69,    69,    69,    69,    69,    70,    70,    70,    70,
+      70,    70,    70,    70,    70,    70,    70,    71,    72,    72,
+      73,    73,    74,    74,    74,    74,    75,    75,    76,    76,
+      76,    76,    76,    76,    77,    77,    78,    78,    78,    78,
+      78,    78,    78,    79,    79,    79,    80,    80,    81,    81,
+      82,    83,    83,    84,    84,    84,    84,    84,    84,    84,
+      84,    85,    86,    86,    87,    88,    88,    89,    89,    90,
+      90,    91,    91,    92,    92,    93,    93,    94,    94,    94,
+      95,    96,    96,    97,    97,    98,    98,    99,    99,   100,
+     101,   101,   102
+};
+
+  /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     1,     2,     0,     2,     0,     4,     0,     3,
+       1,     1,     1,     1,     2,     2,     3,     0,     1,     1,
+       3,     4,     0,     1,     1,     2,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     4,     1,     2,     2,     2,
+       3,     3,     3,     2,     2,     2,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     1,     1,     2,     0,     1,
+       1,     2,     1,     1,     1,     1,     2,     1,     1,     1,
+       4,     4,     2,     3,     2,     1,     1,     1,     4,     4,
+       2,     3,     3,     2,     1,     3,     0,     1,     1,     3,
+       2,     2,     1,     0,     1,     1,     4,     4,     2,     3,
+       3,     3,     0,     1,     2,     3,     3,     0,     1,     1,
+       2,     3,     2,     0,     1,     1,     3,     2,     2,     1,
+       2,     0,     2,     3,     4,     1,     3,     1,     3,     2,
+       0,     1,     5
+};
+
+
+#define yyerrok         (yyerrstatus = 0)
+#define yyclearin       (yychar = YYEMPTY)
+#define YYEMPTY         (-2)
+#define YYEOF           0
+
+#define YYACCEPT        goto yyacceptlab
+#define YYABORT         goto yyabortlab
+#define YYERROR         goto yyerrorlab
+
 
 #define YYRECOVERING()  (!!yyerrstatus)
 
@@ -921,27 +861,15 @@ do                                                              \
   else                                                          \
     {                                                           \
       yyerror (YY_("syntax error: cannot back up")); \
-      YYERROR;                                                 \
-    }                                                          \
-while (YYID (0))
+      YYERROR;                                                  \
+    }                                                           \
+while (0)
 
 /* Error token number */
-#define YYTERROR       1
-#define YYERRCODE      256
+#define YYTERROR        1
+#define YYERRCODE       256
 
 
-/* This macro is provided for backward compatibility. */
-#ifndef YY_LOCATION_PRINT
-# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
-#endif
-
-
-/* YYLEX -- calling `yylex' with the right arguments.  */
-#ifdef YYLEX_PARAM
-# define YYLEX yylex (YYLEX_PARAM)
-#else
-# define YYLEX yylex ()
-#endif
 
 /* Enable debugging if requested.  */
 #if YYDEBUG
@@ -951,40 +879,36 @@ while (YYID (0))
 #  define YYFPRINTF fprintf
 # endif
 
-# define YYDPRINTF(Args)                       \
-do {                                           \
-  if (yydebug)                                 \
-    YYFPRINTF Args;                            \
-} while (YYID (0))
+# define YYDPRINTF(Args)                        \
+do {                                            \
+  if (yydebug)                                  \
+    YYFPRINTF Args;                             \
+} while (0)
+
+/* This macro is provided for backward compatibility. */
+#ifndef YY_LOCATION_PRINT
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+#endif
+
 
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)                   \
-do {                                                                     \
-  if (yydebug)                                                           \
-    {                                                                    \
-      YYFPRINTF (stderr, "%s ", Title);                                          \
-      yy_symbol_print (stderr,                                           \
-                 Type, Value); \
-      YYFPRINTF (stderr, "\n");                                                  \
-    }                                                                    \
-} while (YYID (0))
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)                    \
+do {                                                                      \
+  if (yydebug)                                                            \
+    {                                                                     \
+      YYFPRINTF (stderr, "%s ", Title);                                   \
+      yy_symbol_print (stderr,                                            \
+                  Type, Value); \
+      YYFPRINTF (stderr, "\n");                                           \
+    }                                                                     \
+} while (0)
 
 
-/*--------------------------------.
-| Print this symbol on YYOUTPUT.  |
-`--------------------------------*/
+/*----------------------------------------.
+| Print this symbol's value on YYOUTPUT.  |
+`----------------------------------------*/
 
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
 static void
 yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_value_print (yyoutput, yytype, yyvaluep)
-    FILE *yyoutput;
-    int yytype;
-    YYSTYPE const * const yyvaluep;
-#endif
 {
   FILE *yyo = yyoutput;
   YYUSE (yyo);
@@ -993,14 +917,8 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep)
 # ifdef YYPRINT
   if (yytype < YYNTOKENS)
     YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
-# else
-  YYUSE (yyoutput);
 # endif
-  switch (yytype)
-    {
-      default:
-        break;
-    }
+  YYUSE (yytype);
 }
 
 
@@ -1008,22 +926,11 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep)
 | Print this symbol on YYOUTPUT.  |
 `--------------------------------*/
 
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
 static void
 yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_print (yyoutput, yytype, yyvaluep)
-    FILE *yyoutput;
-    int yytype;
-    YYSTYPE const * const yyvaluep;
-#endif
 {
-  if (yytype < YYNTOKENS)
-    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
-  else
-    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+  YYFPRINTF (yyoutput, "%s %s (",
+             yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]);
 
   yy_symbol_value_print (yyoutput, yytype, yyvaluep);
   YYFPRINTF (yyoutput, ")");
@@ -1034,16 +941,8 @@ yy_symbol_print (yyoutput, yytype, yyvaluep)
 | TOP (included).                                                   |
 `------------------------------------------------------------------*/
 
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
 static void
 yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
-#else
-static void
-yy_stack_print (yybottom, yytop)
-    yytype_int16 *yybottom;
-    yytype_int16 *yytop;
-#endif
 {
   YYFPRINTF (stderr, "Stack now");
   for (; yybottom <= yytop; yybottom++)
@@ -1054,49 +953,42 @@ yy_stack_print (yybottom, yytop)
   YYFPRINTF (stderr, "\n");
 }
 
-# define YY_STACK_PRINT(Bottom, Top)                           \
-do {                                                           \
-  if (yydebug)                                                 \
-    yy_stack_print ((Bottom), (Top));                          \
-} while (YYID (0))
+# define YY_STACK_PRINT(Bottom, Top)                            \
+do {                                                            \
+  if (yydebug)                                                  \
+    yy_stack_print ((Bottom), (Top));                           \
+} while (0)
 
 
 /*------------------------------------------------.
 | Report that the YYRULE is going to be reduced.  |
 `------------------------------------------------*/
 
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
 static void
-yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
-#else
-static void
-yy_reduce_print (yyvsp, yyrule)
-    YYSTYPE *yyvsp;
-    int yyrule;
-#endif
+yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule)
 {
+  unsigned long int yylno = yyrline[yyrule];
   int yynrhs = yyr2[yyrule];
   int yyi;
-  unsigned long int yylno = yyrline[yyrule];
   YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
-            yyrule - 1, yylno);
+             yyrule - 1, yylno);
   /* The symbols being reduced.  */
   for (yyi = 0; yyi < yynrhs; yyi++)
     {
       YYFPRINTF (stderr, "   $%d = ", yyi + 1);
-      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
-                      &(yyvsp[(yyi + 1) - (yynrhs)])
-                                      );
+      yy_symbol_print (stderr,
+                       yystos[yyssp[yyi + 1 - yynrhs]],
+                       &(yyvsp[(yyi + 1) - (yynrhs)])
+                                              );
       YYFPRINTF (stderr, "\n");
     }
 }
 
-# define YY_REDUCE_PRINT(Rule)         \
-do {                                   \
-  if (yydebug)                         \
-    yy_reduce_print (yyvsp, Rule); \
-} while (YYID (0))
+# define YY_REDUCE_PRINT(Rule)          \
+do {                                    \
+  if (yydebug)                          \
+    yy_reduce_print (yyssp, yyvsp, Rule); \
+} while (0)
 
 /* Nonzero means print parse trace.  It is left uninitialized so that
    multiple parsers can coexist.  */
@@ -1110,7 +1002,7 @@ int yydebug;
 
 
 /* YYINITDEPTH -- initial size of the parser's stacks.  */
-#ifndef        YYINITDEPTH
+#ifndef YYINITDEPTH
 # define YYINITDEPTH 200
 #endif
 
@@ -1133,15 +1025,8 @@ int yydebug;
 #   define yystrlen strlen
 #  else
 /* Return the length of YYSTR.  */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
 static YYSIZE_T
 yystrlen (const char *yystr)
-#else
-static YYSIZE_T
-yystrlen (yystr)
-    const char *yystr;
-#endif
 {
   YYSIZE_T yylen;
   for (yylen = 0; yystr[yylen]; yylen++)
@@ -1157,16 +1042,8 @@ yystrlen (yystr)
 #  else
 /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
    YYDEST.  */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
 static char *
 yystpcpy (char *yydest, const char *yysrc)
-#else
-static char *
-yystpcpy (yydest, yysrc)
-    char *yydest;
-    const char *yysrc;
-#endif
 {
   char *yyd = yydest;
   const char *yys = yysrc;
@@ -1196,27 +1073,27 @@ yytnamerr (char *yyres, const char *yystr)
       char const *yyp = yystr;
 
       for (;;)
-       switch (*++yyp)
-         {
-         case '\'':
-         case ',':
-           goto do_not_strip_quotes;
-
-         case '\\':
-           if (*++yyp != '\\')
-             goto do_not_strip_quotes;
-           /* Fall through.  */
-         default:
-           if (yyres)
-             yyres[yyn] = *yyp;
-           yyn++;
-           break;
-
-         case '"':
-           if (yyres)
-             yyres[yyn] = '\0';
-           return yyn;
-         }
+        switch (*++yyp)
+          {
+          case '\'':
+          case ',':
+            goto do_not_strip_quotes;
+
+          case '\\':
+            if (*++yyp != '\\')
+              goto do_not_strip_quotes;
+            /* Fall through.  */
+          default:
+            if (yyres)
+              yyres[yyn] = *yyp;
+            yyn++;
+            break;
+
+          case '"':
+            if (yyres)
+              yyres[yyn] = '\0';
+            return yyn;
+          }
     do_not_strip_quotes: ;
     }
 
@@ -1239,11 +1116,11 @@ static int
 yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
                 yytype_int16 *yyssp, int yytoken)
 {
-  YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]);
+  YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]);
   YYSIZE_T yysize = yysize0;
   enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
   /* Internationalized format string. */
-  const char *yyformat = YY_NULL;
+  const char *yyformat = YY_NULLPTR;
   /* Arguments of yyformat. */
   char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
   /* Number of reported tokens (one for the "unexpected", one per
@@ -1251,10 +1128,6 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
   int yycount = 0;
 
   /* There are many possibilities here to consider:
-     - Assume YYFAIL is not used.  It's too flawed to consider.  See
-       <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
-       for details.  YYERROR is fine as it does not invoke this
-       function.
      - If this state is a consistent state with a default action, then
        the only way this function was invoked is if the default action
        is an error action.  In that case, don't check for expected
@@ -1304,7 +1177,7 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
                   }
                 yyarg[yycount++] = yytname[yyx];
                 {
-                  YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]);
+                  YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]);
                   if (! (yysize <= yysize1
                          && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
                     return 2;
@@ -1371,31 +1244,17 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
 | Release the memory associated to this symbol.  |
 `-----------------------------------------------*/
 
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
 static void
 yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
-#else
-static void
-yydestruct (yymsg, yytype, yyvaluep)
-    const char *yymsg;
-    int yytype;
-    YYSTYPE *yyvaluep;
-#endif
 {
   YYUSE (yyvaluep);
-
   if (!yymsg)
     yymsg = "Deleting";
   YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
 
-  switch (yytype)
-    {
-
-      default:
-        break;
-    }
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+  YYUSE (yytype);
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
 }
 
 
@@ -1404,18 +1263,8 @@ yydestruct (yymsg, yytype, yyvaluep)
 /* The lookahead symbol.  */
 int yychar;
 
-
-#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-# define YY_IGNORE_MAYBE_UNINITIALIZED_END
-#endif
-#ifndef YY_INITIAL_VALUE
-# define YY_INITIAL_VALUE(Value) /* Nothing. */
-#endif
-
 /* The semantic value of the lookahead symbol.  */
-YYSTYPE yylval YY_INITIAL_VALUE(yyval_default);
-
+YYSTYPE yylval;
 /* Number of syntax errors so far.  */
 int yynerrs;
 
@@ -1424,35 +1273,16 @@ int yynerrs;
 | yyparse.  |
 `----------*/
 
-#ifdef YYPARSE_PARAM
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void *YYPARSE_PARAM)
-#else
-int
-yyparse (YYPARSE_PARAM)
-    void *YYPARSE_PARAM;
-#endif
-#else /* ! YYPARSE_PARAM */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
 int
 yyparse (void)
-#else
-int
-yyparse ()
-
-#endif
-#endif
 {
     int yystate;
     /* Number of tokens to shift before error messages enabled.  */
     int yyerrstatus;
 
     /* The stacks and their tools:
-       `yyss': related to states.
-       `yyvs': related to semantic values.
+       'yyss': related to states.
+       'yyvs': related to semantic values.
 
        Refer to the stacks through separate pointers, to allow yyoverflow
        to reallocate them elsewhere.  */
@@ -1520,23 +1350,23 @@ yyparse ()
 
 #ifdef yyoverflow
       {
-       /* Give user a chance to reallocate the stack.  Use copies of
-          these so that the &'s don't force the real ones into
-          memory.  */
-       YYSTYPE *yyvs1 = yyvs;
-       yytype_int16 *yyss1 = yyss;
-
-       /* Each stack pointer address is followed by the size of the
-          data in use in that stack, in bytes.  This used to be a
-          conditional around just the two extra args, but that might
-          be undefined if yyoverflow is a macro.  */
-       yyoverflow (YY_("memory exhausted"),
-                   &yyss1, yysize * sizeof (*yyssp),
-                   &yyvs1, yysize * sizeof (*yyvsp),
-                   &yystacksize);
-
-       yyss = yyss1;
-       yyvs = yyvs1;
+        /* Give user a chance to reallocate the stack.  Use copies of
+           these so that the &'s don't force the real ones into
+           memory.  */
+        YYSTYPE *yyvs1 = yyvs;
+        yytype_int16 *yyss1 = yyss;
+
+        /* Each stack pointer address is followed by the size of the
+           data in use in that stack, in bytes.  This used to be a
+           conditional around just the two extra args, but that might
+           be undefined if yyoverflow is a macro.  */
+        yyoverflow (YY_("memory exhausted"),
+                    &yyss1, yysize * sizeof (*yyssp),
+                    &yyvs1, yysize * sizeof (*yyvsp),
+                    &yystacksize);
+
+        yyss = yyss1;
+        yyvs = yyvs1;
       }
 #else /* no yyoverflow */
 # ifndef YYSTACK_RELOCATE
@@ -1544,22 +1374,22 @@ yyparse ()
 # else
       /* Extend the stack our own way.  */
       if (YYMAXDEPTH <= yystacksize)
-       goto yyexhaustedlab;
+        goto yyexhaustedlab;
       yystacksize *= 2;
       if (YYMAXDEPTH < yystacksize)
-       yystacksize = YYMAXDEPTH;
+        yystacksize = YYMAXDEPTH;
 
       {
-       yytype_int16 *yyss1 = yyss;
-       union yyalloc *yyptr =
-         (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
-       if (! yyptr)
-         goto yyexhaustedlab;
-       YYSTACK_RELOCATE (yyss_alloc, yyss);
-       YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+        yytype_int16 *yyss1 = yyss;
+        union yyalloc *yyptr =
+          (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+        if (! yyptr)
+          goto yyexhaustedlab;
+        YYSTACK_RELOCATE (yyss_alloc, yyss);
+        YYSTACK_RELOCATE (yyvs_alloc, yyvs);
 #  undef YYSTACK_RELOCATE
-       if (yyss1 != yyssa)
-         YYSTACK_FREE (yyss1);
+        if (yyss1 != yyssa)
+          YYSTACK_FREE (yyss1);
       }
 # endif
 #endif /* no yyoverflow */
@@ -1568,10 +1398,10 @@ yyparse ()
       yyvsp = yyvs + yysize - 1;
 
       YYDPRINTF ((stderr, "Stack size increased to %lu\n",
-                 (unsigned long int) yystacksize));
+                  (unsigned long int) yystacksize));
 
       if (yyss + yystacksize - 1 <= yyssp)
-       YYABORT;
+        YYABORT;
     }
 
   YYDPRINTF ((stderr, "Entering state %d\n", yystate));
@@ -1600,7 +1430,7 @@ yybackup:
   if (yychar == YYEMPTY)
     {
       YYDPRINTF ((stderr, "Reading a token: "));
-      yychar = YYLEX;
+      yychar = yylex ();
     }
 
   if (yychar <= YYEOF)
@@ -1665,7 +1495,7 @@ yyreduce:
   yylen = yyr2[yyn];
 
   /* If YYLEN is nonzero, implement the default value of the action:
-     `$$ = $1'.
+     '$$ = $1'.
 
      Otherwise, the following line sets YYVAL to garbage.
      This behavior is undocumented and Bison
@@ -1679,483 +1509,560 @@ yyreduce:
   switch (yyn)
     {
         case 4:
-
+#line 129 "parse.y" /* yacc.c:1646  */
     { is_typedef = 0; is_extern = 0; current_name = NULL; decl_spec = NULL; }
+#line 1515 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 5:
-
-    { free_list(*(yyvsp[(2) - (2)]), NULL); *(yyvsp[(2) - (2)]) = NULL; }
+#line 131 "parse.y" /* yacc.c:1646  */
+    { free_list(*(yyvsp[0]), NULL); *(yyvsp[0]) = NULL; }
+#line 1521 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 6:
-
+#line 135 "parse.y" /* yacc.c:1646  */
     { is_typedef = 1; }
+#line 1527 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 7:
-
-    { (yyval) = (yyvsp[(4) - (4)]); }
+#line 136 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1533 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 8:
-
+#line 137 "parse.y" /* yacc.c:1646  */
     { is_typedef = 1; }
+#line 1539 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 9:
-
-    { (yyval) = (yyvsp[(3) - (3)]); }
+#line 138 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1545 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 14:
-
-    { (yyval) = (yyvsp[(2) - (2)]); }
+#line 143 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1551 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 15:
-
-    { (yyval) = (yyvsp[(2) - (2)]); }
+#line 144 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1557 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 16:
-
+#line 149 "parse.y" /* yacc.c:1646  */
     { if (current_name) {
-                   struct string_list *decl = (*(yyvsp[(3) - (3)]))->next;
-                   (*(yyvsp[(3) - (3)]))->next = NULL;
+                   struct string_list *decl = (*(yyvsp[0]))->next;
+                   (*(yyvsp[0]))->next = NULL;
                    add_symbol(current_name,
                               is_typedef ? SYM_TYPEDEF : SYM_NORMAL,
                               decl, is_extern);
                    current_name = NULL;
                  }
-                 (yyval) = (yyvsp[(3) - (3)]);
+                 (yyval) = (yyvsp[0]);
                }
+#line 1572 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 17:
-
+#line 162 "parse.y" /* yacc.c:1646  */
     { (yyval) = NULL; }
+#line 1578 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 19:
-
-    { struct string_list *decl = *(yyvsp[(1) - (1)]);
-                 *(yyvsp[(1) - (1)]) = NULL;
+#line 168 "parse.y" /* yacc.c:1646  */
+    { struct string_list *decl = *(yyvsp[0]);
+                 *(yyvsp[0]) = NULL;
                  add_symbol(current_name,
                             is_typedef ? SYM_TYPEDEF : SYM_NORMAL, decl, is_extern);
                  current_name = NULL;
-                 (yyval) = (yyvsp[(1) - (1)]);
+                 (yyval) = (yyvsp[0]);
                }
+#line 1590 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 20:
-
-    { struct string_list *decl = *(yyvsp[(3) - (3)]);
-                 *(yyvsp[(3) - (3)]) = NULL;
-                 free_list(*(yyvsp[(2) - (3)]), NULL);
-                 *(yyvsp[(2) - (3)]) = decl_spec;
+#line 176 "parse.y" /* yacc.c:1646  */
+    { struct string_list *decl = *(yyvsp[0]);
+                 *(yyvsp[0]) = NULL;
+                 free_list(*(yyvsp[-1]), NULL);
+                 *(yyvsp[-1]) = decl_spec;
                  add_symbol(current_name,
                             is_typedef ? SYM_TYPEDEF : SYM_NORMAL, decl, is_extern);
                  current_name = NULL;
-                 (yyval) = (yyvsp[(3) - (3)]);
+                 (yyval) = (yyvsp[0]);
                }
+#line 1604 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 21:
-
-    { (yyval) = (yyvsp[(4) - (4)]) ? (yyvsp[(4) - (4)]) : (yyvsp[(3) - (4)]) ? (yyvsp[(3) - (4)]) : (yyvsp[(2) - (4)]) ? (yyvsp[(2) - (4)]) : (yyvsp[(1) - (4)]); }
+#line 189 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]) ? (yyvsp[0]) : (yyvsp[-1]) ? (yyvsp[-1]) : (yyvsp[-2]) ? (yyvsp[-2]) : (yyvsp[-3]); }
+#line 1610 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 22:
-
+#line 194 "parse.y" /* yacc.c:1646  */
     { decl_spec = NULL; }
+#line 1616 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 24:
-
-    { decl_spec = *(yyvsp[(1) - (1)]); }
+#line 199 "parse.y" /* yacc.c:1646  */
+    { decl_spec = *(yyvsp[0]); }
+#line 1622 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 25:
-
-    { decl_spec = *(yyvsp[(2) - (2)]); }
+#line 200 "parse.y" /* yacc.c:1646  */
+    { decl_spec = *(yyvsp[0]); }
+#line 1628 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 26:
-
+#line 205 "parse.y" /* yacc.c:1646  */
     { /* Version 2 checksumming ignores storage class, as that
                     is really irrelevant to the linkage.  */
-                 remove_node((yyvsp[(1) - (1)]));
-                 (yyval) = (yyvsp[(1) - (1)]);
+                 remove_node((yyvsp[0]));
+                 (yyval) = (yyvsp[0]);
                }
+#line 1638 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 31:
-
-    { is_extern = 1; (yyval) = (yyvsp[(1) - (1)]); }
+#line 217 "parse.y" /* yacc.c:1646  */
+    { is_extern = 1; (yyval) = (yyvsp[0]); }
+#line 1644 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 32:
-
-    { is_extern = 0; (yyval) = (yyvsp[(1) - (1)]); }
+#line 218 "parse.y" /* yacc.c:1646  */
+    { is_extern = 0; (yyval) = (yyvsp[0]); }
+#line 1650 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 37:
-
-    { remove_node((yyvsp[(1) - (2)])); (*(yyvsp[(2) - (2)]))->tag = SYM_STRUCT; (yyval) = (yyvsp[(2) - (2)]); }
+#line 230 "parse.y" /* yacc.c:1646  */
+    { remove_node((yyvsp[-1])); (*(yyvsp[0]))->tag = SYM_STRUCT; (yyval) = (yyvsp[0]); }
+#line 1656 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 38:
-
-    { remove_node((yyvsp[(1) - (2)])); (*(yyvsp[(2) - (2)]))->tag = SYM_UNION; (yyval) = (yyvsp[(2) - (2)]); }
+#line 232 "parse.y" /* yacc.c:1646  */
+    { remove_node((yyvsp[-1])); (*(yyvsp[0]))->tag = SYM_UNION; (yyval) = (yyvsp[0]); }
+#line 1662 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 39:
-
-    { remove_node((yyvsp[(1) - (2)])); (*(yyvsp[(2) - (2)]))->tag = SYM_ENUM; (yyval) = (yyvsp[(2) - (2)]); }
+#line 234 "parse.y" /* yacc.c:1646  */
+    { remove_node((yyvsp[-1])); (*(yyvsp[0]))->tag = SYM_ENUM; (yyval) = (yyvsp[0]); }
+#line 1668 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 40:
-
-    { record_compound((yyvsp[(1) - (3)]), (yyvsp[(2) - (3)]), (yyvsp[(3) - (3)]), SYM_STRUCT); (yyval) = (yyvsp[(3) - (3)]); }
+#line 238 "parse.y" /* yacc.c:1646  */
+    { record_compound((yyvsp[-2]), (yyvsp[-1]), (yyvsp[0]), SYM_STRUCT); (yyval) = (yyvsp[0]); }
+#line 1674 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 41:
-
-    { record_compound((yyvsp[(1) - (3)]), (yyvsp[(2) - (3)]), (yyvsp[(3) - (3)]), SYM_UNION); (yyval) = (yyvsp[(3) - (3)]); }
+#line 240 "parse.y" /* yacc.c:1646  */
+    { record_compound((yyvsp[-2]), (yyvsp[-1]), (yyvsp[0]), SYM_UNION); (yyval) = (yyvsp[0]); }
+#line 1680 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 42:
-
-    { record_compound((yyvsp[(1) - (3)]), (yyvsp[(2) - (3)]), (yyvsp[(3) - (3)]), SYM_ENUM); (yyval) = (yyvsp[(3) - (3)]); }
+#line 242 "parse.y" /* yacc.c:1646  */
+    { record_compound((yyvsp[-2]), (yyvsp[-1]), (yyvsp[0]), SYM_ENUM); (yyval) = (yyvsp[0]); }
+#line 1686 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 43:
-
-    { add_symbol(NULL, SYM_ENUM, NULL, 0); (yyval) = (yyvsp[(2) - (2)]); }
+#line 247 "parse.y" /* yacc.c:1646  */
+    { add_symbol(NULL, SYM_ENUM, NULL, 0); (yyval) = (yyvsp[0]); }
+#line 1692 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 44:
-
-    { (yyval) = (yyvsp[(2) - (2)]); }
+#line 249 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1698 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 45:
-
-    { (yyval) = (yyvsp[(2) - (2)]); }
+#line 250 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1704 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 56:
-
-    { (*(yyvsp[(1) - (1)]))->tag = SYM_TYPEDEF; (yyval) = (yyvsp[(1) - (1)]); }
+#line 264 "parse.y" /* yacc.c:1646  */
+    { (*(yyvsp[0]))->tag = SYM_TYPEDEF; (yyval) = (yyvsp[0]); }
+#line 1710 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 57:
-
-    { (yyval) = (yyvsp[(2) - (2)]) ? (yyvsp[(2) - (2)]) : (yyvsp[(1) - (2)]); }
+#line 269 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]) ? (yyvsp[0]) : (yyvsp[-1]); }
+#line 1716 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 58:
-
+#line 273 "parse.y" /* yacc.c:1646  */
     { (yyval) = NULL; }
+#line 1722 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 61:
-
-    { (yyval) = (yyvsp[(2) - (2)]); }
+#line 279 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1728 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 65:
-
+#line 285 "parse.y" /* yacc.c:1646  */
     { /* restrict has no effect in prototypes so ignore it */
-                 remove_node((yyvsp[(1) - (1)]));
-                 (yyval) = (yyvsp[(1) - (1)]);
+                 remove_node((yyvsp[0]));
+                 (yyval) = (yyvsp[0]);
                }
+#line 1737 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 66:
-
-    { (yyval) = (yyvsp[(2) - (2)]); }
+#line 292 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1743 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 68:
-
+#line 298 "parse.y" /* yacc.c:1646  */
     { if (current_name != NULL) {
                    error_with_pos("unexpected second declaration name");
                    YYERROR;
                  } else {
-                   current_name = (*(yyvsp[(1) - (1)]))->string;
-                   (yyval) = (yyvsp[(1) - (1)]);
+                   current_name = (*(yyvsp[0]))->string;
+                   (yyval) = (yyvsp[0]);
                  }
                }
+#line 1756 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 69:
-
+#line 307 "parse.y" /* yacc.c:1646  */
     { if (current_name != NULL) {
                    error_with_pos("unexpected second declaration name");
                    YYERROR;
                  } else {
-                   current_name = (*(yyvsp[(1) - (1)]))->string;
-                   (yyval) = (yyvsp[(1) - (1)]);
+                   current_name = (*(yyvsp[0]))->string;
+                   (yyval) = (yyvsp[0]);
                  }
                }
+#line 1769 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 70:
-
-    { (yyval) = (yyvsp[(4) - (4)]); }
+#line 316 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1775 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 71:
-
-    { (yyval) = (yyvsp[(4) - (4)]); }
+#line 318 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1781 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 72:
-
-    { (yyval) = (yyvsp[(2) - (2)]); }
+#line 320 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1787 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 73:
-
-    { (yyval) = (yyvsp[(3) - (3)]); }
+#line 322 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1793 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 74:
-
-    { (yyval) = (yyvsp[(3) - (3)]); }
+#line 328 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1799 "parse.tab.c" /* yacc.c:1646  */
     break;
 
-  case 75:
-
-    { (yyval) = (yyvsp[(2) - (2)]); }
+  case 78:
+#line 336 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1805 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 79:
-
-    { (yyval) = (yyvsp[(4) - (4)]); }
+#line 338 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1811 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 80:
-
-    { (yyval) = (yyvsp[(4) - (4)]); }
+#line 340 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1817 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 81:
-
-    { (yyval) = (yyvsp[(2) - (2)]); }
+#line 342 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1823 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 82:
-
-    { (yyval) = (yyvsp[(3) - (3)]); }
+#line 344 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1829 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 83:
-
-    { (yyval) = (yyvsp[(3) - (3)]); }
+#line 348 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1835 "parse.tab.c" /* yacc.c:1646  */
     break;
 
-  case 84:
-
-    { (yyval) = (yyvsp[(2) - (2)]); }
+  case 85:
+#line 350 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1841 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 86:
-
-    { (yyval) = (yyvsp[(3) - (3)]); }
+#line 354 "parse.y" /* yacc.c:1646  */
+    { (yyval) = NULL; }
+#line 1847 "parse.tab.c" /* yacc.c:1646  */
     break;
 
-  case 87:
-
-    { (yyval) = NULL; }
+  case 89:
+#line 361 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1853 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 90:
-
-    { (yyval) = (yyvsp[(3) - (3)]); }
+#line 366 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]) ? (yyvsp[0]) : (yyvsp[-1]); }
+#line 1859 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 91:
-
-    { (yyval) = (yyvsp[(2) - (2)]) ? (yyvsp[(2) - (2)]) : (yyvsp[(1) - (2)]); }
+#line 371 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]) ? (yyvsp[0]) : (yyvsp[-1]); }
+#line 1865 "parse.tab.c" /* yacc.c:1646  */
     break;
 
-  case 92:
-
-    { (yyval) = (yyvsp[(2) - (2)]) ? (yyvsp[(2) - (2)]) : (yyvsp[(1) - (2)]); }
+  case 93:
+#line 376 "parse.y" /* yacc.c:1646  */
+    { (yyval) = NULL; }
+#line 1871 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 94:
-
-    { (yyval) = NULL; }
+#line 378 "parse.y" /* yacc.c:1646  */
+    { /* For version 2 checksums, we don't want to remember
+                    private parameter names.  */
+                 remove_node((yyvsp[0]));
+                 (yyval) = (yyvsp[0]);
+               }
+#line 1881 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 95:
-
-    { /* For version 2 checksums, we don't want to remember
-                    private parameter names.  */
-                 remove_node((yyvsp[(1) - (1)]));
-                 (yyval) = (yyvsp[(1) - (1)]);
+#line 386 "parse.y" /* yacc.c:1646  */
+    { remove_node((yyvsp[0]));
+                 (yyval) = (yyvsp[0]);
                }
+#line 1889 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 96:
-
-    { remove_node((yyvsp[(1) - (1)]));
-                 (yyval) = (yyvsp[(1) - (1)]);
-               }
+#line 390 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1895 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 97:
-
-    { (yyval) = (yyvsp[(4) - (4)]); }
+#line 392 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1901 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 98:
-
-    { (yyval) = (yyvsp[(4) - (4)]); }
+#line 394 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1907 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 99:
-
-    { (yyval) = (yyvsp[(2) - (2)]); }
+#line 396 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1913 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 100:
-
-    { (yyval) = (yyvsp[(3) - (3)]); }
+#line 398 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1919 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 101:
-
-    { (yyval) = (yyvsp[(3) - (3)]); }
-    break;
-
-  case 102:
-
-    { struct string_list *decl = *(yyvsp[(2) - (3)]);
-                 *(yyvsp[(2) - (3)]) = NULL;
+#line 403 "parse.y" /* yacc.c:1646  */
+    { struct string_list *decl = *(yyvsp[-1]);
+                 *(yyvsp[-1]) = NULL;
                  add_symbol(current_name, SYM_NORMAL, decl, is_extern);
-                 (yyval) = (yyvsp[(3) - (3)]);
+                 (yyval) = (yyvsp[0]);
                }
+#line 1929 "parse.tab.c" /* yacc.c:1646  */
     break;
 
-  case 103:
-
+  case 102:
+#line 411 "parse.y" /* yacc.c:1646  */
     { (yyval) = NULL; }
+#line 1935 "parse.tab.c" /* yacc.c:1646  */
     break;
 
-  case 105:
+  case 104:
+#line 418 "parse.y" /* yacc.c:1646  */
+    { remove_list((yyvsp[0]), &(*(yyvsp[-1]))->next); (yyval) = (yyvsp[0]); }
+#line 1941 "parse.tab.c" /* yacc.c:1646  */
+    break;
 
-    { remove_list((yyvsp[(2) - (2)]), &(*(yyvsp[(1) - (2)]))->next); (yyval) = (yyvsp[(2) - (2)]); }
+  case 105:
+#line 422 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1947 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 106:
-
-    { (yyval) = (yyvsp[(3) - (3)]); }
+#line 423 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1953 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 107:
-
-    { (yyval) = (yyvsp[(3) - (3)]); }
+#line 427 "parse.y" /* yacc.c:1646  */
+    { (yyval) = NULL; }
+#line 1959 "parse.tab.c" /* yacc.c:1646  */
     break;
 
-  case 108:
-
-    { (yyval) = NULL; }
+  case 110:
+#line 433 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1965 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 111:
-
-    { (yyval) = (yyvsp[(2) - (2)]); }
+#line 438 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1971 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 112:
-
-    { (yyval) = (yyvsp[(3) - (3)]); }
+#line 440 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1977 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 113:
-
-    { (yyval) = (yyvsp[(2) - (2)]); }
+#line 444 "parse.y" /* yacc.c:1646  */
+    { (yyval) = NULL; }
+#line 1983 "parse.tab.c" /* yacc.c:1646  */
     break;
 
-  case 114:
-
-    { (yyval) = NULL; }
+  case 116:
+#line 450 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 1989 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 117:
-
-    { (yyval) = (yyvsp[(3) - (3)]); }
+#line 454 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]) ? (yyvsp[0]) : (yyvsp[-1]); }
+#line 1995 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 118:
-
-    { (yyval) = (yyvsp[(2) - (2)]) ? (yyvsp[(2) - (2)]) : (yyvsp[(1) - (2)]); }
+#line 455 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 2001 "parse.tab.c" /* yacc.c:1646  */
     break;
 
-  case 119:
-
-    { (yyval) = (yyvsp[(2) - (2)]); }
+  case 120:
+#line 460 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 2007 "parse.tab.c" /* yacc.c:1646  */
     break;
 
   case 121:
-
-    { (yyval) = (yyvsp[(2) - (2)]); }
-    break;
-
-  case 122:
-
+#line 464 "parse.y" /* yacc.c:1646  */
     { (yyval) = NULL; }
+#line 2013 "parse.tab.c" /* yacc.c:1646  */
     break;
 
-  case 124:
-
-    { (yyval) = (yyvsp[(3) - (3)]); }
+  case 123:
+#line 469 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 2019 "parse.tab.c" /* yacc.c:1646  */
     break;
 
-  case 125:
-
-    { (yyval) = (yyvsp[(4) - (4)]); }
+  case 124:
+#line 470 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 2025 "parse.tab.c" /* yacc.c:1646  */
     break;
 
-  case 128:
-
+  case 127:
+#line 479 "parse.y" /* yacc.c:1646  */
     {
-                       const char *name = strdup((*(yyvsp[(1) - (1)]))->string);
+                       const char *name = strdup((*(yyvsp[0]))->string);
                        add_symbol(name, SYM_ENUM_CONST, NULL, 0);
                }
+#line 2034 "parse.tab.c" /* yacc.c:1646  */
     break;
 
-  case 129:
-
+  case 128:
+#line 484 "parse.y" /* yacc.c:1646  */
     {
-                       const char *name = strdup((*(yyvsp[(1) - (3)]))->string);
-                       struct string_list *expr = copy_list_range(*(yyvsp[(3) - (3)]), *(yyvsp[(2) - (3)]));
+                       const char *name = strdup((*(yyvsp[-2]))->string);
+                       struct string_list *expr = copy_list_range(*(yyvsp[0]), *(yyvsp[-1]));
                        add_symbol(name, SYM_ENUM_CONST, expr, 0);
                }
+#line 2044 "parse.tab.c" /* yacc.c:1646  */
     break;
 
-  case 130:
-
-    { (yyval) = (yyvsp[(2) - (2)]); }
+  case 129:
+#line 491 "parse.y" /* yacc.c:1646  */
+    { (yyval) = (yyvsp[0]); }
+#line 2050 "parse.tab.c" /* yacc.c:1646  */
     break;
 
-  case 131:
-
+  case 130:
+#line 495 "parse.y" /* yacc.c:1646  */
     { (yyval) = NULL; }
+#line 2056 "parse.tab.c" /* yacc.c:1646  */
     break;
 
-  case 133:
-
-    { export_symbol((*(yyvsp[(3) - (5)]))->string); (yyval) = (yyvsp[(5) - (5)]); }
+  case 132:
+#line 501 "parse.y" /* yacc.c:1646  */
+    { export_symbol((*(yyvsp[-2]))->string); (yyval) = (yyvsp[0]); }
+#line 2062 "parse.tab.c" /* yacc.c:1646  */
     break;
 
 
-
+#line 2066 "parse.tab.c" /* yacc.c:1646  */
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
@@ -2177,7 +2084,7 @@ yyreduce:
 
   *++yyvsp = yyval;
 
-  /* Now `shift' the result of the reduction.  Determine what state
+  /* Now 'shift' the result of the reduction.  Determine what state
      that goes to, based on the state we popped back to and the rule
      number reduced by.  */
 
@@ -2192,9 +2099,9 @@ yyreduce:
   goto yynewstate;
 
 
-/*------------------------------------.
-| yyerrlab -- here on detecting error |
-`------------------------------------*/
+/*--------------------------------------.
+| yyerrlab -- here on detecting error |
+`--------------------------------------*/
 yyerrlab:
   /* Make sure we have latest lookahead translation.  See comments at
      user semantic actions for why this is necessary.  */
@@ -2245,20 +2152,20 @@ yyerrlab:
   if (yyerrstatus == 3)
     {
       /* If just tried and failed to reuse lookahead token after an
-        error, discard it.  */
+         error, discard it.  */
 
       if (yychar <= YYEOF)
-       {
-         /* Return failure if at end of input.  */
-         if (yychar == YYEOF)
-           YYABORT;
-       }
+        {
+          /* Return failure if at end of input.  */
+          if (yychar == YYEOF)
+            YYABORT;
+        }
       else
-       {
-         yydestruct ("Error: discarding",
-                     yytoken, &yylval);
-         yychar = YYEMPTY;
-       }
+        {
+          yydestruct ("Error: discarding",
+                      yytoken, &yylval);
+          yychar = YYEMPTY;
+        }
     }
 
   /* Else will try to reuse lookahead token after shifting the error
@@ -2277,7 +2184,7 @@ yyerrorlab:
   if (/*CONSTCOND*/ 0)
      goto yyerrorlab;
 
-  /* Do not reclaim the symbols of the rule which action triggered
+  /* Do not reclaim the symbols of the rule whose action triggered
      this YYERROR.  */
   YYPOPSTACK (yylen);
   yylen = 0;
@@ -2290,29 +2197,29 @@ yyerrorlab:
 | yyerrlab1 -- common code for both syntax error and YYERROR.  |
 `-------------------------------------------------------------*/
 yyerrlab1:
-  yyerrstatus = 3;     /* Each real token shifted decrements this.  */
+  yyerrstatus = 3;      /* Each real token shifted decrements this.  */
 
   for (;;)
     {
       yyn = yypact[yystate];
       if (!yypact_value_is_default (yyn))
-       {
-         yyn += YYTERROR;
-         if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
-           {
-             yyn = yytable[yyn];
-             if (0 < yyn)
-               break;
-           }
-       }
+        {
+          yyn += YYTERROR;
+          if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+            {
+              yyn = yytable[yyn];
+              if (0 < yyn)
+                break;
+            }
+        }
 
       /* Pop the current state because it cannot handle the error token.  */
       if (yyssp == yyss)
-       YYABORT;
+        YYABORT;
 
 
       yydestruct ("Error: popping",
-                 yystos[yystate], yyvsp);
+                  yystos[yystate], yyvsp);
       YYPOPSTACK (1);
       yystate = *yyssp;
       YY_STACK_PRINT (yyss, yyssp);
@@ -2363,14 +2270,14 @@ yyreturn:
       yydestruct ("Cleanup: discarding lookahead",
                   yytoken, &yylval);
     }
-  /* Do not reclaim the symbols of the rule which action triggered
+  /* Do not reclaim the symbols of the rule whose action triggered
      this YYABORT or YYACCEPT.  */
   YYPOPSTACK (yylen);
   YY_STACK_PRINT (yyss, yyssp);
   while (yyssp != yyss)
     {
       yydestruct ("Cleanup: popping",
-                 yystos[*yyssp], yyvsp);
+                  yystos[*yyssp], yyvsp);
       YYPOPSTACK (1);
     }
 #ifndef yyoverflow
@@ -2381,12 +2288,9 @@ yyreturn:
   if (yymsg != yymsgbuf)
     YYSTACK_FREE (yymsg);
 #endif
-  /* Make sure YYID is used.  */
-  return YYID (yyresult);
+  return yyresult;
 }
-
-
-
+#line 505 "parse.y" /* yacc.c:1906  */
 
 
 static void
index 4c00cef..1751bd0 100644 (file)
@@ -1,19 +1,19 @@
-/* A Bison parser, made by GNU Bison 2.7.  */
+/* A Bison parser, made by GNU Bison 3.0.4.  */
 
 /* Bison interface for Yacc-like parsers in C
-   
-      Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
-   
+
+   Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
+
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
-   
+
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-   
+
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
    special exception, which will cause the skeleton and the resulting
    Bison output files to be licensed under the GNU General Public
    License without this special exception.
-   
+
    This special exception was added by the Free Software Foundation in
    version 2.2 of Bison.  */
 
-#ifndef YY_YY_SCRIPTS_GENKSYMS_PARSE_TAB_H_SHIPPED_INCLUDED
-# define YY_YY_SCRIPTS_GENKSYMS_PARSE_TAB_H_SHIPPED_INCLUDED
-/* Enabling traces.  */
+#ifndef YY_YY_PARSE_TAB_H_INCLUDED
+# define YY_YY_PARSE_TAB_H_INCLUDED
+/* Debug traces.  */
 #ifndef YYDEBUG
-# define YYDEBUG 1
+# define YYDEBUG 0
 #endif
 #if YYDEBUG
 extern int yydebug;
 #endif
 
-/* Tokens.  */
+/* Token type.  */
 #ifndef YYTOKENTYPE
 # define YYTOKENTYPE
-   /* Put the tokens into the symbol table, so that GDB and other debuggers
-      know about them.  */
-   enum yytokentype {
-     ASM_KEYW = 258,
-     ATTRIBUTE_KEYW = 259,
-     AUTO_KEYW = 260,
-     BOOL_KEYW = 261,
-     CHAR_KEYW = 262,
-     CONST_KEYW = 263,
-     DOUBLE_KEYW = 264,
-     ENUM_KEYW = 265,
-     EXTERN_KEYW = 266,
-     EXTENSION_KEYW = 267,
-     FLOAT_KEYW = 268,
-     INLINE_KEYW = 269,
-     INT_KEYW = 270,
-     LONG_KEYW = 271,
-     REGISTER_KEYW = 272,
-     RESTRICT_KEYW = 273,
-     SHORT_KEYW = 274,
-     SIGNED_KEYW = 275,
-     STATIC_KEYW = 276,
-     STRUCT_KEYW = 277,
-     TYPEDEF_KEYW = 278,
-     UNION_KEYW = 279,
-     UNSIGNED_KEYW = 280,
-     VOID_KEYW = 281,
-     VOLATILE_KEYW = 282,
-     TYPEOF_KEYW = 283,
-     EXPORT_SYMBOL_KEYW = 284,
-     ASM_PHRASE = 285,
-     ATTRIBUTE_PHRASE = 286,
-     TYPEOF_PHRASE = 287,
-     BRACE_PHRASE = 288,
-     BRACKET_PHRASE = 289,
-     EXPRESSION_PHRASE = 290,
-     CHAR = 291,
-     DOTS = 292,
-     IDENT = 293,
-     INT = 294,
-     REAL = 295,
-     STRING = 296,
-     TYPE = 297,
-     OTHER = 298,
-     FILENAME = 299
-   };
+  enum yytokentype
+  {
+    ASM_KEYW = 258,
+    ATTRIBUTE_KEYW = 259,
+    AUTO_KEYW = 260,
+    BOOL_KEYW = 261,
+    CHAR_KEYW = 262,
+    CONST_KEYW = 263,
+    DOUBLE_KEYW = 264,
+    ENUM_KEYW = 265,
+    EXTERN_KEYW = 266,
+    EXTENSION_KEYW = 267,
+    FLOAT_KEYW = 268,
+    INLINE_KEYW = 269,
+    INT_KEYW = 270,
+    LONG_KEYW = 271,
+    REGISTER_KEYW = 272,
+    RESTRICT_KEYW = 273,
+    SHORT_KEYW = 274,
+    SIGNED_KEYW = 275,
+    STATIC_KEYW = 276,
+    STRUCT_KEYW = 277,
+    TYPEDEF_KEYW = 278,
+    UNION_KEYW = 279,
+    UNSIGNED_KEYW = 280,
+    VOID_KEYW = 281,
+    VOLATILE_KEYW = 282,
+    TYPEOF_KEYW = 283,
+    EXPORT_SYMBOL_KEYW = 284,
+    ASM_PHRASE = 285,
+    ATTRIBUTE_PHRASE = 286,
+    TYPEOF_PHRASE = 287,
+    BRACE_PHRASE = 288,
+    BRACKET_PHRASE = 289,
+    EXPRESSION_PHRASE = 290,
+    CHAR = 291,
+    DOTS = 292,
+    IDENT = 293,
+    INT = 294,
+    REAL = 295,
+    STRING = 296,
+    TYPE = 297,
+    OTHER = 298,
+    FILENAME = 299
+  };
 #endif
 
-
+/* Value type.  */
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef int YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
 #endif
 
+
 extern YYSTYPE yylval;
 
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void *YYPARSE_PARAM);
-#else
-int yyparse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
 int yyparse (void);
-#else
-int yyparse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
 
-#endif /* !YY_YY_SCRIPTS_GENKSYMS_PARSE_TAB_H_SHIPPED_INCLUDED  */
+#endif /* !YY_YY_PARSE_TAB_H_INCLUDED  */
index 723ab30..268efe3 100644 (file)
@@ -320,8 +320,6 @@ direct_declarator:
                { $$ = $2; }
        | '(' declarator ')'
                { $$ = $3; }
-       | '(' error ')'
-               { $$ = $3; }
        ;
 
 /* Nested declarators differ from regular declarators in that they do
index 638a38e..bba8ad9 100755 (executable)
@@ -2742,4 +2742,4 @@ if ($verbose && $warnings) {
   print STDERR "$warnings warnings\n";
 }
 
-exit($errors);
+exit($output_mode eq "none" ? 0 : $errors);
index e080746..bd51519 100644 (file)
@@ -594,7 +594,8 @@ static int ignore_undef_symbol(struct elf_info *info, const char *symname)
                if (strncmp(symname, "_restgpr0_", sizeof("_restgpr0_") - 1) == 0 ||
                    strncmp(symname, "_savegpr0_", sizeof("_savegpr0_") - 1) == 0 ||
                    strncmp(symname, "_restvr_", sizeof("_restvr_") - 1) == 0 ||
-                   strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0)
+                   strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0 ||
+                   strcmp(symname, ".TOC.") == 0)
                        return 1;
        /* Do not ignore this symbol */
        return 0;
@@ -2128,6 +2129,14 @@ static void add_intree_flag(struct buffer *b, int is_intree)
                buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
 }
 
+/* Cannot check for assembler */
+static void add_retpoline(struct buffer *b)
+{
+       buf_printf(b, "\n#ifdef RETPOLINE\n");
+       buf_printf(b, "MODULE_INFO(retpoline, \"Y\");\n");
+       buf_printf(b, "#endif\n");
+}
+
 static void add_staging_flag(struct buffer *b, const char *name)
 {
        static const char *staging_dir = "drivers/staging";
@@ -2472,6 +2481,7 @@ int main(int argc, char **argv)
 
                add_header(&buf, mod);
                add_intree_flag(&buf, !external_module);
+               add_retpoline(&buf);
                add_staging_flag(&buf, mod->name);
                err |= add_versions(&buf, mod);
                add_depends(&buf, mod, modules);
index ce295c0..e44e844 100644 (file)
@@ -141,23 +141,22 @@ static int valid_ecryptfs_desc(const char *ecryptfs_desc)
  */
 static int valid_master_desc(const char *new_desc, const char *orig_desc)
 {
-       if (!memcmp(new_desc, KEY_TRUSTED_PREFIX, KEY_TRUSTED_PREFIX_LEN)) {
-               if (strlen(new_desc) == KEY_TRUSTED_PREFIX_LEN)
-                       goto out;
-               if (orig_desc)
-                       if (memcmp(new_desc, orig_desc, KEY_TRUSTED_PREFIX_LEN))
-                               goto out;
-       } else if (!memcmp(new_desc, KEY_USER_PREFIX, KEY_USER_PREFIX_LEN)) {
-               if (strlen(new_desc) == KEY_USER_PREFIX_LEN)
-                       goto out;
-               if (orig_desc)
-                       if (memcmp(new_desc, orig_desc, KEY_USER_PREFIX_LEN))
-                               goto out;
-       } else
-               goto out;
+       int prefix_len;
+
+       if (!strncmp(new_desc, KEY_TRUSTED_PREFIX, KEY_TRUSTED_PREFIX_LEN))
+               prefix_len = KEY_TRUSTED_PREFIX_LEN;
+       else if (!strncmp(new_desc, KEY_USER_PREFIX, KEY_USER_PREFIX_LEN))
+               prefix_len = KEY_USER_PREFIX_LEN;
+       else
+               return -EINVAL;
+
+       if (!new_desc[prefix_len])
+               return -EINVAL;
+
+       if (orig_desc && strncmp(new_desc, orig_desc, prefix_len))
+               return -EINVAL;
+
        return 0;
-out:
-       return -EINVAL;
 }
 
 /*
index ebb5eb3..db7eff3 100644 (file)
@@ -860,6 +860,9 @@ int security_bounded_transition(u32 old_sid, u32 new_sid)
        int index;
        int rc;
 
+       if (!ss_initialized)
+               return 0;
+
        read_lock(&policy_rwlock);
 
        rc = -EINVAL;
@@ -1406,27 +1409,25 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
        if (!scontext_len)
                return -EINVAL;
 
+       /* Copy the string to allow changes and ensure a NUL terminator */
+       scontext2 = kmemdup_nul(scontext, scontext_len, gfp_flags);
+       if (!scontext2)
+               return -ENOMEM;
+
        if (!ss_initialized) {
                int i;
 
                for (i = 1; i < SECINITSID_NUM; i++) {
-                       if (!strcmp(initial_sid_to_string[i], scontext)) {
+                       if (!strcmp(initial_sid_to_string[i], scontext2)) {
                                *sid = i;
-                               return 0;
+                               goto out;
                        }
                }
                *sid = SECINITSID_KERNEL;
-               return 0;
+               goto out;
        }
        *sid = SECSID_NULL;
 
-       /* Copy the string so that we can modify the copy as we parse it. */
-       scontext2 = kmalloc(scontext_len + 1, gfp_flags);
-       if (!scontext2)
-               return -ENOMEM;
-       memcpy(scontext2, scontext, scontext_len);
-       scontext2[scontext_len] = 0;
-
        if (force) {
                /* Save another copy for storing in uninterpreted form */
                rc = -ENOMEM;
index 7bb9fe7..167b943 100644 (file)
@@ -1012,7 +1012,7 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf,
 {
        struct snd_seq_client *client = file->private_data;
        int written = 0, len;
-       int err = -EINVAL;
+       int err;
        struct snd_seq_event event;
 
        if (!(snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_OUTPUT))
@@ -1027,11 +1027,15 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf,
 
        /* allocate the pool now if the pool is not allocated yet */ 
        if (client->pool->size > 0 && !snd_seq_write_pool_allocated(client)) {
-               if (snd_seq_pool_init(client->pool) < 0)
+               mutex_lock(&client->ioctl_mutex);
+               err = snd_seq_pool_init(client->pool);
+               mutex_unlock(&client->ioctl_mutex);
+               if (err < 0)
                        return -ENOMEM;
        }
 
        /* only process whole events */
+       err = -EINVAL;
        while (count >= sizeof(struct snd_seq_event)) {
                /* Read in the event header from the user */
                len = sizeof(event);
@@ -2196,7 +2200,6 @@ static int snd_seq_do_ioctl(struct snd_seq_client *client, unsigned int cmd,
                            void __user *arg)
 {
        struct seq_ioctl_table *p;
-       int ret;
 
        switch (cmd) {
        case SNDRV_SEQ_IOCTL_PVERSION:
@@ -2210,12 +2213,8 @@ static int snd_seq_do_ioctl(struct snd_seq_client *client, unsigned int cmd,
        if (! arg)
                return -EFAULT;
        for (p = ioctl_tables; p->cmd; p++) {
-               if (p->cmd == cmd) {
-                       mutex_lock(&client->ioctl_mutex);
-                       ret = p->func(client, arg);
-                       mutex_unlock(&client->ioctl_mutex);
-                       return ret;
-               }
+               if (p->cmd == cmd)
+                       return p->func(client, arg);
        }
        pr_debug("ALSA: seq unknown ioctl() 0x%x (type='%c', number=0x%02x)\n",
                   cmd, _IOC_TYPE(cmd), _IOC_NR(cmd));
@@ -2226,11 +2225,15 @@ static int snd_seq_do_ioctl(struct snd_seq_client *client, unsigned int cmd,
 static long snd_seq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        struct snd_seq_client *client = file->private_data;
+       long ret;
 
        if (snd_BUG_ON(!client))
                return -ENXIO;
                
-       return snd_seq_do_ioctl(client, cmd, (void __user *) arg);
+       mutex_lock(&client->ioctl_mutex);
+       ret = snd_seq_do_ioctl(client, cmd, (void __user *) arg);
+       mutex_unlock(&client->ioctl_mutex);
+       return ret;
 }
 
 #ifdef CONFIG_COMPAT
index c146d0d..29e1ce2 100644 (file)
@@ -1482,6 +1482,9 @@ static int dspio_scp(struct hda_codec *codec,
                } else if (ret_size != reply_data_size) {
                        codec_dbg(codec, "RetLen and HdrLen .NE.\n");
                        return -EINVAL;
+               } else if (!reply) {
+                       codec_dbg(codec, "NULL reply\n");
+                       return -EINVAL;
                } else {
                        *reply_len = ret_size*sizeof(unsigned int);
                        memcpy(reply, scp_reply.data, *reply_len);
index f14c1f2..b302d05 100644 (file)
@@ -3130,6 +3130,19 @@ static void alc269_fixup_pincfg_no_hp_to_lineout(struct hda_codec *codec,
                spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
 }
 
+static void alc269_fixup_pincfg_U7x7_headset_mic(struct hda_codec *codec,
+                                                const struct hda_fixup *fix,
+                                                int action)
+{
+       unsigned int cfg_headphone = snd_hda_codec_get_pincfg(codec, 0x21);
+       unsigned int cfg_headset_mic = snd_hda_codec_get_pincfg(codec, 0x19);
+
+       if (cfg_headphone && cfg_headset_mic == 0x411111f0)
+               snd_hda_codec_set_pincfg(codec, 0x19,
+                       (cfg_headphone & ~AC_DEFCFG_DEVICE) |
+                       (AC_JACK_MIC_IN << AC_DEFCFG_DEVICE_SHIFT));
+}
+
 static void alc269_fixup_hweq(struct hda_codec *codec,
                               const struct hda_fixup *fix, int action)
 {
@@ -4782,6 +4795,7 @@ enum {
        ALC269_FIXUP_LIFEBOOK_EXTMIC,
        ALC269_FIXUP_LIFEBOOK_HP_PIN,
        ALC269_FIXUP_LIFEBOOK_NO_HP_TO_LINEOUT,
+       ALC255_FIXUP_LIFEBOOK_U7x7_HEADSET_MIC,
        ALC269_FIXUP_AMIC,
        ALC269_FIXUP_DMIC,
        ALC269VB_FIXUP_AMIC,
@@ -4972,6 +4986,10 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc269_fixup_pincfg_no_hp_to_lineout,
        },
+       [ALC255_FIXUP_LIFEBOOK_U7x7_HEADSET_MIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_pincfg_U7x7_headset_mic,
+       },
        [ALC269_FIXUP_AMIC] = {
                .type = HDA_FIXUP_PINS,
                .v.pins = (const struct hda_pintbl[]) {
@@ -5687,6 +5705,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x10cf, 0x159f, "Lifebook E780", ALC269_FIXUP_LIFEBOOK_NO_HP_TO_LINEOUT),
        SND_PCI_QUIRK(0x10cf, 0x15dc, "Lifebook T731", ALC269_FIXUP_LIFEBOOK_HP_PIN),
        SND_PCI_QUIRK(0x10cf, 0x1757, "Lifebook E752", ALC269_FIXUP_LIFEBOOK_HP_PIN),
+       SND_PCI_QUIRK(0x10cf, 0x1629, "Lifebook U7x7", ALC255_FIXUP_LIFEBOOK_U7x7_HEADSET_MIC),
        SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC),
        SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC),
        SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_BXBT2807_MIC),
@@ -5976,6 +5995,11 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
                {0x14, 0x90170110},
                {0x21, 0x02211020}),
        SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x12, 0x90a60130},
+               {0x14, 0x90170110},
+               {0x14, 0x01011020},
+               {0x21, 0x0221101f}),
+       SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
                ALC256_STANDARD_PINS),
        SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC280_FIXUP_HP_GPIO4,
                {0x12, 0x90a60130},
@@ -6031,6 +6055,10 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
                {0x12, 0x90a60120},
                {0x14, 0x90170110},
                {0x21, 0x0321101f}),
+       SND_HDA_PIN_QUIRK(0x10ec0289, 0x1028, "Dell", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x12, 0xb7a60130},
+               {0x14, 0x90170110},
+               {0x21, 0x04211020}),
        SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
                ALC290_STANDARD_PINS,
                {0x15, 0x04211040},
index 712ed65..ebdf9bd 100644 (file)
@@ -70,3 +70,7 @@ static struct spi_driver pcm512x_spi_driver = {
 };
 
 module_spi_driver(pcm512x_spi_driver);
+
+MODULE_DESCRIPTION("ASoC PCM512x codec driver - SPI");
+MODULE_AUTHOR("Mark Brown <broonie@kernel.org>");
+MODULE_LICENSE("GPL v2");
index ff6fcd9..0b1b6fc 100644 (file)
@@ -343,13 +343,19 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
        snprintf(prop, sizeof(prop), "%scpu", prefix);
        cpu = of_get_child_by_name(node, prop);
 
+       if (!cpu) {
+               ret = -EINVAL;
+               dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
+               goto dai_link_of_err;
+       }
+
        snprintf(prop, sizeof(prop), "%splat", prefix);
        plat = of_get_child_by_name(node, prop);
 
        snprintf(prop, sizeof(prop), "%scodec", prefix);
        codec = of_get_child_by_name(node, prop);
 
-       if (!cpu || !codec) {
+       if (!codec) {
                ret = -EINVAL;
                dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
                goto dai_link_of_err;
index d430ef5..79c2933 100644 (file)
@@ -24,7 +24,6 @@ config SND_SST_IPC_PCI
 config SND_SST_IPC_ACPI
        tristate
        select SND_SST_IPC
-       depends on ACPI
 
 config SND_SOC_INTEL_SST
        tristate
@@ -91,7 +90,7 @@ config SND_SOC_INTEL_BROADWELL_MACH
 
 config SND_SOC_INTEL_BYTCR_RT5640_MACH
        tristate "ASoC Audio DSP Support for MID BYT Platform"
-       depends on X86 && I2C
+       depends on X86 && I2C && ACPI
        select SND_SOC_RT5640
        select SND_SST_MFLD_PLATFORM
        select SND_SST_IPC_ACPI
@@ -103,7 +102,7 @@ config SND_SOC_INTEL_BYTCR_RT5640_MACH
 
 config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
         tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec"
-        depends on X86_INTEL_LPSS && I2C
+        depends on X86_INTEL_LPSS && I2C && ACPI
         select SND_SOC_RT5670
         select SND_SST_MFLD_PLATFORM
         select SND_SST_IPC_ACPI
@@ -115,7 +114,7 @@ config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
 
 config SND_SOC_INTEL_CHT_BSW_RT5645_MACH
        tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5645/5650 codec"
-       depends on X86_INTEL_LPSS && I2C
+       depends on X86_INTEL_LPSS && I2C && ACPI
        select SND_SOC_RT5645
        select SND_SST_MFLD_PLATFORM
        select SND_SST_IPC_ACPI
index 15c04e2..9769676 100644 (file)
@@ -9,7 +9,7 @@ config SND_SOC_MEDIATEK
 
 config SND_SOC_MT8173_MAX98090
        tristate "ASoC Audio driver for MT8173 with MAX98090 codec"
-       depends on SND_SOC_MEDIATEK
+       depends on SND_SOC_MEDIATEK && I2C
        select SND_SOC_MAX98090
        help
          This adds ASoC driver for Mediatek MT8173 boards
@@ -19,7 +19,7 @@ config SND_SOC_MT8173_MAX98090
 
 config SND_SOC_MT8173_RT5650_RT5676
        tristate "ASoC Audio driver for MT8173 with RT5650 RT5676 codecs"
-       depends on SND_SOC_MEDIATEK
+       depends on SND_SOC_MEDIATEK && I2C
        select SND_SOC_RT5645
        select SND_SOC_RT5677
        help
index 45a3f42..15134a0 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -3701,6 +3701,7 @@ static int msm_compr_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol,
        struct msm_compr_audio *prtd;
        int ret = 0;
        struct msm_adsp_event_data *event_data = NULL;
+       uint64_t actual_payload_len = 0;
 
        if (fe_id >= MSM_FRONTEND_DAI_MAX) {
                pr_err("%s Received invalid fe_id %lu\n",
@@ -3738,6 +3739,16 @@ static int msm_compr_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol,
                goto done;
        }
 
+       actual_payload_len = sizeof(struct msm_adsp_event_data) +
+                                       event_data->payload_len;
+       if (actual_payload_len >= U32_MAX) {
+               pr_err("%s payload length 0x%X  exceeds limit",
+                               __func__, event_data->payload_len);
+               ret = -EINVAL;
+               goto done;
+       }
+
+
        if ((sizeof(struct msm_adsp_event_data) + event_data->payload_len) >=
                                        sizeof(ucontrol->value.bytes.data)) {
                pr_err("%s param length=%d  exceeds limit",
index 292b3d0..27daa3a 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -27,6 +27,7 @@
 #include <sound/q6afe-v2.h>
 #include <sound/msm-dai-q6-v2.h>
 #include <sound/pcm_params.h>
+#include <sound/q6core.h>
 
 #define MSM_DAI_PRI_AUXPCM_DT_DEV_ID 1
 #define MSM_DAI_SEC_AUXPCM_DT_DEV_ID 2
@@ -6160,6 +6161,9 @@ static int msm_dai_q6_tdm_set_tdm_slot(struct snd_soc_dai *dai,
        case 16:
                cap_mask = 0xFFFF;
                break;
+       case 32:
+               cap_mask = 0xFFFFFFFF;
+               break;
        default:
                dev_err(dai->dev, "%s: invalid slots %d\n",
                        __func__, slots);
@@ -6292,6 +6296,8 @@ static int msm_dai_q6_tdm_set_channel_map(struct snd_soc_dai *dai,
                dev_get_drvdata(dai->dev);
        struct afe_param_id_slot_mapping_cfg *slot_mapping =
                &dai_data->port_cfg.slot_mapping;
+       struct afe_param_id_slot_mapping_cfg_v2 *slot_mapping_v2 =
+               &dai_data->port_cfg.slot_mapping_v2;
        int i = 0;
 
        dev_dbg(dai->dev, "%s: dai id = 0x%x\n", __func__, dai->id);
@@ -6329,23 +6335,49 @@ static int msm_dai_q6_tdm_set_channel_map(struct snd_soc_dai *dai,
        case AFE_PORT_ID_QUATERNARY_TDM_RX_5:
        case AFE_PORT_ID_QUATERNARY_TDM_RX_6:
        case AFE_PORT_ID_QUATERNARY_TDM_RX_7:
-               if (!rx_slot) {
-                       dev_err(dai->dev, "%s: rx slot not found\n", __func__);
-                       return -EINVAL;
-               }
-               if (rx_num > AFE_PORT_MAX_AUDIO_CHAN_CNT) {
-                       dev_err(dai->dev, "%s: invalid rx num %d\n", __func__,
-                               rx_num);
-                       return -EINVAL;
-               }
+               if (afe_get_svc_version(APR_SVC_AFE) >=
+                               ADSP_AFE_API_VERSION_V3) {
+                       if (!rx_slot) {
+                               dev_err(dai->dev, "%s: rx slot not found\n",
+                                               __func__);
+                               return -EINVAL;
+                       }
+                       if (rx_num > AFE_PORT_MAX_AUDIO_CHAN_CNT_V2) {
+                               dev_err(dai->dev, "%s: invalid rx num %d\n",
+                                               __func__,
+                                       rx_num);
+                               return -EINVAL;
+                       }
 
-               for (i = 0; i < rx_num; i++)
-                       slot_mapping->offset[i] = rx_slot[i];
-               for (i = rx_num; i < AFE_PORT_MAX_AUDIO_CHAN_CNT; i++)
-                       slot_mapping->offset[i] =
-                               AFE_SLOT_MAPPING_OFFSET_INVALID;
+                       for (i = 0; i < rx_num; i++)
+                               slot_mapping_v2->offset[i] = rx_slot[i];
+                       for (i = rx_num; i < AFE_PORT_MAX_AUDIO_CHAN_CNT_V2;
+                                       i++)
+                               slot_mapping_v2->offset[i] =
+                                       AFE_SLOT_MAPPING_OFFSET_INVALID;
 
-               slot_mapping->num_channel = rx_num;
+                       slot_mapping_v2->num_channel = rx_num;
+               } else {
+                       if (!rx_slot) {
+                               dev_err(dai->dev, "%s: rx slot not found\n",
+                                               __func__);
+                               return -EINVAL;
+                       }
+                       if (rx_num > AFE_PORT_MAX_AUDIO_CHAN_CNT) {
+                               dev_err(dai->dev, "%s: invalid rx num %d\n",
+                                               __func__,
+                                       rx_num);
+                               return -EINVAL;
+                       }
+
+                       for (i = 0; i < rx_num; i++)
+                               slot_mapping->offset[i] = rx_slot[i];
+                       for (i = rx_num; i < AFE_PORT_MAX_AUDIO_CHAN_CNT; i++)
+                               slot_mapping->offset[i] =
+                                       AFE_SLOT_MAPPING_OFFSET_INVALID;
+
+                       slot_mapping->num_channel = rx_num;
+               }
                break;
        case AFE_PORT_ID_PRIMARY_TDM_TX:
        case AFE_PORT_ID_PRIMARY_TDM_TX_1:
@@ -6379,23 +6411,49 @@ static int msm_dai_q6_tdm_set_channel_map(struct snd_soc_dai *dai,
        case AFE_PORT_ID_QUATERNARY_TDM_TX_5:
        case AFE_PORT_ID_QUATERNARY_TDM_TX_6:
        case AFE_PORT_ID_QUATERNARY_TDM_TX_7:
-               if (!tx_slot) {
-                       dev_err(dai->dev, "%s: tx slot not found\n", __func__);
-                       return -EINVAL;
-               }
-               if (tx_num > AFE_PORT_MAX_AUDIO_CHAN_CNT) {
-                       dev_err(dai->dev, "%s: invalid tx num %d\n", __func__,
-                               tx_num);
-                       return -EINVAL;
-               }
+               if (afe_get_svc_version(APR_SVC_AFE) >=
+                               ADSP_AFE_API_VERSION_V3) {
+                       if (!tx_slot) {
+                               dev_err(dai->dev, "%s: tx slot not found\n",
+                                               __func__);
+                               return -EINVAL;
+                       }
+                       if (tx_num > AFE_PORT_MAX_AUDIO_CHAN_CNT_V2) {
+                               dev_err(dai->dev, "%s: invalid tx num %d\n",
+                                               __func__,
+                                       tx_num);
+                               return -EINVAL;
+                       }
+
+                       for (i = 0; i < tx_num; i++)
+                               slot_mapping_v2->offset[i] = tx_slot[i];
+                       for (i = tx_num; i < AFE_PORT_MAX_AUDIO_CHAN_CNT_V2;
+                                       i++)
+                               slot_mapping_v2->offset[i] =
+                                       AFE_SLOT_MAPPING_OFFSET_INVALID;
 
-               for (i = 0; i < tx_num; i++)
-                       slot_mapping->offset[i] = tx_slot[i];
-               for (i = tx_num; i < AFE_PORT_MAX_AUDIO_CHAN_CNT; i++)
-                       slot_mapping->offset[i] =
-                               AFE_SLOT_MAPPING_OFFSET_INVALID;
+                       slot_mapping_v2->num_channel = tx_num;
+               } else {
+                       if (!tx_slot) {
+                               dev_err(dai->dev, "%s: tx slot not found\n",
+                                               __func__);
+                               return -EINVAL;
+                       }
+                       if (tx_num > AFE_PORT_MAX_AUDIO_CHAN_CNT) {
+                               dev_err(dai->dev, "%s: invalid tx num %d\n",
+                                               __func__,
+                                       tx_num);
+                               return -EINVAL;
+                       }
 
-               slot_mapping->num_channel = tx_num;
+                       for (i = 0; i < tx_num; i++)
+                               slot_mapping->offset[i] = tx_slot[i];
+                       for (i = tx_num; i < AFE_PORT_MAX_AUDIO_CHAN_CNT; i++)
+                               slot_mapping->offset[i] =
+                                       AFE_SLOT_MAPPING_OFFSET_INVALID;
+
+                       slot_mapping->num_channel = tx_num;
+               }
                break;
        default:
                dev_err(dai->dev, "%s: invalid dai id 0x%x\n",
@@ -6419,6 +6477,8 @@ static int msm_dai_q6_tdm_hw_params(struct snd_pcm_substream *substream,
                &dai_data->port_cfg.tdm;
        struct afe_param_id_slot_mapping_cfg *slot_mapping =
                &dai_data->port_cfg.slot_mapping;
+       struct afe_param_id_slot_mapping_cfg_v2 *slot_mapping_v2 =
+               &dai_data->port_cfg.slot_mapping_v2;
        struct afe_param_id_custom_tdm_header_cfg *custom_tdm_header =
                &dai_data->port_cfg.custom_tdm_header;
 
@@ -6426,7 +6486,7 @@ static int msm_dai_q6_tdm_hw_params(struct snd_pcm_substream *substream,
                __func__, dev_name(dai->dev));
 
        if ((params_channels(params) == 0) ||
-               (params_channels(params) > 8)) {
+               (params_channels(params) > 32)) {
                dev_err(dai->dev, "%s: invalid param channels %d\n",
                        __func__, params_channels(params));
                return -EINVAL;
@@ -6514,32 +6574,88 @@ static int msm_dai_q6_tdm_hw_params(struct snd_pcm_substream *substream,
                tdm->ctrl_data_out_enable,
                tdm->ctrl_invert_sync_pulse,
                tdm->ctrl_sync_data_delay);
+       if (afe_get_svc_version(APR_SVC_AFE) >=
+                       ADSP_AFE_API_VERSION_V3) {
+               /*
+                * update slot mapping v2 config param
+                * NOTE: channels/rate/bitwidth are per stream property
+                */
+               slot_mapping_v2->bitwidth = dai_data->bitwidth;
 
-       /*
-        * update slot mapping config param
-        * NOTE: channels/rate/bitwidth are per stream property
-        */
-       slot_mapping->bitwidth = dai_data->bitwidth;
-
-       pr_debug("%s: SLOT MAPPING:\n"
+       pr_debug("%s: SLOT MAPPING_V2:\n"
                "num_channel=%d bitwidth=%d data_align=0x%x\n",
                __func__,
-               slot_mapping->num_channel,
-               slot_mapping->bitwidth,
-               slot_mapping->data_align_type);
-       pr_debug("%s: SLOT MAPPING:\n"
+               slot_mapping_v2->num_channel,
+               slot_mapping_v2->bitwidth,
+               slot_mapping_v2->data_align_type);
+       pr_debug("%s: SLOT MAPPING V2:\n"
                "offset[0]=0x%x offset[1]=0x%x offset[2]=0x%x offset[3]=0x%x\n"
-               "offset[4]=0x%x offset[5]=0x%x offset[6]=0x%x offset[7]=0x%x\n",
+               "offset[4]=0x%x offset[5]=0x%x offset[6]=0x%x offset[7]=0x%x\n"
+               "offset[8]=0x%x offset[9]=0x%x offset[10]=0x%x offset[11]=0x%x\n"
+               "offset[12]=0x%x offset[13]=0x%x offset[14]=0x%x offset[15]=0x%x\n"
+               "offset[16]=0x%x offset[17]=0x%x offset[18]=0x%x offset[19]=0x%x\n"
+               "offset[20]=0x%x offset[21]=0x%x offset[22]=0x%x offset[23]=0x%x\n"
+               "offset[24]=0x%x offset[25]=0x%x offset[26]=0x%x offset[27]=0x%x\n"
+               "offset[28]=0x%x offset[29]=0x%x offset[30]=0x%x offset[31]=0x%x\n",
                __func__,
-               slot_mapping->offset[0],
-               slot_mapping->offset[1],
-               slot_mapping->offset[2],
-               slot_mapping->offset[3],
-               slot_mapping->offset[4],
-               slot_mapping->offset[5],
-               slot_mapping->offset[6],
-               slot_mapping->offset[7]);
+               slot_mapping_v2->offset[0],
+               slot_mapping_v2->offset[1],
+               slot_mapping_v2->offset[2],
+               slot_mapping_v2->offset[3],
+               slot_mapping_v2->offset[4],
+               slot_mapping_v2->offset[5],
+               slot_mapping_v2->offset[6],
+               slot_mapping_v2->offset[7],
+               slot_mapping_v2->offset[8],
+               slot_mapping_v2->offset[9],
+               slot_mapping_v2->offset[10],
+               slot_mapping_v2->offset[11],
+               slot_mapping_v2->offset[12],
+               slot_mapping_v2->offset[13],
+               slot_mapping_v2->offset[14],
+               slot_mapping_v2->offset[15],
+               slot_mapping_v2->offset[16],
+               slot_mapping_v2->offset[17],
+               slot_mapping_v2->offset[18],
+               slot_mapping_v2->offset[19],
+               slot_mapping_v2->offset[20],
+               slot_mapping_v2->offset[21],
+               slot_mapping_v2->offset[22],
+               slot_mapping_v2->offset[23],
+               slot_mapping_v2->offset[24],
+               slot_mapping_v2->offset[25],
+               slot_mapping_v2->offset[26],
+               slot_mapping_v2->offset[27],
+               slot_mapping_v2->offset[28],
+               slot_mapping_v2->offset[29],
+               slot_mapping_v2->offset[30],
+               slot_mapping_v2->offset[31]);
+       } else {
+               /*
+                * update slot mapping config param
+                * NOTE: channels/rate/bitwidth are per stream property
+                */
+               slot_mapping->bitwidth = dai_data->bitwidth;
 
+               pr_debug("%s: SLOT MAPPING:\n"
+                       "num_channel=%d bitwidth=%d data_align=0x%x\n",
+                       __func__,
+                       slot_mapping->num_channel,
+                       slot_mapping->bitwidth,
+                       slot_mapping->data_align_type);
+               pr_debug("%s: SLOT MAPPING:\n"
+                       "offset[0]=0x%x offset[1]=0x%x offset[2]=0x%x offset[3]=0x%x\n"
+                       "offset[4]=0x%x offset[5]=0x%x offset[6]=0x%x offset[7]=0x%x\n",
+                       __func__,
+                       slot_mapping->offset[0],
+                       slot_mapping->offset[1],
+                       slot_mapping->offset[2],
+                       slot_mapping->offset[3],
+                       slot_mapping->offset[4],
+                       slot_mapping->offset[5],
+                       slot_mapping->offset[6],
+                       slot_mapping->offset[7]);
+       }
        /*
         * update custom header config param
         * NOTE: channels/rate/bitwidth are per playback stream property.
@@ -8121,6 +8237,9 @@ static int msm_dai_q6_tdm_dev_probe(struct platform_device *pdev)
        dai_data->port_cfg.slot_mapping.minor_version =
                AFE_API_VERSION_SLOT_MAPPING_CONFIG;
 
+       dai_data->port_cfg.slot_mapping_v2.minor_version =
+               AFE_API_VERSION_SLOT_MAPPING_CONFIG_V2;
+
        /* CUSTOM TDM HEADER CFG */
        custom_tdm_header = &dai_data->port_cfg.custom_tdm_header;
        if (of_find_property(pdev->dev.of_node,
index 00847d9..15f4b49 100644 (file)
@@ -1,9 +1,9 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
-
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
-
+*
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
@@ -70,6 +70,8 @@ static u32 hfp_tx_mute;
 
 struct msm_pcm_pdata {
        int perf_mode;
+       struct snd_pcm *pcm_device[MSM_FRONTEND_DAI_MM_SIZE];
+       struct msm_pcm_channel_mixer chmixer_pspd[MSM_FRONTEND_DAI_MM_SIZE][2];
 };
 
 static void stop_pcm(struct msm_pcm_loopback *pcm);
@@ -321,7 +323,7 @@ static int msm_pcm_open(struct snd_pcm_substream *substream)
                                             param_id);
        }
        dev_info(rtd->platform->dev, "%s: Instance = %d, Stream ID = %s\n",
-                       __func__ , pcm->instance, substream->pcm->id);
+                       __func__, pcm->instance, substream->pcm->id);
        runtime->private_data = pcm;
 
        mutex_unlock(&pcm->lock);
@@ -414,6 +416,12 @@ static int msm_pcm_prepare(struct snd_pcm_substream *substream)
 
        dev_dbg(rtd->platform->dev, "%s: ASM loopback stream:%d\n",
                __func__, substream->stream);
+
+       if (pcm->playback_start && pcm->capture_start) {
+               mutex_unlock(&pcm->lock);
+               return ret;
+       }
+
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                if (!pcm->playback_start)
                        pcm->playback_start = 1;
@@ -422,7 +430,7 @@ static int msm_pcm_prepare(struct snd_pcm_substream *substream)
                        pcm->capture_start = 1;
        }
 
-       if (pcm->instance == 2) {
+       if (pcm->playback_start && pcm->capture_start) {
                struct snd_soc_pcm_runtime *soc_pcm_rx =
                                pcm->playback_substream->private_data;
                struct snd_soc_pcm_runtime *soc_pcm_tx =
@@ -708,6 +716,732 @@ static int msm_pcm_add_app_type_controls(struct snd_soc_pcm_runtime *rtd)
        return 0;
 }
 
+static int msm_pcm_channel_mixer_cfg_ctl_put(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+       u64 fe_id = kcontrol->private_value & 0xFF;
+       int session_type = (kcontrol->private_value >> 8) & 0xFF;
+       int ret = 0;
+       int stream_id = 0;
+       int be_id = 0;
+       struct msm_pcm_loopback *prtd = NULL;
+       struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_platform *platform = snd_soc_component_to_platform(comp);
+       struct msm_pcm_pdata *pdata = dev_get_drvdata(platform->dev);
+       struct snd_pcm *pcm = NULL;
+       struct snd_pcm_substream *substream = NULL;
+       struct msm_pcm_channel_mixer *chmixer_pspd = NULL;
+
+       if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+               pr_err("%s: invalid FE %llu\n", __func__, fe_id);
+               return -EINVAL;
+       }
+
+       if ((session_type != SESSION_TYPE_TX) &&
+               (session_type != SESSION_TYPE_RX)) {
+               pr_err("%s: invalid session type %d\n", __func__, session_type);
+               return -EINVAL;
+       }
+
+       pcm = pdata->pcm_device[fe_id];
+       if (!pcm) {
+               pr_err("%s invalid pcm handle for fe_id %llu\n",
+                               __func__, fe_id);
+               ret = -EINVAL;
+               goto done;
+       }
+
+       if (session_type == SESSION_TYPE_RX)
+               substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+       else
+               substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
+       if (!substream) {
+               pr_err("%s substream not found\n", __func__);
+               ret = -EINVAL;
+               goto done;
+       }
+
+       chmixer_pspd = &(pdata->chmixer_pspd[fe_id][session_type]);
+       chmixer_pspd->enable = ucontrol->value.integer.value[0];
+       chmixer_pspd->rule = ucontrol->value.integer.value[1];
+       chmixer_pspd->input_channel = ucontrol->value.integer.value[2];
+       chmixer_pspd->output_channel = ucontrol->value.integer.value[3];
+       chmixer_pspd->port_idx = ucontrol->value.integer.value[4];
+
+       /* cache value and take effect during adm_open stage */
+       msm_pcm_routing_set_channel_mixer_cfg(fe_id,
+                       session_type,
+                       chmixer_pspd);
+
+       if (substream->runtime) {
+               prtd = substream->runtime->private_data;
+               if (!prtd) {
+                       pr_err("%s find invalid prtd fail\n", __func__);
+                       return -EINVAL;
+               }
+
+               if (chmixer_pspd->enable) {
+                       stream_id = prtd->audio_client->session;
+                       be_id = chmixer_pspd->port_idx;
+                       msm_pcm_routing_set_channel_mixer_runtime(be_id,
+                                       stream_id,
+                                       session_type,
+                                       chmixer_pspd);
+               }
+       }
+done:
+       return ret;
+}
+
+static int msm_pcm_channel_mixer_cfg_ctl_get(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       u64 fe_id = kcontrol->private_value & 0xFF;
+       int session_type = (kcontrol->private_value >> 8) & 0xFF;
+       struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_platform *platform = snd_soc_component_to_platform(comp);
+       struct msm_pcm_pdata *pdata = dev_get_drvdata(platform->dev);
+       struct msm_pcm_channel_mixer *chmixer_pspd;
+
+       if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+               pr_err("%s: invalid FE %llu\n", __func__, fe_id);
+               return -EINVAL;
+       }
+
+       if ((session_type != SESSION_TYPE_TX) &&
+               (session_type != SESSION_TYPE_RX)) {
+               pr_err("%s: invalid session type %d\n", __func__, session_type);
+               return -EINVAL;
+       }
+
+       chmixer_pspd = &(pdata->chmixer_pspd[fe_id][session_type]);
+       ucontrol->value.integer.value[0] = chmixer_pspd->enable;
+       ucontrol->value.integer.value[1] = chmixer_pspd->rule;
+       ucontrol->value.integer.value[2] = chmixer_pspd->input_channel;
+       ucontrol->value.integer.value[3] = chmixer_pspd->output_channel;
+       ucontrol->value.integer.value[4] = chmixer_pspd->port_idx;
+       return 0;
+}
+
+static int msm_pcm_channel_mixer_output_map_ctl_put(
+               struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       u64 fe_id = kcontrol->private_value & 0xFF;
+       int session_type = (kcontrol->private_value >> 8) & 0xFF;
+       int i = 0;
+       struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_platform *platform = snd_soc_component_to_platform(comp);
+       struct msm_pcm_pdata *pdata = dev_get_drvdata(platform->dev);
+       struct msm_pcm_channel_mixer *chmixer_pspd;
+
+       if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+               pr_err("%s: invalid FE %llu\n", __func__, fe_id);
+               return -EINVAL;
+       }
+
+       if ((session_type != SESSION_TYPE_TX) &&
+               (session_type != SESSION_TYPE_RX)) {
+               pr_err("%s: invalid session type %d\n", __func__, session_type);
+               return -EINVAL;
+       }
+
+       chmixer_pspd = &(pdata->chmixer_pspd[fe_id][session_type]);
+       for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+               chmixer_pspd->out_ch_map[i] =
+                       ucontrol->value.integer.value[i];
+
+       return 0;
+}
+
+static int msm_pcm_channel_mixer_output_map_ctl_get(
+               struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       u64 fe_id = kcontrol->private_value & 0xFF;
+       int session_type = (kcontrol->private_value >> 8) & 0xFF;
+       int i = 0;
+       struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_platform *platform = snd_soc_component_to_platform(comp);
+       struct msm_pcm_pdata *pdata = dev_get_drvdata(platform->dev);
+       struct msm_pcm_channel_mixer *chmixer_pspd;
+
+       if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+               pr_err("%s: invalid FE %llu\n", __func__, fe_id);
+               return -EINVAL;
+       }
+
+       if ((session_type != SESSION_TYPE_TX) &&
+               (session_type != SESSION_TYPE_RX)) {
+               pr_err("%s: invalid session type %d\n", __func__, session_type);
+               return -EINVAL;
+       }
+
+       chmixer_pspd = &(pdata->chmixer_pspd[fe_id][session_type]);
+       for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+               ucontrol->value.integer.value[i] =
+                       chmixer_pspd->out_ch_map[i];
+       return 0;
+}
+
+static int msm_pcm_channel_mixer_input_map_ctl_put(
+               struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       u64 fe_id = kcontrol->private_value & 0xFF;
+       int session_type = (kcontrol->private_value >> 8) & 0xFF;
+       int i = 0;
+       struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_platform *platform = snd_soc_component_to_platform(comp);
+       struct msm_pcm_pdata *pdata = dev_get_drvdata(platform->dev);
+       struct msm_pcm_channel_mixer *chmixer_pspd;
+
+       if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+               pr_err("%s: invalid FE %llu\n", __func__, fe_id);
+               return -EINVAL;
+       }
+
+       if ((session_type != SESSION_TYPE_TX) &&
+               (session_type != SESSION_TYPE_RX)) {
+               pr_err("%s: invalid session type %d\n", __func__, session_type);
+               return -EINVAL;
+       }
+
+       chmixer_pspd = &(pdata->chmixer_pspd[fe_id][session_type]);
+       for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+               chmixer_pspd->in_ch_map[i] = ucontrol->value.integer.value[i];
+
+       return 0;
+}
+
+static int msm_pcm_channel_mixer_input_map_ctl_get(
+               struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       u64 fe_id = kcontrol->private_value & 0xFF;
+       int session_type = (kcontrol->private_value >> 8) & 0xFF;
+       int i = 0;
+       struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_platform *platform = snd_soc_component_to_platform(comp);
+       struct msm_pcm_pdata *pdata = dev_get_drvdata(platform->dev);
+       struct msm_pcm_channel_mixer *chmixer_pspd;
+
+       if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+               pr_err("%s: invalid FE %llu\n", __func__, fe_id);
+               return -EINVAL;
+       }
+
+       if ((session_type != SESSION_TYPE_TX) &&
+               (session_type != SESSION_TYPE_RX)) {
+               pr_err("%s: invalid session type %d\n", __func__, session_type);
+               return -EINVAL;
+       }
+
+       chmixer_pspd = &(pdata->chmixer_pspd[fe_id][session_type]);
+       for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+               ucontrol->value.integer.value[i] =
+                       chmixer_pspd->in_ch_map[i];
+       return 0;
+}
+
+static int msm_pcm_channel_mixer_weight_ctl_put(
+               struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       u64 fe_id = kcontrol->private_value & 0xFF;
+       int session_type = (kcontrol->private_value >> 8) & 0xFF;
+       int channel = (kcontrol->private_value >> 16) & 0xFF;
+       int i = 0;
+       struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_platform *platform = snd_soc_component_to_platform(comp);
+       struct msm_pcm_pdata *pdata = dev_get_drvdata(platform->dev);
+       struct msm_pcm_channel_mixer *chmixer_pspd;
+
+       if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+               pr_err("%s: invalid FE %llu\n", __func__, fe_id);
+               return -EINVAL;
+       }
+
+       if ((session_type != SESSION_TYPE_TX) &&
+               (session_type != SESSION_TYPE_RX)) {
+               pr_err("%s: invalid session type %d\n", __func__, session_type);
+               return -EINVAL;
+       }
+
+       chmixer_pspd = &(pdata->chmixer_pspd[fe_id][session_type]);
+       if (channel <= 0 || channel > PCM_FORMAT_MAX_NUM_CHANNEL) {
+               pr_err("%s: invalid channel number %d\n", __func__, channel);
+               return -EINVAL;
+       }
+
+       channel--;
+       for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+               chmixer_pspd->channel_weight[channel][i] =
+                       ucontrol->value.integer.value[i];
+       return 0;
+}
+
+static int msm_pcm_channel_mixer_weight_ctl_get(
+               struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       u64 fe_id = kcontrol->private_value & 0xFF;
+       int session_type = (kcontrol->private_value >> 8) & 0xFF;
+       int channel = (kcontrol->private_value >> 16) & 0xFF;
+       struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_platform *platform = snd_soc_component_to_platform(comp);
+       struct msm_pcm_pdata *pdata = dev_get_drvdata(platform->dev);
+       int i = 0;
+       struct msm_pcm_channel_mixer *chmixer_pspd;
+
+       if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+               pr_err("%s: invalid FE %llu\n", __func__, fe_id);
+               return -EINVAL;
+       }
+
+       if ((session_type != SESSION_TYPE_TX) &&
+               (session_type != SESSION_TYPE_RX)) {
+               pr_err("%s: invalid session type %d\n", __func__, session_type);
+               return -EINVAL;
+       }
+
+       if (channel <= 0 || channel > PCM_FORMAT_MAX_NUM_CHANNEL) {
+               pr_err("%s: invalid channel number %d\n", __func__, channel);
+               return -EINVAL;
+       }
+
+       channel--;
+       chmixer_pspd = &(pdata->chmixer_pspd[fe_id][session_type]);
+       for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+               ucontrol->value.integer.value[i] =
+                       chmixer_pspd->channel_weight[channel][i];
+       return 0;
+}
+
+static int msm_pcm_channel_mixer_output_map_info(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 32;
+       uinfo->value.integer.min = 1;
+       uinfo->value.integer.max = 64;
+       return 0;
+}
+
+static int msm_pcm_add_channel_mixer_output_map_controls(
+               struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_pcm *pcm = rtd->pcm;
+       const char *playback_mixer_ctl_name     = "AudStr";
+       const char *capture_mixer_ctl_name      = "AudStr Capture";
+       const char *deviceNo            = "NN";
+       const char *suffix              = "ChMixer Output Map";
+       int ctl_len = 0;
+       int session_type = 0;
+       char *playback_mixer_str = NULL;
+       char *capture_mixer_str = NULL;
+       int ret = 0;
+       struct snd_kcontrol_new channel_mixer_output_map_control[2] = {
+               {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "?",
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info = msm_pcm_channel_mixer_output_map_info,
+               .put = msm_pcm_channel_mixer_output_map_ctl_put,
+               .get = msm_pcm_channel_mixer_output_map_ctl_get,
+               .private_value = 0,
+               },
+               {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "?",
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info = msm_pcm_channel_mixer_output_map_info,
+               .put = msm_pcm_channel_mixer_output_map_ctl_put,
+               .get = msm_pcm_channel_mixer_output_map_ctl_get,
+               .private_value = 0,
+               }
+       };
+
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
+               ctl_len = strlen(playback_mixer_ctl_name) + 1 +
+                       strlen(deviceNo) + 1 + strlen(suffix) + 1;
+               playback_mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+               if (playback_mixer_str == NULL) {
+                       pr_err("failed to allocate mixer ctrl str of len %d",
+                                       ctl_len);
+                       goto done;
+               }
+               session_type = SESSION_TYPE_RX;
+               snprintf(playback_mixer_str, ctl_len, "%s %d %s",
+                       playback_mixer_ctl_name, rtd->pcm->device, suffix);
+               channel_mixer_output_map_control[0].name = playback_mixer_str;
+               channel_mixer_output_map_control[0].private_value =
+                               (rtd->dai_link->be_id) | (session_type << 8);
+       }
+
+       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
+               ctl_len = strlen(capture_mixer_ctl_name) + 1 +
+                       strlen(deviceNo) + 1 + strlen(suffix) + 1;
+               capture_mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+               if (capture_mixer_str == NULL) {
+                       pr_err("failed to allocate mixer ctrl str of len %d",
+                                       ctl_len);
+                       goto done;
+               }
+               session_type = SESSION_TYPE_TX;
+               snprintf(capture_mixer_str, ctl_len, "%s %d %s",
+                       capture_mixer_ctl_name, rtd->pcm->device, suffix);
+               channel_mixer_output_map_control[1].name = capture_mixer_str;
+               channel_mixer_output_map_control[1].private_value =
+                               (rtd->dai_link->be_id) | (session_type << 8);
+       }
+
+       ret = snd_soc_add_platform_controls(rtd->platform,
+                                       channel_mixer_output_map_control,
+                                       ARRAY_SIZE
+                                       (channel_mixer_output_map_control));
+       if (ret < 0) {
+               pr_err("%s: failed add platform ctl, err = %d\n",
+                        __func__, ret);
+               ret = -EINVAL;
+               goto done;
+       }
+
+done:
+       kfree(playback_mixer_str);
+       kfree(capture_mixer_str);
+       return ret;
+}
+
+static int msm_pcm_channel_mixer_input_map_info(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 32;
+       uinfo->value.integer.min = 1;
+       uinfo->value.integer.max = 64;
+       return 0;
+}
+
+static int msm_pcm_add_channel_mixer_input_map_controls(
+               struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_pcm *pcm = rtd->pcm;
+       const char *playback_mixer_ctl_name     = "AudStr";
+       const char *capture_mixer_ctl_name      = "AudStr Capture";
+       const char *deviceNo = "NN";
+       const char *suffix = "ChMixer Input Map";
+       int ctl_len = 0;
+       int session_type = 0;
+       char *playback_mixer_str = NULL;
+       char *capture_mixer_str = NULL;
+       int ret = 0;
+       struct snd_kcontrol_new channel_mixer_input_map_control[2] = {
+               {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "?",
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info = msm_pcm_channel_mixer_input_map_info,
+               .put = msm_pcm_channel_mixer_input_map_ctl_put,
+               .get = msm_pcm_channel_mixer_input_map_ctl_get,
+               .private_value = 0,
+               },
+               {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "?",
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info = msm_pcm_channel_mixer_input_map_info,
+               .put = msm_pcm_channel_mixer_input_map_ctl_put,
+               .get = msm_pcm_channel_mixer_input_map_ctl_get,
+               .private_value = 0,
+               }
+       };
+
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
+               ctl_len = strlen(playback_mixer_ctl_name) + 1 +
+                       strlen(deviceNo) + 1 + strlen(suffix) + 1;
+               playback_mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+               if (playback_mixer_str == NULL) {
+                       pr_err("failed to allocate mixer ctrl str of len %d",
+                                       ctl_len);
+                       goto done;
+               }
+               session_type = SESSION_TYPE_RX;
+               snprintf(playback_mixer_str, ctl_len, "%s %d %s",
+                       playback_mixer_ctl_name, rtd->pcm->device, suffix);
+               channel_mixer_input_map_control[0].name = playback_mixer_str;
+               channel_mixer_input_map_control[0].private_value =
+                               (rtd->dai_link->be_id) | (session_type << 8);
+       }
+
+       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
+               ctl_len = strlen(capture_mixer_ctl_name) + 1 +
+                       strlen(deviceNo) + 1 + strlen(suffix) + 1;
+               capture_mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+               if (capture_mixer_str == NULL) {
+                       pr_err("failed to allocate mixer ctrl str of len %d",
+                                       ctl_len);
+                       goto done;
+               }
+               session_type = SESSION_TYPE_TX;
+               snprintf(capture_mixer_str, ctl_len, "%s %d %s",
+                       capture_mixer_ctl_name, rtd->pcm->device, suffix);
+               channel_mixer_input_map_control[1].name = capture_mixer_str;
+               channel_mixer_input_map_control[1].private_value =
+                               (rtd->dai_link->be_id) | (session_type << 8);
+       }
+
+       ret = snd_soc_add_platform_controls(rtd->platform,
+                                       channel_mixer_input_map_control,
+                                       ARRAY_SIZE
+                                       (channel_mixer_input_map_control));
+       if (ret < 0) {
+               pr_err("%s: failed add platform ctl, err = %d\n",
+                        __func__, ret);
+               ret = -EINVAL;
+               goto done;
+       }
+
+done:
+       kfree(playback_mixer_str);
+       kfree(capture_mixer_str);
+       return ret;
+}
+
+static int msm_pcm_channel_mixer_cfg_info(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 5;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 0xFFFFFFFF;
+       return 0;
+}
+
+static int msm_pcm_add_channel_mixer_cfg_controls(
+               struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_pcm *pcm = rtd->pcm;
+       const char *playback_mixer_ctl_name     = "AudStr";
+       const char *capture_mixer_ctl_name      = "AudStr Capture";
+       const char *deviceNo            = "NN";
+       const char *suffix              = "ChMixer Cfg";
+       int ctl_len = 0;
+       char *playback_mixer_str = NULL;
+       char *capture_mixer_str = NULL;
+       int session_type = 0;
+       int ret = 0;
+       struct msm_pcm_pdata *pdata = NULL;
+       struct snd_kcontrol_new channel_mixer_cfg_control[2] = {
+               {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "?",
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info = msm_pcm_channel_mixer_cfg_info,
+               .put = msm_pcm_channel_mixer_cfg_ctl_put,
+               .get = msm_pcm_channel_mixer_cfg_ctl_get,
+               .private_value = 0,
+               },
+               {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "?",
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info = msm_pcm_channel_mixer_cfg_info,
+               .put = msm_pcm_channel_mixer_cfg_ctl_put,
+               .get = msm_pcm_channel_mixer_cfg_ctl_get,
+               .private_value = 0,
+               }
+       };
+
+       pdata = (struct msm_pcm_pdata *)
+               dev_get_drvdata(rtd->platform->dev);
+       if (pdata == NULL) {
+               pr_err("%s: platform data not populated\n", __func__);
+               ret = -EINVAL;
+               goto done;
+       }
+
+       pdata->pcm_device[rtd->dai_link->be_id] = rtd->pcm;
+
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
+               ctl_len = strlen(playback_mixer_ctl_name) + 1 +
+                       strlen(deviceNo) + 1 + strlen(suffix) + 1;
+               playback_mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+               if (playback_mixer_str == NULL) {
+                       pr_err("failed to allocate mixer ctrl str of len %d",
+                                       ctl_len);
+                       goto done;
+               }
+               session_type = SESSION_TYPE_RX;
+               snprintf(playback_mixer_str, ctl_len, "%s %d %s",
+                       playback_mixer_ctl_name, rtd->pcm->device, suffix);
+               channel_mixer_cfg_control[0].name = playback_mixer_str;
+               channel_mixer_cfg_control[0].private_value =
+                               (rtd->dai_link->be_id) | (session_type << 8);
+       }
+
+       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
+               ctl_len = strlen(capture_mixer_ctl_name) + 1 +
+                       strlen(deviceNo) + 1 + strlen(suffix) + 1;
+               capture_mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+               if (capture_mixer_str == NULL) {
+                       pr_err("failed to allocate mixer ctrl str of len %d",
+                                       ctl_len);
+                       goto done;
+               }
+               session_type = SESSION_TYPE_TX;
+               snprintf(capture_mixer_str, ctl_len, "%s %d %s",
+                       capture_mixer_ctl_name, rtd->pcm->device, suffix);
+               channel_mixer_cfg_control[1].name = capture_mixer_str;
+               channel_mixer_cfg_control[1].private_value =
+                               (rtd->dai_link->be_id) | (session_type << 8);
+       }
+
+       ret = snd_soc_add_platform_controls(rtd->platform,
+                                       channel_mixer_cfg_control,
+                                       ARRAY_SIZE
+                                       (channel_mixer_cfg_control));
+       if (ret < 0) {
+               pr_err("%s: failed add platform ctl, err = %d\n",
+                        __func__, ret);
+               ret = -EINVAL;
+               goto done;
+       }
+
+done:
+       kfree(playback_mixer_str);
+       kfree(capture_mixer_str);
+       return ret;
+}
+
+static int msm_pcm_channel_mixer_weight_info(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 32;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 0x4000;
+       return 0;
+}
+
+static int msm_pcm_add_channel_mixer_weight_controls(
+               struct snd_soc_pcm_runtime *rtd,
+               int channel)
+{
+       struct snd_pcm *pcm = rtd->pcm;
+       const char *playback_mixer_ctl_name     = "AudStr";
+       const char *capture_mixer_ctl_name      = "AudStr Capture";
+       const char *deviceNo            = "NN";
+       const char *channelNo           = "NN";
+       const char *suffix              = "ChMixer Weight Ch";
+       int ctl_len = 0;
+       int session_type = 0;
+       char *playback_mixer_str = NULL;
+       char *capture_mixer_str = NULL;
+       int ret = 0;
+       struct snd_kcontrol_new channel_mixer_weight_control[2] = {
+               {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "?",
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info = msm_pcm_channel_mixer_weight_info,
+               .put = msm_pcm_channel_mixer_weight_ctl_put,
+               .get = msm_pcm_channel_mixer_weight_ctl_get,
+               .private_value = 0,
+               },
+               {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "?",
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info = msm_pcm_channel_mixer_weight_info,
+               .put = msm_pcm_channel_mixer_weight_ctl_put,
+               .get = msm_pcm_channel_mixer_weight_ctl_get,
+               .private_value = 0,
+               }
+       };
+
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
+               ctl_len = strlen(playback_mixer_ctl_name) + 1 +
+                       strlen(deviceNo) + 1 + strlen(suffix) + 1 +
+                       strlen(channelNo) + 1;
+               playback_mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+               if (playback_mixer_str == NULL) {
+                       pr_err("failed to allocate mixer ctrl str of len %d",
+                                       ctl_len);
+                       goto done;
+               }
+               session_type = SESSION_TYPE_RX;
+               snprintf(playback_mixer_str, ctl_len, "%s %d %s %d",
+                       playback_mixer_ctl_name, rtd->pcm->device, suffix,
+                       channel);
+               channel_mixer_weight_control[0].name = playback_mixer_str;
+               channel_mixer_weight_control[0].private_value =
+                               (rtd->dai_link->be_id) | (session_type << 8)
+                               | (channel << 16);
+       }
+
+       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
+               ctl_len = strlen(capture_mixer_ctl_name) + 1 +
+                       strlen(deviceNo) + 1 + strlen(suffix) + 1 +
+                       strlen(channelNo) + 1;
+               capture_mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+               if (capture_mixer_str == NULL) {
+                       pr_err("failed to allocate mixer ctrl str of len %d",
+                                       ctl_len);
+                       goto done;
+               }
+               session_type = SESSION_TYPE_TX;
+               snprintf(capture_mixer_str, ctl_len, "%s %d %s %d",
+                       capture_mixer_ctl_name, rtd->pcm->device, suffix,
+                       channel);
+               channel_mixer_weight_control[1].name = capture_mixer_str;
+               channel_mixer_weight_control[1].private_value =
+                               (rtd->dai_link->be_id) | (session_type << 8)
+                               | (channel << 16);
+       }
+
+       ret = snd_soc_add_platform_controls(rtd->platform,
+                                       channel_mixer_weight_control,
+                                       ARRAY_SIZE
+                                       (channel_mixer_weight_control));
+       if (ret < 0) {
+               pr_err("%s: failed add platform ctl, err = %d\n",
+                        __func__, ret);
+               ret = -EINVAL;
+               goto done;
+       }
+
+done:
+       kfree(playback_mixer_str);
+       kfree(capture_mixer_str);
+       return ret;
+}
+
+static int msm_pcm_add_channel_mixer_controls(struct snd_soc_pcm_runtime *rtd)
+{
+       int i, ret = 0;
+
+       ret = msm_pcm_add_channel_mixer_cfg_controls(rtd);
+       if (ret)
+               pr_err("%s: pcm add channel mixer cfg controls failed:%d\n",
+                               __func__, ret);
+       ret = msm_pcm_add_channel_mixer_input_map_controls(rtd);
+       if (ret)
+               pr_err("%s: pcm add channel mixer input map controls failed:%d\n",
+                               __func__, ret);
+       ret = msm_pcm_add_channel_mixer_output_map_controls(rtd);
+       if (ret)
+               pr_err("%s: pcm add channel mixer output map controls failed:%d\n",
+                               __func__, ret);
+
+       for (i = 1; i <= PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+               ret |=  msm_pcm_add_channel_mixer_weight_controls(rtd, i);
+       if (ret)
+               pr_err("%s: pcm add channel mixer weight controls failed:%d\n",
+                               __func__, ret);
+       return ret;
+}
+
 static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd)
 {
        int ret = 0;
@@ -721,6 +1455,11 @@ static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd)
        if (ret)
                pr_err("%s: pcm add app type controls failed:%d\n",
                        __func__, ret);
+
+       ret = msm_pcm_add_channel_mixer_controls(rtd);
+       if (ret)
+               pr_err("%s: pcm add channel mixer controls failed:%d\n",
+                       __func__, ret);
        return ret;
 }
 
index 7e02261..f7c288d 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -52,6 +52,7 @@ static struct audio_locks the_locks;
 static const DECLARE_TLV_DB_LINEAR(msm_pcm_vol_gain, 0,
                        PCM_MASTER_VOL_MAX_STEPS);
 
+
 struct snd_msm {
        struct snd_card *card;
        struct snd_pcm *pcm;
@@ -1084,6 +1085,7 @@ static int msm_pcm_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol,
        struct msm_audio *prtd;
        int ret = 0;
        struct msm_adsp_event_data *event_data = NULL;
+       uint64_t actual_payload_len = 0;
 
        if (!pdata) {
                pr_err("%s pdata is NULL\n", __func__);
@@ -1120,6 +1122,15 @@ static int msm_pcm_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol,
                goto done;
        }
 
+       actual_payload_len = sizeof(struct msm_adsp_event_data) +
+                                                       event_data->payload_len;
+       if (actual_payload_len >= U32_MAX) {
+               pr_err("%s payload length 0x%X  exceeds limit",
+                       __func__, event_data->payload_len);
+               ret = -EINVAL;
+               goto done;
+       }
+
        if ((sizeof(struct msm_adsp_event_data) + event_data->payload_len) >=
                                        sizeof(ucontrol->value.bytes.data)) {
                pr_err("%s param length=%d  exceeds limit",
@@ -1631,6 +1642,7 @@ static int msm_pcm_playback_pan_scale_ctl_put(struct snd_kcontrol *kcontrol,
        struct asm_stream_pan_ctrl_params pan_param;
        char *usr_value = NULL;
        uint32_t *gain_ptr = NULL;
+
        if (!usr_info) {
                pr_err("%s: usr_info is null\n", __func__);
                ret = -EINVAL;
@@ -2086,9 +2098,736 @@ static int msm_pcm_add_app_type_controls(struct snd_soc_pcm_runtime *rtd)
        return 0;
 }
 
+static int msm_pcm_channel_mixer_cfg_ctl_put(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+       u64 fe_id = kcontrol->private_value & 0xFF;
+       int session_type = (kcontrol->private_value >> 8) & 0xFF;
+       int ret = 0;
+       int stream_id = 0;
+       int be_id = 0;
+       struct msm_audio *prtd = NULL;
+       struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_platform *platform = snd_soc_component_to_platform(comp);
+       struct msm_plat_data *pdata = dev_get_drvdata(platform->dev);
+       struct snd_pcm *pcm = NULL;
+       struct snd_pcm_substream *substream = NULL;
+       struct msm_pcm_channel_mixer *chmixer_pspd = NULL;
+
+       if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+               pr_err("%s: invalid FE %llu\n", __func__, fe_id);
+               return -EINVAL;
+       }
+
+       if ((session_type != SESSION_TYPE_TX) &&
+               (session_type != SESSION_TYPE_RX)) {
+               pr_err("%s: invalid session type %d\n", __func__, session_type);
+               return -EINVAL;
+       }
+
+       pcm = pdata->pcm_device[fe_id];
+       if (!pcm) {
+               pr_err("%s invalid pcm handle for fe_id %llu\n",
+                               __func__, fe_id);
+               ret = -EINVAL;
+               goto done;
+       }
+
+       if (session_type == SESSION_TYPE_RX)
+               substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+       else
+               substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
+       if (!substream) {
+               pr_err("%s substream not found\n", __func__);
+               ret = -EINVAL;
+               goto done;
+       }
+
+       chmixer_pspd = &(pdata->chmixer_pspd[fe_id][session_type]);
+       chmixer_pspd->enable = ucontrol->value.integer.value[0];
+       chmixer_pspd->rule = ucontrol->value.integer.value[1];
+       chmixer_pspd->input_channel = ucontrol->value.integer.value[2];
+       chmixer_pspd->output_channel = ucontrol->value.integer.value[3];
+       chmixer_pspd->port_idx = ucontrol->value.integer.value[4];
+
+       /* cache value and take effect during adm_open stage */
+       msm_pcm_routing_set_channel_mixer_cfg(fe_id,
+                       session_type,
+                       chmixer_pspd);
+
+       if (substream->runtime) {
+               prtd = substream->runtime->private_data;
+               if (!prtd) {
+                       pr_err("%s find invalid prtd fail\n", __func__);
+                       return -EINVAL;
+               }
+
+               if (chmixer_pspd->enable) {
+                       stream_id = prtd->audio_client->session;
+                       be_id = chmixer_pspd->port_idx;
+                       msm_pcm_routing_set_channel_mixer_runtime(be_id,
+                                       stream_id,
+                                       session_type,
+                                       chmixer_pspd);
+               }
+       }
+done:
+       return ret;
+}
+
+static int msm_pcm_channel_mixer_cfg_ctl_get(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       u64 fe_id = kcontrol->private_value & 0xFF;
+       int session_type = (kcontrol->private_value >> 8) & 0xFF;
+       struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_platform *platform = snd_soc_component_to_platform(comp);
+       struct msm_plat_data *pdata = dev_get_drvdata(platform->dev);
+       struct msm_pcm_channel_mixer *chmixer_pspd;
+
+       if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+               pr_err("%s: invalid FE %llu\n", __func__, fe_id);
+               return -EINVAL;
+       }
+
+       if ((session_type != SESSION_TYPE_TX) &&
+               (session_type != SESSION_TYPE_RX)) {
+               pr_err("%s: invalid session type %d\n", __func__, session_type);
+               return -EINVAL;
+       }
+
+       chmixer_pspd = &(pdata->chmixer_pspd[fe_id][session_type]);
+       ucontrol->value.integer.value[0] = chmixer_pspd->enable;
+       ucontrol->value.integer.value[1] = chmixer_pspd->rule;
+       ucontrol->value.integer.value[2] = chmixer_pspd->input_channel;
+       ucontrol->value.integer.value[3] = chmixer_pspd->output_channel;
+       ucontrol->value.integer.value[4] = chmixer_pspd->port_idx;
+       return 0;
+}
+
+static int msm_pcm_channel_mixer_output_map_ctl_put(
+               struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       u64 fe_id = kcontrol->private_value & 0xFF;
+       int session_type = (kcontrol->private_value >> 8) & 0xFF;
+       int i = 0;
+       struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_platform *platform = snd_soc_component_to_platform(comp);
+       struct msm_plat_data *pdata = dev_get_drvdata(platform->dev);
+       struct msm_pcm_channel_mixer *chmixer_pspd;
+
+       if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+               pr_err("%s: invalid FE %llu\n", __func__, fe_id);
+               return -EINVAL;
+       }
+
+       if ((session_type != SESSION_TYPE_TX) &&
+               (session_type != SESSION_TYPE_RX)) {
+               pr_err("%s: invalid session type %d\n", __func__, session_type);
+               return -EINVAL;
+       }
+
+       chmixer_pspd = &(pdata->chmixer_pspd[fe_id][session_type]);
+       for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+               chmixer_pspd->out_ch_map[i] =
+                       ucontrol->value.integer.value[i];
+
+       return 0;
+}
+
+static int msm_pcm_channel_mixer_output_map_ctl_get(
+               struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       u64 fe_id = kcontrol->private_value & 0xFF;
+       int session_type = (kcontrol->private_value >> 8) & 0xFF;
+       int i = 0;
+       struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_platform *platform = snd_soc_component_to_platform(comp);
+       struct msm_plat_data *pdata = dev_get_drvdata(platform->dev);
+       struct msm_pcm_channel_mixer *chmixer_pspd;
+
+       if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+               pr_err("%s: invalid FE %llu\n", __func__, fe_id);
+               return -EINVAL;
+       }
+
+       if ((session_type != SESSION_TYPE_TX) &&
+               (session_type != SESSION_TYPE_RX)) {
+               pr_err("%s: invalid session type %d\n", __func__, session_type);
+               return -EINVAL;
+       }
+
+       chmixer_pspd = &(pdata->chmixer_pspd[fe_id][session_type]);
+       for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+               ucontrol->value.integer.value[i] =
+                       chmixer_pspd->out_ch_map[i];
+       return 0;
+}
+
+static int msm_pcm_channel_mixer_input_map_ctl_put(
+               struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       u64 fe_id = kcontrol->private_value & 0xFF;
+       int session_type = (kcontrol->private_value >> 8) & 0xFF;
+       int i = 0;
+       struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_platform *platform = snd_soc_component_to_platform(comp);
+       struct msm_plat_data *pdata = dev_get_drvdata(platform->dev);
+       struct msm_pcm_channel_mixer *chmixer_pspd;
+
+       if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+               pr_err("%s: invalid FE %llu\n", __func__, fe_id);
+               return -EINVAL;
+       }
+
+       if ((session_type != SESSION_TYPE_TX) &&
+               (session_type != SESSION_TYPE_RX)) {
+               pr_err("%s: invalid session type %d\n", __func__, session_type);
+               return -EINVAL;
+       }
+
+       chmixer_pspd = &(pdata->chmixer_pspd[fe_id][session_type]);
+       for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+               chmixer_pspd->in_ch_map[i] = ucontrol->value.integer.value[i];
+
+       return 0;
+}
+
+static int msm_pcm_channel_mixer_input_map_ctl_get(
+               struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       u64 fe_id = kcontrol->private_value & 0xFF;
+       int session_type = (kcontrol->private_value >> 8) & 0xFF;
+       int i = 0;
+       struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_platform *platform = snd_soc_component_to_platform(comp);
+       struct msm_plat_data *pdata = dev_get_drvdata(platform->dev);
+       struct msm_pcm_channel_mixer *chmixer_pspd;
+
+       if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+               pr_err("%s: invalid FE %llu\n", __func__, fe_id);
+               return -EINVAL;
+       }
+
+       if ((session_type != SESSION_TYPE_TX) &&
+               (session_type != SESSION_TYPE_RX)) {
+               pr_err("%s: invalid session type %d\n", __func__, session_type);
+               return -EINVAL;
+       }
+
+       chmixer_pspd = &(pdata->chmixer_pspd[fe_id][session_type]);
+       for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+               ucontrol->value.integer.value[i] =
+                       chmixer_pspd->in_ch_map[i];
+       return 0;
+}
+
+static int msm_pcm_channel_mixer_weight_ctl_put(
+               struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       u64 fe_id = kcontrol->private_value & 0xFF;
+       int session_type = (kcontrol->private_value >> 8) & 0xFF;
+       int channel = (kcontrol->private_value >> 16) & 0xFF;
+       int i = 0;
+       struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_platform *platform = snd_soc_component_to_platform(comp);
+       struct msm_plat_data *pdata = dev_get_drvdata(platform->dev);
+       struct msm_pcm_channel_mixer *chmixer_pspd;
+
+       if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+               pr_err("%s: invalid FE %llu\n", __func__, fe_id);
+               return -EINVAL;
+       }
+
+       if ((session_type != SESSION_TYPE_TX) &&
+               (session_type != SESSION_TYPE_RX)) {
+               pr_err("%s: invalid session type %d\n", __func__, session_type);
+               return -EINVAL;
+       }
+
+       chmixer_pspd = &(pdata->chmixer_pspd[fe_id][session_type]);
+       if (channel <= 0 || channel > PCM_FORMAT_MAX_NUM_CHANNEL) {
+               pr_err("%s: invalid channel number %d\n", __func__, channel);
+               return -EINVAL;
+       }
+
+       channel--;
+       for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+               chmixer_pspd->channel_weight[channel][i] =
+                       ucontrol->value.integer.value[i];
+       return 0;
+}
+
+static int msm_pcm_channel_mixer_weight_ctl_get(
+               struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       u64 fe_id = kcontrol->private_value & 0xFF;
+       int session_type = (kcontrol->private_value >> 8) & 0xFF;
+       int channel = (kcontrol->private_value >> 16) & 0xFF;
+       struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_platform *platform = snd_soc_component_to_platform(comp);
+       struct msm_plat_data *pdata = dev_get_drvdata(platform->dev);
+       int i = 0;
+       struct msm_pcm_channel_mixer *chmixer_pspd;
+
+       if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+               pr_err("%s: invalid FE %llu\n", __func__, fe_id);
+               return -EINVAL;
+       }
+
+       if ((session_type != SESSION_TYPE_TX) &&
+               (session_type != SESSION_TYPE_RX)) {
+               pr_err("%s: invalid session type %d\n", __func__, session_type);
+               return -EINVAL;
+       }
+
+       if (channel <= 0 || channel > PCM_FORMAT_MAX_NUM_CHANNEL) {
+               pr_err("%s: invalid channel number %d\n", __func__, channel);
+               return -EINVAL;
+       }
+
+       channel--;
+       chmixer_pspd = &(pdata->chmixer_pspd[fe_id][session_type]);
+       for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+               ucontrol->value.integer.value[i] =
+                       chmixer_pspd->channel_weight[channel][i];
+       return 0;
+}
+
+static int msm_pcm_channel_mixer_output_map_info(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 32;
+       uinfo->value.integer.min = 1;
+       uinfo->value.integer.max = 64;
+       return 0;
+}
+
+static int msm_pcm_add_channel_mixer_output_map_controls(
+               struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_pcm *pcm = rtd->pcm;
+       const char *playback_mixer_ctl_name     = "AudStr";
+       const char *capture_mixer_ctl_name      = "AudStr Capture";
+       const char *deviceNo            = "NN";
+       const char *suffix              = "ChMixer Output Map";
+       int ctl_len = 0;
+       int session_type = 0;
+       char *playback_mixer_str = NULL;
+       char *capture_mixer_str = NULL;
+       int ret = 0;
+       struct snd_kcontrol_new channel_mixer_output_map_control[2] = {
+               {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "?",
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info = msm_pcm_channel_mixer_output_map_info,
+               .put = msm_pcm_channel_mixer_output_map_ctl_put,
+               .get = msm_pcm_channel_mixer_output_map_ctl_get,
+               .private_value = 0,
+               },
+               {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "?",
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info = msm_pcm_channel_mixer_output_map_info,
+               .put = msm_pcm_channel_mixer_output_map_ctl_put,
+               .get = msm_pcm_channel_mixer_output_map_ctl_get,
+               .private_value = 0,
+               }
+       };
+
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
+               ctl_len = strlen(playback_mixer_ctl_name) + 1 +
+                       strlen(deviceNo) + 1 + strlen(suffix) + 1;
+               playback_mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+               if (playback_mixer_str == NULL) {
+                       pr_err("failed to allocate mixer ctrl str of len %d",
+                                       ctl_len);
+                       goto done;
+               }
+               session_type = SESSION_TYPE_RX;
+               snprintf(playback_mixer_str, ctl_len, "%s %d %s",
+                       playback_mixer_ctl_name, rtd->pcm->device, suffix);
+               channel_mixer_output_map_control[0].name = playback_mixer_str;
+               channel_mixer_output_map_control[0].private_value =
+                               (rtd->dai_link->be_id) | (session_type << 8);
+       }
+
+       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
+               ctl_len = strlen(capture_mixer_ctl_name) + 1 +
+                       strlen(deviceNo) + 1 + strlen(suffix) + 1;
+               capture_mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+               if (capture_mixer_str == NULL) {
+                       pr_err("failed to allocate mixer ctrl str of len %d",
+                                       ctl_len);
+                       goto done;
+               }
+               session_type = SESSION_TYPE_TX;
+               snprintf(capture_mixer_str, ctl_len, "%s %d %s",
+                       capture_mixer_ctl_name, rtd->pcm->device, suffix);
+               channel_mixer_output_map_control[1].name = capture_mixer_str;
+               channel_mixer_output_map_control[1].private_value =
+                               (rtd->dai_link->be_id) | (session_type << 8);
+       }
+
+       ret = snd_soc_add_platform_controls(rtd->platform,
+                                       channel_mixer_output_map_control,
+                                       ARRAY_SIZE
+                                       (channel_mixer_output_map_control));
+       if (ret < 0) {
+               pr_err("%s: failed add platform ctl, err = %d\n",
+                        __func__, ret);
+               ret = -EINVAL;
+               goto done;
+       }
+
+done:
+       kfree(playback_mixer_str);
+       kfree(capture_mixer_str);
+       return ret;
+}
+
+static int msm_pcm_channel_mixer_input_map_info(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 32;
+       uinfo->value.integer.min = 1;
+       uinfo->value.integer.max = 64;
+       return 0;
+}
+
+static int msm_pcm_add_channel_mixer_input_map_controls(
+               struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_pcm *pcm = rtd->pcm;
+       const char *playback_mixer_ctl_name     = "AudStr";
+       const char *capture_mixer_ctl_name      = "AudStr Capture";
+       const char *deviceNo = "NN";
+       const char *suffix = "ChMixer Input Map";
+       int ctl_len = 0;
+       int session_type = 0;
+       char *playback_mixer_str = NULL;
+       char *capture_mixer_str = NULL;
+       int ret = 0;
+       struct snd_kcontrol_new channel_mixer_input_map_control[2] = {
+               {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "?",
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info = msm_pcm_channel_mixer_input_map_info,
+               .put = msm_pcm_channel_mixer_input_map_ctl_put,
+               .get = msm_pcm_channel_mixer_input_map_ctl_get,
+               .private_value = 0,
+               },
+               {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "?",
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info = msm_pcm_channel_mixer_input_map_info,
+               .put = msm_pcm_channel_mixer_input_map_ctl_put,
+               .get = msm_pcm_channel_mixer_input_map_ctl_get,
+               .private_value = 0,
+               }
+       };
+
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
+               ctl_len = strlen(playback_mixer_ctl_name) + 1 +
+                       strlen(deviceNo) + 1 + strlen(suffix) + 1;
+               playback_mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+               if (playback_mixer_str == NULL) {
+                       pr_err("failed to allocate mixer ctrl str of len %d",
+                                       ctl_len);
+                       goto done;
+               }
+               session_type = SESSION_TYPE_RX;
+               snprintf(playback_mixer_str, ctl_len, "%s %d %s",
+                       playback_mixer_ctl_name, rtd->pcm->device, suffix);
+               channel_mixer_input_map_control[0].name = playback_mixer_str;
+               channel_mixer_input_map_control[0].private_value =
+                               (rtd->dai_link->be_id) | (session_type << 8);
+       }
+
+       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
+               ctl_len = strlen(capture_mixer_ctl_name) + 1 +
+                       strlen(deviceNo) + 1 + strlen(suffix) + 1;
+               capture_mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+               if (capture_mixer_str == NULL) {
+                       pr_err("failed to allocate mixer ctrl str of len %d",
+                                       ctl_len);
+                       goto done;
+               }
+               session_type = SESSION_TYPE_TX;
+               snprintf(capture_mixer_str, ctl_len, "%s %d %s",
+                       capture_mixer_ctl_name, rtd->pcm->device, suffix);
+               channel_mixer_input_map_control[1].name = capture_mixer_str;
+               channel_mixer_input_map_control[1].private_value =
+                               (rtd->dai_link->be_id) | (session_type << 8);
+       }
+
+       ret = snd_soc_add_platform_controls(rtd->platform,
+                                       channel_mixer_input_map_control,
+                                       ARRAY_SIZE
+                                       (channel_mixer_input_map_control));
+       if (ret < 0) {
+               pr_err("%s: failed add platform ctl, err = %d\n",
+                        __func__, ret);
+               ret = -EINVAL;
+               goto done;
+       }
+
+done:
+       kfree(playback_mixer_str);
+       kfree(capture_mixer_str);
+       return ret;
+}
+
+static int msm_pcm_channel_mixer_cfg_info(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 5;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 0xFFFFFFFF;
+       return 0;
+}
+
+static int msm_pcm_add_channel_mixer_cfg_controls(
+               struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_pcm *pcm = rtd->pcm;
+       const char *playback_mixer_ctl_name     = "AudStr";
+       const char *capture_mixer_ctl_name      = "AudStr Capture";
+       const char *deviceNo            = "NN";
+       const char *suffix              = "ChMixer Cfg";
+       int ctl_len = 0;
+       char *playback_mixer_str = NULL;
+       char *capture_mixer_str = NULL;
+       int session_type = 0;
+       int ret = 0;
+       struct msm_plat_data *pdata = NULL;
+       struct snd_kcontrol_new channel_mixer_cfg_control[2] = {
+               {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "?",
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info = msm_pcm_channel_mixer_cfg_info,
+               .put = msm_pcm_channel_mixer_cfg_ctl_put,
+               .get = msm_pcm_channel_mixer_cfg_ctl_get,
+               .private_value = 0,
+               },
+               {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "?",
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info = msm_pcm_channel_mixer_cfg_info,
+               .put = msm_pcm_channel_mixer_cfg_ctl_put,
+               .get = msm_pcm_channel_mixer_cfg_ctl_get,
+               .private_value = 0,
+               }
+       };
+
+       pdata = (struct msm_plat_data *)
+               dev_get_drvdata(rtd->platform->dev);
+       if (pdata == NULL) {
+               pr_err("%s: platform data not populated\n", __func__);
+               ret = -EINVAL;
+               goto done;
+       }
+
+       pdata->pcm_device[rtd->dai_link->be_id] = rtd->pcm;
+
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
+               ctl_len = strlen(playback_mixer_ctl_name) + 1 +
+                       strlen(deviceNo) + 1 + strlen(suffix) + 1;
+               playback_mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+               if (playback_mixer_str == NULL) {
+                       pr_err("failed to allocate mixer ctrl str of len %d",
+                                       ctl_len);
+                       goto done;
+               }
+               session_type = SESSION_TYPE_RX;
+               snprintf(playback_mixer_str, ctl_len, "%s %d %s",
+                       playback_mixer_ctl_name, rtd->pcm->device, suffix);
+               channel_mixer_cfg_control[0].name = playback_mixer_str;
+               channel_mixer_cfg_control[0].private_value =
+                               (rtd->dai_link->be_id) | (session_type << 8);
+       }
+
+       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
+               ctl_len = strlen(capture_mixer_ctl_name) + 1 +
+                       strlen(deviceNo) + 1 + strlen(suffix) + 1;
+               capture_mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+               if (capture_mixer_str == NULL) {
+                       pr_err("failed to allocate mixer ctrl str of len %d",
+                                       ctl_len);
+                       goto done;
+               }
+               session_type = SESSION_TYPE_TX;
+               snprintf(capture_mixer_str, ctl_len, "%s %d %s",
+                       capture_mixer_ctl_name, rtd->pcm->device, suffix);
+               channel_mixer_cfg_control[1].name = capture_mixer_str;
+               channel_mixer_cfg_control[1].private_value =
+                               (rtd->dai_link->be_id) | (session_type << 8);
+       }
+
+       ret = snd_soc_add_platform_controls(rtd->platform,
+                                       channel_mixer_cfg_control,
+                                       ARRAY_SIZE
+                                       (channel_mixer_cfg_control));
+       if (ret < 0) {
+               pr_err("%s: failed add platform ctl, err = %d\n",
+                        __func__, ret);
+               ret = -EINVAL;
+               goto done;
+       }
+
+done:
+       kfree(playback_mixer_str);
+       kfree(capture_mixer_str);
+       return ret;
+}
+
+static int msm_pcm_channel_mixer_weight_info(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 32;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 0x4000;
+       return 0;
+}
+
+static int msm_pcm_add_channel_mixer_weight_controls(
+               struct snd_soc_pcm_runtime *rtd,
+               int channel)
+{
+       struct snd_pcm *pcm = rtd->pcm;
+       const char *playback_mixer_ctl_name     = "AudStr";
+       const char *capture_mixer_ctl_name      = "AudStr Capture";
+       const char *deviceNo            = "NN";
+       const char *channelNo           = "NN";
+       const char *suffix              = "ChMixer Weight Ch";
+       int ctl_len = 0;
+       int session_type = 0;
+       char *playback_mixer_str = NULL;
+       char *capture_mixer_str = NULL;
+       int ret = 0;
+       struct snd_kcontrol_new channel_mixer_weight_control[2] = {
+               {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "?",
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info = msm_pcm_channel_mixer_weight_info,
+               .put = msm_pcm_channel_mixer_weight_ctl_put,
+               .get = msm_pcm_channel_mixer_weight_ctl_get,
+               .private_value = 0,
+               },
+               {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "?",
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info = msm_pcm_channel_mixer_weight_info,
+               .put = msm_pcm_channel_mixer_weight_ctl_put,
+               .get = msm_pcm_channel_mixer_weight_ctl_get,
+               .private_value = 0,
+               }
+       };
+
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream != NULL) {
+               ctl_len = strlen(playback_mixer_ctl_name) + 1 +
+                       strlen(deviceNo) + 1 + strlen(suffix) + 1 +
+                       strlen(channelNo) + 1;
+               playback_mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+               if (playback_mixer_str == NULL) {
+                       pr_err("failed to allocate mixer ctrl str of len %d",
+                                       ctl_len);
+                       goto done;
+               }
+               session_type = SESSION_TYPE_RX;
+               snprintf(playback_mixer_str, ctl_len, "%s %d %s %d",
+                       playback_mixer_ctl_name, rtd->pcm->device, suffix,
+                       channel);
+               channel_mixer_weight_control[0].name = playback_mixer_str;
+               channel_mixer_weight_control[0].private_value =
+                               (rtd->dai_link->be_id) | (session_type << 8)
+                               | (channel << 16);
+       }
+
+       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream != NULL) {
+               ctl_len = strlen(capture_mixer_ctl_name) + 1 +
+                       strlen(deviceNo) + 1 + strlen(suffix) + 1 +
+                       strlen(channelNo) + 1;
+               capture_mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+               if (capture_mixer_str == NULL) {
+                       pr_err("failed to allocate mixer ctrl str of len %d",
+                                       ctl_len);
+                       goto done;
+               }
+               session_type = SESSION_TYPE_TX;
+               snprintf(capture_mixer_str, ctl_len, "%s %d %s %d",
+                       capture_mixer_ctl_name, rtd->pcm->device, suffix,
+                       channel);
+               channel_mixer_weight_control[1].name = capture_mixer_str;
+               channel_mixer_weight_control[1].private_value =
+                               (rtd->dai_link->be_id) | (session_type << 8)
+                               | (channel << 16);
+       }
+
+       ret = snd_soc_add_platform_controls(rtd->platform,
+                                       channel_mixer_weight_control,
+                                       ARRAY_SIZE
+                                       (channel_mixer_weight_control));
+       if (ret < 0) {
+               pr_err("%s: failed add platform ctl, err = %d\n",
+                        __func__, ret);
+               ret = -EINVAL;
+               goto done;
+       }
+
+done:
+       kfree(playback_mixer_str);
+       kfree(capture_mixer_str);
+       return ret;
+}
+
+static int msm_pcm_add_channel_mixer_controls(struct snd_soc_pcm_runtime *rtd)
+{
+       int i, ret = 0;
+
+       ret = msm_pcm_add_channel_mixer_cfg_controls(rtd);
+       if (ret)
+               pr_err("%s: pcm add channel mixer cfg controls failed:%d\n",
+                               __func__, ret);
+       ret = msm_pcm_add_channel_mixer_input_map_controls(rtd);
+       if (ret)
+               pr_err("%s: pcm add channel mixer input map controls failed:%d\n",
+                               __func__, ret);
+       ret = msm_pcm_add_channel_mixer_output_map_controls(rtd);
+       if (ret)
+               pr_err("%s: pcm add channel mixer output map controls failed:%d\n",
+                               __func__, ret);
+
+       for (i = 1; i <= PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+               ret |=  msm_pcm_add_channel_mixer_weight_controls(rtd, i);
+       if (ret)
+               pr_err("%s: pcm add channel mixer weight controls failed:%d\n",
+                               __func__, ret);
+       return ret;
+}
+
 static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd)
 {
        int ret = 0;
+
        pr_debug("%s\n", __func__);
        ret = msm_pcm_add_chmap_controls(rtd);
        if (ret)
@@ -2105,6 +2844,10 @@ static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd)
        if (ret)
                pr_err("%s: pcm add dnmix controls failed:%d\n",
                        __func__, ret);
+       ret = msm_pcm_add_channel_mixer_controls(rtd);
+       if (ret)
+               pr_err("%s: pcm add channel mixer controls failed:%d\n",
+                       __func__, ret);
        return ret;
 }
 
@@ -2212,13 +2955,12 @@ static int msm_pcm_probe(struct platform_device *pdev)
                                pdata->perf_mode =
                                        ULL_POST_PROCESSING_PCM_MODE;
                }
-       }
-       else
+       } else {
                pdata->perf_mode = LEGACY_PCM_MODE;
+       }
 
        dev_set_drvdata(&pdev->dev, pdata);
 
-
        dev_dbg(&pdev->dev, "%s: dev name %s\n",
                                __func__, dev_name(&pdev->dev));
        return snd_soc_register_platform(&pdev->dev,
index f5ff63f..f9c0c03 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2008 Google, Inc.
  * Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -20,8 +20,7 @@
 #define _MSM_PCM_H
 #include <sound/apr_audio-v2.h>
 #include <sound/q6asm-v2.h>
-
-
+#include "msm-pcm-routing-v2.h"
 
 /* Support unconventional sample rates 12000, 24000 as well */
 #define USE_RATE                \
@@ -125,6 +124,8 @@ struct output_meta_data_st {
 struct msm_plat_data {
        int perf_mode;
        struct snd_pcm *pcm;
+       struct snd_pcm *pcm_device[MSM_FRONTEND_DAI_MM_SIZE];
+       struct msm_pcm_channel_mixer chmixer_pspd[MSM_FRONTEND_DAI_MM_SIZE][2];
 };
 
 #endif /*_MSM_PCM_H*/
index 2dba05d..6e83ee3 100644 (file)
@@ -87,6 +87,11 @@ static bool swap_ch;
 #define WEIGHT_0_DB 0x4000
 /* all the FEs which can support channel mixer */
 static struct msm_pcm_channel_mixer channel_mixer[MSM_FRONTEND_DAI_MM_SIZE];
+
+/* all the FES which can support channel mixer for bidirection */
+static struct msm_pcm_channel_mixer
+       channel_mixer_v2[MSM_FRONTEND_DAI_MM_SIZE][2];
+
 /* input BE for each FE */
 static int channel_input[MSM_FRONTEND_DAI_MM_SIZE][ADM_MAX_CHANNELS];
 
@@ -776,6 +781,46 @@ static bool is_mm_lsm_fe_id(int fe_id)
        return rc;
 }
 
+/**
+ * msm_pcm_routing_set_channel_mixer_cfg - cache channel mixer
+ * setting before use case start.
+ *
+ * @fe_id: frontend idx
+ * @type: stream direction type
+ * @params: parameters of channel mixer setting
+ *
+ * Return 0 for success
+ */
+int msm_pcm_routing_set_channel_mixer_cfg(
+       int fe_id, int type,
+       struct msm_pcm_channel_mixer *params)
+{
+       int i, j = 0;
+
+       channel_mixer_v2[fe_id][type].enable = params->enable;
+       channel_mixer_v2[fe_id][type].rule = params->rule;
+       channel_mixer_v2[fe_id][type].input_channel =
+               params->input_channel;
+       channel_mixer_v2[fe_id][type].output_channel =
+               params->output_channel;
+       channel_mixer_v2[fe_id][type].port_idx = params->port_idx;
+
+       for (i = 0; i < ADM_MAX_CHANNELS; i++)
+               channel_mixer_v2[fe_id][type].in_ch_map[i] =
+                       params->in_ch_map[i];
+       for (i = 0; i < ADM_MAX_CHANNELS; i++)
+               channel_mixer_v2[fe_id][type].out_ch_map[i] =
+                       params->out_ch_map[i];
+
+       for (i = 0; i < ADM_MAX_CHANNELS; i++)
+               for (j = 0; j < ADM_MAX_CHANNELS; j++)
+                       channel_mixer_v2[fe_id][type].channel_weight[i][j] =
+                               params->channel_weight[i][j];
+       channel_mixer_v2[fe_id][type].override_cfg = 1;
+       return 0;
+}
+EXPORT_SYMBOL(msm_pcm_routing_set_channel_mixer_cfg);
+
 int msm_pcm_routing_reg_stream_app_type_cfg(
        int fedai_id, int session_type, int be_id,
        struct msm_pcm_stream_app_type_cfg *cfg_data)
@@ -1300,14 +1345,79 @@ static u32 msm_pcm_routing_get_voc_sessionid(u16 val)
        return session_id;
 }
 
+static int msm_pcm_routing_channel_mixer_v2(int fe_id, bool perf_mode,
+                               int dspst_id, int stream_type)
+{
+       int copp_idx = 0;
+       int sess_type = 0;
+       int j = 0, be_id = 0;
+       int ret = 0;
+
+       if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
+               pr_err("%s: invalid FE %d\n", __func__, fe_id);
+               return 0;
+       }
+
+       if (stream_type == SNDRV_PCM_STREAM_PLAYBACK)
+               sess_type = SESSION_TYPE_RX;
+       else
+               sess_type = SESSION_TYPE_TX;
+
+       if (!(channel_mixer_v2[fe_id][sess_type].enable)) {
+               pr_debug("%s: channel mixer not enabled for FE %d direction %d\n",
+                       __func__, fe_id, sess_type);
+               return 0;
+       }
+
+       pr_debug("%s sess type %d fe_id %d override %d be active %d\n",
+                       __func__,
+                       sess_type,
+                       fe_id,
+                       channel_mixer_v2[fe_id][sess_type].override_cfg,
+                       msm_bedais[be_id].active);
+       if (channel_mixer_v2[fe_id][sess_type].override_cfg) {
+               be_id = channel_mixer_v2[fe_id][sess_type].port_idx - 1;
+               channel_mixer_v2[fe_id][sess_type].input_channels[0] =
+                       channel_mixer_v2[fe_id][sess_type].input_channel;
+
+               if ((msm_bedais[be_id].active) &&
+                       test_bit(fe_id,
+                       &msm_bedais[be_id].fe_sessions[0])) {
+                       unsigned long copp =
+                               session_copp_map[fe_id][sess_type][be_id];
+                       for (j = 0; j < MAX_COPPS_PER_PORT; j++) {
+                               if (test_bit(j, &copp)) {
+                                       copp_idx = j;
+                                       break;
+                               }
+                       }
+
+                       ret = adm_programable_channel_mixer(
+                               msm_bedais[be_id].port_id,
+                               copp_idx, dspst_id, sess_type,
+                               &channel_mixer_v2[fe_id][sess_type], 0);
+               }
+       }
+
+       return ret;
+}
+
 static int msm_pcm_routing_channel_mixer(int fe_id, bool perf_mode,
                                int dspst_id, int stream_type)
 {
        int copp_idx = 0;
        int sess_type = 0;
-       int i = 0, j = 0, be_id;
+       int i = 0, j = 0, be_id = 0;
        int ret = 0;
 
+       ret = msm_pcm_routing_channel_mixer_v2(fe_id, perf_mode,
+                               dspst_id, stream_type);
+       if (ret) {
+               pr_err("%s channel mixer v2 cmd  set failure%d\n", __func__,
+                               fe_id);
+               return ret;
+       }
+
        if (fe_id >= MSM_FRONTEND_DAI_MM_SIZE) {
                pr_err("%s: invalid FE %d\n", __func__, fe_id);
                return 0;
@@ -16475,6 +16585,129 @@ static struct snd_pcm_ops msm_routing_pcm_ops = {
        .prepare        = msm_pcm_routing_prepare,
 };
 
+/**
+ * msm_pcm_routing_set_channel_mixer_runtime - apply channel mixer
+ * setting during runtime.
+ *
+ * @be_id: backend index
+ * @session_id: session index
+ * @session_type: session type
+ * @params: parameters for channel mixer
+ *
+ * Retuen: 0 for success, else error
+ */
+int msm_pcm_routing_set_channel_mixer_runtime(int be_id, int session_id,
+                       int session_type,
+                       struct msm_pcm_channel_mixer *params)
+{
+       int i, j, rc = 0;
+       struct adm_pspd_param_data_t data;
+       struct audproc_chmixer_param_coeff chmixer_cfg;
+       uint16_t variable_payload = 0;
+       char *adm_params = NULL;
+       int port_id, copp_idx = 0;
+       uint32_t params_length = 0;
+       uint16_t *dst_gain_ptr = NULL;
+
+       be_id--;
+       if (be_id < 0 || be_id >= MSM_BACKEND_DAI_MAX) {
+               pr_err("%s: invalid backend id %d\n", __func__,
+                               be_id);
+               return -EINVAL;
+       }
+
+       memset(&data, 0, sizeof(struct adm_pspd_param_data_t));
+       memset(&chmixer_cfg, 0, sizeof(struct audproc_chmixer_param_coeff));
+       port_id = msm_bedais[be_id].port_id;
+       copp_idx = adm_get_default_copp_idx(port_id);
+       pr_debug("%s: port_id - %d, copp_idx %d session id - %d\n",
+                __func__, port_id, copp_idx, session_id);
+
+       if ((params->input_channel < 0) ||
+               (params->input_channel > ADM_MAX_CHANNELS)) {
+               pr_err("%s: invalid input channel %d\n", __func__,
+                               params->input_channel);
+               return -EINVAL;
+       }
+
+       if ((params->output_channel < 0) ||
+               (params->output_channel > ADM_MAX_CHANNELS)) {
+               pr_err("%s: invalid output channel %d\n", __func__,
+                               params->output_channel);
+               return -EINVAL;
+       }
+       variable_payload = params->output_channel * sizeof(uint16_t)+
+                          params->input_channel * sizeof(uint16_t) +
+                          params->output_channel *
+                          params->input_channel * sizeof(uint16_t);
+       variable_payload = roundup(variable_payload, 4);
+
+       params_length = variable_payload +
+                       sizeof(struct adm_pspd_param_data_t) +
+                       sizeof(struct audproc_chmixer_param_coeff);
+       adm_params = kzalloc(params_length, GFP_KERNEL);
+       if (!adm_params)
+               return -ENOMEM;
+
+       data.module_id  = AUDPROC_MODULE_ID_CHMIXER;
+       data.param_id   = AUDPROC_CHMIXER_PARAM_ID_COEFF;
+       data.param_size = sizeof(struct audproc_chmixer_param_coeff) +
+                         variable_payload;
+       data.reserved   = 0;
+       memcpy((u8 *)adm_params, &data, sizeof(struct adm_pspd_param_data_t));
+
+       chmixer_cfg.index               = params->rule;
+       chmixer_cfg.num_output_channels = params->output_channel;
+       chmixer_cfg.num_input_channels  = params->input_channel;
+       memcpy(((u8 *)adm_params +
+               sizeof(struct adm_pspd_param_data_t)),
+               &chmixer_cfg, sizeof(struct audproc_chmixer_param_coeff));
+
+       memcpy(((u8 *)adm_params +
+               sizeof(struct adm_pspd_param_data_t) +
+               sizeof(struct audproc_chmixer_param_coeff)),
+               params->out_ch_map,
+               params->output_channel * sizeof(uint16_t));
+       memcpy(((u8 *)adm_params +
+               sizeof(struct adm_pspd_param_data_t) +
+               sizeof(struct audproc_chmixer_param_coeff) +
+               params->output_channel * sizeof(uint16_t)),
+               params->in_ch_map,
+               params->input_channel * sizeof(uint16_t));
+
+       dst_gain_ptr = (uint16_t *) ((u8 *)adm_params +
+               sizeof(struct adm_pspd_param_data_t) +
+               sizeof(struct audproc_chmixer_param_coeff) +
+               (params->output_channel * sizeof(uint16_t)) +
+               (params->input_channel * sizeof(uint16_t)));
+
+       for (i = 0; i < params->output_channel; i++) {
+               for (j = 0; j < params->input_channel; j++) {
+                       *dst_gain_ptr = (uint16_t) params->channel_weight[i][j];
+                        pr_debug("%s: ptr[%d][%d] = %d\n",
+                               __func__, i, j, *dst_gain_ptr);
+                       dst_gain_ptr++;
+               }
+       }
+
+       if (params_length) {
+               rc = adm_set_pspd_matrix_params(port_id,
+                                               copp_idx,
+                                               session_id,
+                                               adm_params,
+                                               params_length,
+                                               session_type);
+               if (rc) {
+                       pr_err("%s: send params failed rc=%d\n", __func__, rc);
+                       rc = -EINVAL;
+               }
+       }
+
+       kfree(adm_params);
+       return rc;
+}
+EXPORT_SYMBOL(msm_pcm_routing_set_channel_mixer_runtime);
+
 int msm_routing_set_downmix_control_data(int be_id, int session_id,
                        struct asm_stream_pan_ctrl_params *dnmix_param)
 {
@@ -16554,7 +16787,8 @@ int msm_routing_set_downmix_control_data(int be_id, int session_id,
                                                copp_idx,
                                                session_id,
                                                adm_params,
-                                               params_length);
+                                               params_length,
+                                               ADM_MATRIX_ID_AUDIO_RX);
                if (rc) {
                        pr_err("%s: send params failed rc=%d\n", __func__, rc);
                        rc = -EINVAL;
index 99541b8..63c90dc 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,6 +12,7 @@
 #ifndef _MSM_PCM_ROUTING_H
 #define _MSM_PCM_ROUTING_H
 #include <sound/apr_audio-v2.h>
+#include <sound/q6adm-v2.h>
 
 /*
  * These names are used by HAL to specify the BE. If any changes are
@@ -502,4 +503,12 @@ int msm_pcm_routing_get_stream_app_type_cfg(
        struct msm_pcm_stream_app_type_cfg *cfg_data);
 int msm_routing_set_downmix_control_data(int be_id, int session_id,
                                 struct asm_stream_pan_ctrl_params *pan_param);
+int msm_pcm_routing_set_channel_mixer_runtime(
+       int be_id, int session_id,
+       int session_type,
+       struct msm_pcm_channel_mixer *params);
+
+int msm_pcm_routing_set_channel_mixer_cfg(
+       int fe_id, int session_type,
+       struct msm_pcm_channel_mixer *params);
 #endif /*_MSM_PCM_H*/
index bcfb090..1ddb384 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -303,7 +303,8 @@ int msm_qti_pp_send_stereo_to_custom_stereo_cmd(int port_id, int copp_idx,
                                                copp_idx,
                                                session_id,
                                                params_value,
-                                               params_length);
+                                               params_length,
+                                               ADM_MATRIX_ID_AUDIO_RX);
                if (rc) {
                        pr_err("%s: send params failed rc=%d\n", __func__, rc);
                        kfree(params_value);
index 18cac34..72dd751 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -645,6 +645,7 @@ static int msm_transcode_stream_cmd_put(struct snd_kcontrol *kcontrol,
        struct msm_transcode_loopback *prtd;
        int ret = 0;
        struct msm_adsp_event_data *event_data = NULL;
+       uint64_t actual_payload_len = 0;
 
        if (fe_id >= MSM_FRONTEND_DAI_MAX) {
                pr_err("%s Received invalid fe_id %lu\n",
@@ -682,6 +683,16 @@ static int msm_transcode_stream_cmd_put(struct snd_kcontrol *kcontrol,
                goto done;
        }
 
+       actual_payload_len = sizeof(struct msm_adsp_event_data) +
+               event_data->payload_len;
+       if (actual_payload_len >= U32_MAX) {
+               pr_err("%s payload length 0x%X  exceeds limit",
+                               __func__, event_data->payload_len);
+               ret = -EINVAL;
+               goto done;
+       }
+
+
        if ((sizeof(struct msm_adsp_event_data) + event_data->payload_len) >=
                                        sizeof(ucontrol->value.bytes.data)) {
                pr_err("%s param length=%d  exceeds limit",
index 399263c..ddefedb 100644 (file)
@@ -448,7 +448,7 @@ int adm_programable_channel_mixer(int port_id, int copp_idx, int session_id,
                        ch_mixer->input_channels[channel_index] +
                        ch_mixer->input_channels[channel_index] *
                        ch_mixer->output_channel);
-       roundup(param_size, 4);
+       param_size = roundup(param_size, 4);
 
        sz = sizeof(struct adm_cmd_set_pspd_mtmx_strtr_params_v5) +
             sizeof(struct default_chmixer_param_id_coeff) +
@@ -490,81 +490,91 @@ int adm_programable_channel_mixer(int port_id, int copp_idx, int session_id,
        adm_pspd_params[3] = ch_mixer->input_channels[channel_index];
        index = 4;
 
-       if (ch_mixer->output_channel == 1) {
-               adm_pspd_params[index] = PCM_CHANNEL_FC;
-       } else if (ch_mixer->output_channel == 2) {
-               adm_pspd_params[index] = PCM_CHANNEL_FL;
-               adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
-       } else if (ch_mixer->output_channel == 3) {
-               adm_pspd_params[index] = PCM_CHANNEL_FL;
-               adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
-               adm_pspd_params[index + 2] = PCM_CHANNEL_FC;
-       } else if (ch_mixer->output_channel == 4) {
-               adm_pspd_params[index] = PCM_CHANNEL_FL;
-               adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
-               adm_pspd_params[index + 2] = PCM_CHANNEL_LS;
-               adm_pspd_params[index + 3] = PCM_CHANNEL_RS;
-       } else if (ch_mixer->output_channel == 5) {
-               adm_pspd_params[index] = PCM_CHANNEL_FL;
-               adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
-               adm_pspd_params[index + 2] = PCM_CHANNEL_FC;
-               adm_pspd_params[index + 3] = PCM_CHANNEL_LS;
-               adm_pspd_params[index + 4] = PCM_CHANNEL_RS;
-       } else if (ch_mixer->output_channel == 6) {
-               adm_pspd_params[index] = PCM_CHANNEL_FL;
-               adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
-               adm_pspd_params[index + 2] = PCM_CHANNEL_LFE;
-               adm_pspd_params[index + 3] = PCM_CHANNEL_FC;
-               adm_pspd_params[index + 4] = PCM_CHANNEL_LS;
-               adm_pspd_params[index + 5] = PCM_CHANNEL_RS;
-       } else if (ch_mixer->output_channel == 8) {
-               adm_pspd_params[index] = PCM_CHANNEL_FL;
-               adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
-               adm_pspd_params[index + 2] = PCM_CHANNEL_LFE;
-               adm_pspd_params[index + 3] = PCM_CHANNEL_FC;
-               adm_pspd_params[index + 4] = PCM_CHANNEL_LS;
-               adm_pspd_params[index + 5] = PCM_CHANNEL_RS;
-               adm_pspd_params[index + 6] = PCM_CHANNEL_LB;
-               adm_pspd_params[index + 7] = PCM_CHANNEL_RB;
+       if (ch_mixer->override_cfg) {
+               memcpy(&adm_pspd_params[index], &ch_mixer->out_ch_map,
+                       ch_mixer->output_channel * sizeof(uint16_t));
+       } else {
+               if (ch_mixer->output_channel == 1) {
+                       adm_pspd_params[index] = PCM_CHANNEL_FC;
+               } else if (ch_mixer->output_channel == 2) {
+                       adm_pspd_params[index] = PCM_CHANNEL_FL;
+                       adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+               } else if (ch_mixer->output_channel == 3) {
+                       adm_pspd_params[index] = PCM_CHANNEL_FL;
+                       adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+                       adm_pspd_params[index + 2] = PCM_CHANNEL_FC;
+               } else if (ch_mixer->output_channel == 4) {
+                       adm_pspd_params[index] = PCM_CHANNEL_FL;
+                       adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+                       adm_pspd_params[index + 2] = PCM_CHANNEL_LS;
+                       adm_pspd_params[index + 3] = PCM_CHANNEL_RS;
+               } else if (ch_mixer->output_channel == 5) {
+                       adm_pspd_params[index] = PCM_CHANNEL_FL;
+                       adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+                       adm_pspd_params[index + 2] = PCM_CHANNEL_FC;
+                       adm_pspd_params[index + 3] = PCM_CHANNEL_LS;
+                       adm_pspd_params[index + 4] = PCM_CHANNEL_RS;
+               } else if (ch_mixer->output_channel == 6) {
+                       adm_pspd_params[index] = PCM_CHANNEL_FL;
+                       adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+                       adm_pspd_params[index + 2] = PCM_CHANNEL_LFE;
+                       adm_pspd_params[index + 3] = PCM_CHANNEL_FC;
+                       adm_pspd_params[index + 4] = PCM_CHANNEL_LS;
+                       adm_pspd_params[index + 5] = PCM_CHANNEL_RS;
+               } else if (ch_mixer->output_channel == 8) {
+                       adm_pspd_params[index] = PCM_CHANNEL_FL;
+                       adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+                       adm_pspd_params[index + 2] = PCM_CHANNEL_LFE;
+                       adm_pspd_params[index + 3] = PCM_CHANNEL_FC;
+                       adm_pspd_params[index + 4] = PCM_CHANNEL_LS;
+                       adm_pspd_params[index + 5] = PCM_CHANNEL_RS;
+                       adm_pspd_params[index + 6] = PCM_CHANNEL_LB;
+                       adm_pspd_params[index + 7] = PCM_CHANNEL_RB;
+               }
        }
 
        index = index + ch_mixer->output_channel;
-       if (ch_mixer->input_channels[channel_index] == 1) {
-               adm_pspd_params[index] = PCM_CHANNEL_FC;
-       } else if (ch_mixer->input_channels[channel_index] == 2) {
-               adm_pspd_params[index] = PCM_CHANNEL_FL;
-               adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
-       } else if (ch_mixer->input_channels[channel_index] == 3) {
-               adm_pspd_params[index] = PCM_CHANNEL_FL;
-               adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
-               adm_pspd_params[index + 2] = PCM_CHANNEL_FC;
-       } else if (ch_mixer->input_channels[channel_index] == 4) {
-               adm_pspd_params[index] = PCM_CHANNEL_FL;
-               adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
-               adm_pspd_params[index + 2] = PCM_CHANNEL_LS;
-               adm_pspd_params[index + 3] = PCM_CHANNEL_RS;
-       } else if (ch_mixer->input_channels[channel_index] == 5) {
-               adm_pspd_params[index] = PCM_CHANNEL_FL;
-               adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
-               adm_pspd_params[index + 2] = PCM_CHANNEL_FC;
-               adm_pspd_params[index + 3] = PCM_CHANNEL_LS;
-               adm_pspd_params[index + 4] = PCM_CHANNEL_RS;
-       } else if (ch_mixer->input_channels[channel_index] == 6) {
-               adm_pspd_params[index] = PCM_CHANNEL_FL;
-               adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
-               adm_pspd_params[index + 2] = PCM_CHANNEL_LFE;
-               adm_pspd_params[index + 3] = PCM_CHANNEL_FC;
-               adm_pspd_params[index + 4] = PCM_CHANNEL_LS;
-               adm_pspd_params[index + 5] = PCM_CHANNEL_RS;
-       } else if (ch_mixer->input_channels[channel_index] == 8) {
-               adm_pspd_params[index] = PCM_CHANNEL_FL;
-               adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
-               adm_pspd_params[index + 2] = PCM_CHANNEL_LFE;
-               adm_pspd_params[index + 3] = PCM_CHANNEL_FC;
-               adm_pspd_params[index + 4] = PCM_CHANNEL_LS;
-               adm_pspd_params[index + 5] = PCM_CHANNEL_RS;
-               adm_pspd_params[index + 6] = PCM_CHANNEL_LB;
-               adm_pspd_params[index + 7] = PCM_CHANNEL_RB;
+       if (ch_mixer->override_cfg) {
+               memcpy(&adm_pspd_params[index], &ch_mixer->in_ch_map,
+                       ch_mixer->input_channel * sizeof(uint16_t));
+       } else {
+               if (ch_mixer->input_channels[channel_index] == 1) {
+                       adm_pspd_params[index] = PCM_CHANNEL_FC;
+               } else if (ch_mixer->input_channels[channel_index] == 2) {
+                       adm_pspd_params[index] = PCM_CHANNEL_FL;
+                       adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+               } else if (ch_mixer->input_channels[channel_index] == 3) {
+                       adm_pspd_params[index] = PCM_CHANNEL_FL;
+                       adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+                       adm_pspd_params[index + 2] = PCM_CHANNEL_FC;
+               } else if (ch_mixer->input_channels[channel_index] == 4) {
+                       adm_pspd_params[index] = PCM_CHANNEL_FL;
+                       adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+                       adm_pspd_params[index + 2] = PCM_CHANNEL_LS;
+                       adm_pspd_params[index + 3] = PCM_CHANNEL_RS;
+               } else if (ch_mixer->input_channels[channel_index] == 5) {
+                       adm_pspd_params[index] = PCM_CHANNEL_FL;
+                       adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+                       adm_pspd_params[index + 2] = PCM_CHANNEL_FC;
+                       adm_pspd_params[index + 3] = PCM_CHANNEL_LS;
+                       adm_pspd_params[index + 4] = PCM_CHANNEL_RS;
+               } else if (ch_mixer->input_channels[channel_index] == 6) {
+                       adm_pspd_params[index] = PCM_CHANNEL_FL;
+                       adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+                       adm_pspd_params[index + 2] = PCM_CHANNEL_LFE;
+                       adm_pspd_params[index + 3] = PCM_CHANNEL_FC;
+                       adm_pspd_params[index + 4] = PCM_CHANNEL_LS;
+                       adm_pspd_params[index + 5] = PCM_CHANNEL_RS;
+               } else if (ch_mixer->input_channels[channel_index] == 8) {
+                       adm_pspd_params[index] = PCM_CHANNEL_FL;
+                       adm_pspd_params[index + 1] = PCM_CHANNEL_FR;
+                       adm_pspd_params[index + 2] = PCM_CHANNEL_LFE;
+                       adm_pspd_params[index + 3] = PCM_CHANNEL_FC;
+                       adm_pspd_params[index + 4] = PCM_CHANNEL_LS;
+                       adm_pspd_params[index + 5] = PCM_CHANNEL_RS;
+                       adm_pspd_params[index + 6] = PCM_CHANNEL_LB;
+                       adm_pspd_params[index + 7] = PCM_CHANNEL_RB;
+               }
        }
 
        index = index + ch_mixer->input_channels[channel_index];
@@ -626,7 +636,8 @@ fail_cmd:
 
 int adm_set_pspd_matrix_params(int port_id, int copp_idx,
                                unsigned int session_id, char *params,
-                               uint32_t params_length)
+                               uint32_t params_length,
+                               int session_type)
 {
        struct adm_cmd_set_pspd_mtmx_strtr_params_v5 *adm_params = NULL;
        int sz, rc = 0, port_idx;
@@ -666,7 +677,7 @@ int adm_set_pspd_matrix_params(int port_id, int copp_idx,
        adm_params->mem_map_handle = 0;
        adm_params->payload_size = params_length;
        /* direction RX as 0 */
-       adm_params->direction = ADM_MATRIX_ID_AUDIO_RX;
+       adm_params->direction = session_type;
        /* session id for this cmd to be applied on */
        adm_params->sessionid = session_id;
        adm_params->deviceid =
index 9658020..352ea92 100644 (file)
@@ -28,6 +28,7 @@
 #include <sound/audio_cal_utils.h>
 #include <sound/adsp_err.h>
 #include <linux/qdsp6v2/apr_tal.h>
+#include <sound/q6core.h>
 
 #define WAKELOCK_TIMEOUT       5000
 enum {
@@ -144,6 +145,39 @@ static int afe_get_cal_hw_delay(int32_t path,
                                struct audio_cal_hw_delay_entry *entry);
 static int remap_cal_data(struct cal_block_data *cal_block, int cal_index);
 
+int afe_get_svc_version(uint32_t service_id)
+{
+       int ret = 0;
+       static int afe_cached_version;
+       size_t ver_size;
+       struct avcs_fwk_ver_info *ver_info = NULL;
+
+       if (service_id == AVCS_SERVICE_ID_ALL) {
+               pr_err("%s: Invalid service id: %d", __func__,
+                                       AVCS_SERVICE_ID_ALL);
+               return -EINVAL;
+       }
+
+       if (afe_cached_version != 0)
+               return afe_cached_version;
+
+       ver_size = sizeof(struct avcs_get_fwk_version) +
+                       sizeof(struct avs_svc_api_info);
+       ver_info = kzalloc(ver_size, GFP_KERNEL);
+       if (ver_info == NULL)
+               return -ENOMEM;
+
+       ret = q6core_get_service_version(service_id, ver_info, ver_size);
+       if (ret < 0)
+               goto done;
+
+       ret = ver_info->services[0].api_version;
+       afe_cached_version = ret;
+done:
+       kfree(ver_info);
+       return ret;
+}
+
 int afe_get_topology(int port_id)
 {
        int topology;
@@ -2447,6 +2481,36 @@ fail_cmd:
        return ret;
 }
 
+static int afe_send_slot_mapping_cfg_v2(
+       struct afe_param_id_slot_mapping_cfg_v2 *slot_mapping_cfg,
+       u16 port_id)
+{
+       struct param_hdr_v3 param_hdr = {0};
+       int ret = 0;
+
+       if (!slot_mapping_cfg) {
+               pr_err("%s: Error, no configuration data\n", __func__);
+               return -EINVAL;
+       }
+
+       pr_debug("%s: port id: 0x%x\n", __func__, port_id);
+
+       param_hdr.module_id = AFE_MODULE_TDM;
+       param_hdr.instance_id = INSTANCE_ID_0;
+       param_hdr.param_id = AFE_PARAM_ID_PORT_SLOT_MAPPING_CONFIG;
+       param_hdr.param_size = sizeof(struct afe_param_id_slot_mapping_cfg_v2);
+
+       ret = q6afe_pack_and_set_param_in_band(port_id,
+                                              q6audio_get_port_index(port_id),
+                                              param_hdr,
+                                              (u8 *) slot_mapping_cfg);
+       if (ret < 0)
+               pr_err("%s: AFE send slot mapping for port 0x%x failed ret = %d\n",
+                               __func__, port_id, ret);
+       return ret;
+}
+
+
 int afe_send_slot_mapping_cfg(
        struct afe_param_id_slot_mapping_cfg *slot_mapping_cfg,
        u16 port_id)
@@ -2603,8 +2667,15 @@ int afe_tdm_port_start(u16 port_id, struct afe_tdm_port_config *tdm_port,
        }
        /* slot mapping is not need if there is only one group */
        if (num_groups > 1) {
-               ret = afe_send_slot_mapping_cfg(&tdm_port->slot_mapping,
-                                               port_id);
+               if (afe_get_svc_version(APR_SVC_AFE) >=
+                               ADSP_AFE_API_VERSION_V3)
+                       ret = afe_send_slot_mapping_cfg_v2(
+                                       &tdm_port->slot_mapping_v2,
+                                       port_id);
+               else
+                       ret = afe_send_slot_mapping_cfg(
+                                       &tdm_port->slot_mapping,
+                                       port_id);
                if (ret < 0) {
                        pr_err("%s: afe send failed %d\n", __func__, ret);
                        goto fail_cmd;
index 201234a..9e14b34 100644 (file)
@@ -47,6 +47,7 @@
 #define FALSE       0x00
 #define SESSION_MAX 9
 #define ASM_MAX_CHANNELS 8
+
 enum {
        ASM_TOPOLOGY_CAL = 0,
        ASM_CUSTOM_TOP_CAL,
@@ -286,6 +287,11 @@ static ssize_t audio_output_latency_dbgfs_read(struct file *file,
                pr_err("%s: out_buffer is null\n", __func__);
                return 0;
        }
+       if (count < OUT_BUFFER_SIZE) {
+               pr_err("%s: read size %d exceeds buf size %zd\n", __func__,
+                                               OUT_BUFFER_SIZE, count);
+               return 0;
+       }
        snprintf(out_buffer, OUT_BUFFER_SIZE, "%ld,%ld,%ld,%ld,%ld,%ld,",\
                out_cold_tv.tv_sec, out_cold_tv.tv_usec, out_warm_tv.tv_sec,\
                out_warm_tv.tv_usec, out_cont_tv.tv_sec, out_cont_tv.tv_usec);
@@ -339,6 +345,11 @@ static ssize_t audio_input_latency_dbgfs_read(struct file *file,
                pr_err("%s: in_buffer is null\n", __func__);
                return 0;
        }
+       if (count < IN_BUFFER_SIZE) {
+               pr_err("%s: read size %d exceeds buf size %zd\n", __func__,
+                                               IN_BUFFER_SIZE, count);
+               return 0;
+       }
        snprintf(in_buffer, IN_BUFFER_SIZE, "%ld,%ld,",\
                                in_cont_tv.tv_sec, in_cont_tv.tv_usec);
        return  simple_read_from_buffer(buf, IN_BUFFER_SIZE, ppos,
@@ -1159,7 +1170,9 @@ int q6asm_send_stream_cmd(struct audio_client *ac,
 {
        char *asm_params = NULL;
        struct apr_hdr hdr;
-       int sz, rc;
+       int rc;
+       uint32_t sz = 0;
+       uint64_t actual_sz = 0;
 
        if (!data || !ac) {
                pr_err("%s: %s is NULL\n", __func__,
@@ -1176,7 +1189,15 @@ int q6asm_send_stream_cmd(struct audio_client *ac,
                goto done;
        }
 
-       sz = sizeof(struct apr_hdr) + data->payload_len;
+       actual_sz = sizeof(struct apr_hdr) + data->payload_len;
+       if (actual_sz > U32_MAX) {
+               pr_err("%s: payload size 0x%X exceeds limit\n",
+                               __func__, data->payload_len);
+               rc = -EINVAL;
+               goto done;
+       }
+
+       sz = (uint32_t)actual_sz;
        asm_params = kzalloc(sz, GFP_KERNEL);
        if (!asm_params) {
                rc = -ENOMEM;
index 5a806da..5e2eb4c 100644 (file)
@@ -54,7 +54,7 @@ static const struct of_device_id rk_spdif_match[] = {
 };
 MODULE_DEVICE_TABLE(of, rk_spdif_match);
 
-static int rk_spdif_runtime_suspend(struct device *dev)
+static int __maybe_unused rk_spdif_runtime_suspend(struct device *dev)
 {
        struct rk_spdif_dev *spdif = dev_get_drvdata(dev);
 
@@ -64,7 +64,7 @@ static int rk_spdif_runtime_suspend(struct device *dev)
        return 0;
 }
 
-static int rk_spdif_runtime_resume(struct device *dev)
+static int __maybe_unused rk_spdif_runtime_resume(struct device *dev)
 {
        struct rk_spdif_dev *spdif = dev_get_drvdata(dev);
        int ret;
@@ -316,26 +316,30 @@ static int rk_spdif_probe(struct platform_device *pdev)
        spdif->mclk = devm_clk_get(&pdev->dev, "mclk");
        if (IS_ERR(spdif->mclk)) {
                dev_err(&pdev->dev, "Can't retrieve rk_spdif master clock\n");
-               return PTR_ERR(spdif->mclk);
+               ret = PTR_ERR(spdif->mclk);
+               goto err_disable_hclk;
        }
 
        ret = clk_prepare_enable(spdif->mclk);
        if (ret) {
                dev_err(spdif->dev, "clock enable failed %d\n", ret);
-               return ret;
+               goto err_disable_clocks;
        }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        regs = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(regs))
-               return PTR_ERR(regs);
+       if (IS_ERR(regs)) {
+               ret = PTR_ERR(regs);
+               goto err_disable_clocks;
+       }
 
        spdif->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "hclk", regs,
                                                  &rk_spdif_regmap_config);
        if (IS_ERR(spdif->regmap)) {
                dev_err(&pdev->dev,
                        "Failed to initialise managed register map\n");
-               return PTR_ERR(spdif->regmap);
+               ret = PTR_ERR(spdif->regmap);
+               goto err_disable_clocks;
        }
 
        spdif->playback_dma_data.addr = res->start + SPDIF_SMPDR;
@@ -367,6 +371,10 @@ static int rk_spdif_probe(struct platform_device *pdev)
 
 err_pm_runtime:
        pm_runtime_disable(&pdev->dev);
+err_disable_clocks:
+       clk_disable_unprepare(spdif->mclk);
+err_disable_hclk:
+       clk_disable_unprepare(spdif->hclk);
 
        return ret;
 }
index 0853298..5976e39 100644 (file)
@@ -235,6 +235,7 @@ enum rsnd_mod_type {
        RSND_MOD_MIX,
        RSND_MOD_CTU,
        RSND_MOD_SRC,
+       RSND_MOD_SSIP, /* SSI parent */
        RSND_MOD_SSI,
        RSND_MOD_MAX,
 };
@@ -365,6 +366,7 @@ struct rsnd_dai_stream {
 };
 #define rsnd_io_to_mod(io, i)  ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL)
 #define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI)
+#define rsnd_io_to_mod_ssip(io) rsnd_io_to_mod((io), RSND_MOD_SSIP)
 #define rsnd_io_to_mod_src(io) rsnd_io_to_mod((io), RSND_MOD_SRC)
 #define rsnd_io_to_mod_ctu(io) rsnd_io_to_mod((io), RSND_MOD_CTU)
 #define rsnd_io_to_mod_mix(io) rsnd_io_to_mod((io), RSND_MOD_MIX)
index c62a294..38aae96 100644 (file)
@@ -550,11 +550,16 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod,
                               struct rsnd_priv *priv)
 {
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+       struct rsnd_mod *pure_ssi_mod = rsnd_io_to_mod_ssi(io);
        struct device *dev = rsnd_priv_to_dev(priv);
        int irq = ssi->info->irq;
 
        rsnd_dma_quit(io, rsnd_mod_to_dma(mod));
 
+       /* Do nothing if non SSI (= SSI parent, multi SSI) mod */
+       if (pure_ssi_mod != mod)
+               return 0;
+
        /* PIO will request IRQ again */
        devm_free_irq(dev, irq, mod);
 
index ba9fc09..503aef8 100644 (file)
@@ -164,3 +164,7 @@ static struct platform_driver snd_soc_mop500_driver = {
 };
 
 module_platform_driver(snd_soc_mop500_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("ASoC MOP500 board driver");
+MODULE_AUTHOR("Ola Lilja");
index f12c01d..d35ba77 100644 (file)
@@ -165,3 +165,8 @@ int ux500_pcm_unregister_platform(struct platform_device *pdev)
        return 0;
 }
 EXPORT_SYMBOL_GPL(ux500_pcm_unregister_platform);
+
+MODULE_AUTHOR("Ola Lilja");
+MODULE_AUTHOR("Roger Nilsson");
+MODULE_DESCRIPTION("ASoC UX500 driver");
+MODULE_LICENSE("GPL v2");
index deb6baf..ab23051 100644 (file)
@@ -355,17 +355,20 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request,
                            int validx, int *value_ret)
 {
        struct snd_usb_audio *chip = cval->head.mixer->chip;
-       unsigned char buf[4 + 3 * sizeof(__u32)]; /* enough space for one range */
+       /* enough space for one range */
+       unsigned char buf[sizeof(__u16) + 3 * sizeof(__u32)];
        unsigned char *val;
-       int idx = 0, ret, size;
+       int idx = 0, ret, val_size, size;
        __u8 bRequest;
 
+       val_size = uac2_ctl_value_size(cval->val_type);
+
        if (request == UAC_GET_CUR) {
                bRequest = UAC2_CS_CUR;
-               size = uac2_ctl_value_size(cval->val_type);
+               size = val_size;
        } else {
                bRequest = UAC2_CS_RANGE;
-               size = sizeof(buf);
+               size = sizeof(__u16) + 3 * val_size;
        }
 
        memset(buf, 0, sizeof(buf));
@@ -398,16 +401,17 @@ error:
                val = buf + sizeof(__u16);
                break;
        case UAC_GET_MAX:
-               val = buf + sizeof(__u16) * 2;
+               val = buf + sizeof(__u16) + val_size;
                break;
        case UAC_GET_RES:
-               val = buf + sizeof(__u16) * 3;
+               val = buf + sizeof(__u16) + val_size * 2;
                break;
        default:
                return -EINVAL;
        }
 
-       *value_ret = convert_signed_value(cval, snd_usb_combine_bytes(val, sizeof(__u16)));
+       *value_ret = convert_signed_value(cval,
+                                         snd_usb_combine_bytes(val, val_size));
 
        return 0;
 }
index 4c92910..07d9ae1 100644 (file)
@@ -348,6 +348,15 @@ static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs,
 
                alts = &iface->altsetting[1];
                goto add_sync_ep;
+       case USB_ID(0x1397, 0x0002):
+               ep = 0x81;
+               iface = usb_ifnum_to_if(dev, 1);
+
+               if (!iface || iface->num_altsetting == 0)
+                       return -EINVAL;
+
+               alts = &iface->altsetting[1];
+               goto add_sync_ep;
        }
        if (attr == USB_ENDPOINT_SYNC_ASYNC &&
            altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC &&
index 4a96473..4ffc096 100644 (file)
@@ -19,6 +19,16 @@ else
   Q=@
 endif
 
+ifneq ($(filter 4.%,$(MAKE_VERSION)),) # make-4
+ifneq ($(filter %s ,$(firstword x$(MAKEFLAGS))),)
+  quiet=silent_
+endif
+else                                   # make-3.8x
+ifneq ($(filter s% -s%,$(MAKEFLAGS)),)
+  quiet=silent_
+endif
+endif
+
 build-dir := $(srctree)/tools/build
 
 # Define $(fixdep) for dep-cmd function
index b4eb5b6..73d192f 100644 (file)
@@ -208,6 +208,47 @@ static const char * const numa_usage[] = {
        NULL
 };
 
+/*
+ * To get number of numa nodes present.
+ */
+static int nr_numa_nodes(void)
+{
+       int i, nr_nodes = 0;
+
+       for (i = 0; i < g->p.nr_nodes; i++) {
+               if (numa_bitmask_isbitset(numa_nodes_ptr, i))
+                       nr_nodes++;
+       }
+
+       return nr_nodes;
+}
+
+/*
+ * To check if given numa node is present.
+ */
+static int is_node_present(int node)
+{
+       return numa_bitmask_isbitset(numa_nodes_ptr, node);
+}
+
+/*
+ * To check given numa node has cpus.
+ */
+static bool node_has_cpus(int node)
+{
+       struct bitmask *cpu = numa_allocate_cpumask();
+       unsigned int i;
+
+       if (cpu && !numa_node_to_cpus(node, cpu)) {
+               for (i = 0; i < cpu->size; i++) {
+                       if (numa_bitmask_isbitset(cpu, i))
+                               return true;
+               }
+       }
+
+       return false; /* lets fall back to nocpus safely */
+}
+
 static cpu_set_t bind_to_cpu(int target_cpu)
 {
        cpu_set_t orig_mask, mask;
@@ -236,12 +277,12 @@ static cpu_set_t bind_to_cpu(int target_cpu)
 
 static cpu_set_t bind_to_node(int target_node)
 {
-       int cpus_per_node = g->p.nr_cpus/g->p.nr_nodes;
+       int cpus_per_node = g->p.nr_cpus / nr_numa_nodes();
        cpu_set_t orig_mask, mask;
        int cpu;
        int ret;
 
-       BUG_ON(cpus_per_node*g->p.nr_nodes != g->p.nr_cpus);
+       BUG_ON(cpus_per_node * nr_numa_nodes() != g->p.nr_cpus);
        BUG_ON(!cpus_per_node);
 
        ret = sched_getaffinity(0, sizeof(orig_mask), &orig_mask);
@@ -641,7 +682,7 @@ static int parse_setup_node_list(void)
                        int i;
 
                        for (i = 0; i < mul; i++) {
-                               if (t >= g->p.nr_tasks) {
+                               if (t >= g->p.nr_tasks || !node_has_cpus(bind_node)) {
                                        printf("\n# NOTE: ignoring bind NODEs starting at NODE#%d\n", bind_node);
                                        goto out;
                                }
@@ -956,6 +997,8 @@ static void calc_convergence(double runtime_ns_max, double *convergence)
        sum = 0;
 
        for (node = 0; node < g->p.nr_nodes; node++) {
+               if (!is_node_present(node))
+                       continue;
                nr = nodes[node];
                nr_min = min(nr, nr_min);
                nr_max = max(nr, nr_max);
@@ -976,8 +1019,11 @@ static void calc_convergence(double runtime_ns_max, double *convergence)
        process_groups = 0;
 
        for (node = 0; node < g->p.nr_nodes; node++) {
-               int processes = count_node_processes(node);
+               int processes;
 
+               if (!is_node_present(node))
+                       continue;
+               processes = count_node_processes(node);
                nr = nodes[node];
                tprintf(" %2d/%-2d", nr, processes);
 
@@ -1283,7 +1329,7 @@ static void print_summary(void)
 
        printf("\n ###\n");
        printf(" # %d %s will execute (on %d nodes, %d CPUs):\n",
-               g->p.nr_tasks, g->p.nr_tasks == 1 ? "task" : "tasks", g->p.nr_nodes, g->p.nr_cpus);
+               g->p.nr_tasks, g->p.nr_tasks == 1 ? "task" : "tasks", nr_numa_nodes(), g->p.nr_cpus);
        printf(" #      %5dx %5ldMB global  shared mem operations\n",
                        g->p.nr_loops, g->p.bytes_global/1024/1024);
        printf(" #      %5dx %5ldMB process shared mem operations\n",
index 4a8a02c..47719bd 100644 (file)
@@ -70,6 +70,7 @@
 #include <linux/types.h>
 
 static volatile int done;
+static volatile int resize;
 
 #define HEADER_LINE_NR  5
 
@@ -79,10 +80,13 @@ static void perf_top__update_print_entries(struct perf_top *top)
 }
 
 static void perf_top__sig_winch(int sig __maybe_unused,
-                               siginfo_t *info __maybe_unused, void *arg)
+                               siginfo_t *info __maybe_unused, void *arg __maybe_unused)
 {
-       struct perf_top *top = arg;
+       resize = 1;
+}
 
+static void perf_top__resize(struct perf_top *top)
+{
        get_term_dimensions(&top->winsize);
        perf_top__update_print_entries(top);
 }
@@ -466,7 +470,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c)
                                        .sa_sigaction = perf_top__sig_winch,
                                        .sa_flags     = SA_SIGINFO,
                                };
-                               perf_top__sig_winch(SIGWINCH, NULL, top);
+                               perf_top__resize(top);
                                sigaction(SIGWINCH, &act, NULL);
                        } else {
                                signal(SIGWINCH, SIG_DFL);
@@ -1023,6 +1027,11 @@ static int __cmd_top(struct perf_top *top)
 
                if (hits == top->samples)
                        ret = perf_evlist__poll(top->evlist, 100);
+
+               if (resize) {
+                       perf_top__resize(top);
+                       resize = 0;
+               }
        }
 
        ret = 0;
index 8abbef1..19edc1a 100644 (file)
@@ -46,6 +46,16 @@ else
 NO_SUBDIR = :
 endif
 
+ifneq ($(filter 4.%,$(MAKE_VERSION)),)  # make-4
+ifneq ($(filter %s ,$(firstword x$(MAKEFLAGS))),)
+  silent=1
+endif
+else                                   # make-3.8x
+ifneq ($(filter s% -s%,$(MAKEFLAGS)),)
+  silent=1
+endif
+endif
+
 #
 # Define a callable command for descending to a new directory
 #
@@ -58,7 +68,7 @@ descend = \
 QUIET_SUBDIR0  = +$(MAKE) $(COMMAND_O) -C # space to separate -C and subdir
 QUIET_SUBDIR1  =
 
-ifneq ($(findstring $(MAKEFLAGS),s),s)
+ifneq ($(silent),1)
   ifneq ($(V),1)
        QUIET_CC       = @echo '  CC       '$@;
        QUIET_CC_FPIC  = @echo '  CC FPIC  '$@;