Merge tag 'dma-rename-4.18' of git://git.infradead.org/users/hch/dma-mapping
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 20 Jun 2018 07:30:01 +0000 (16:30 +0900)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 20 Jun 2018 07:30:01 +0000 (16:30 +0900)
Pull dma-mapping rename from Christoph Hellwig:
 "Move all the dma-mapping code to kernel/dma and lose their dma-*
  prefixes"

* tag 'dma-rename-4.18' of git://git.infradead.org/users/hch/dma-mapping:
  dma-mapping: move all DMA mapping code to kernel/dma
  dma-mapping: use obj-y instead of lib-y for generic dma ops

897 files changed:
Documentation/ABI/obsolete/sysfs-gpio
Documentation/ABI/testing/sysfs-devices-system-cpu
Documentation/ABI/testing/sysfs-platform-ideapad-laptop
Documentation/admin-guide/LSM/apparmor.rst
Documentation/admin-guide/kernel-parameters.txt
Documentation/block/biodoc.txt
Documentation/core-api/kernel-api.rst
Documentation/crypto/crypto_engine.rst
Documentation/devicetree/bindings/clock/st/st,clkgen.txt
Documentation/devicetree/bindings/clock/ti/gate.txt
Documentation/devicetree/bindings/clock/ti/interface.txt
Documentation/devicetree/bindings/cpufreq/cpufreq-mediatek.txt
Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt
Documentation/devicetree/bindings/display/bridge/tda998x.txt
Documentation/devicetree/bindings/gpu/arm,mali-midgard.txt
Documentation/devicetree/bindings/gpu/arm,mali-utgard.txt
Documentation/devicetree/bindings/i2c/i2c-davinci.txt
Documentation/devicetree/bindings/i2c/i2c-rcar.txt
Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt
Documentation/devicetree/bindings/input/rmi4/rmi_2d_sensor.txt
Documentation/devicetree/bindings/input/rotary-encoder.txt
Documentation/devicetree/bindings/media/stih407-c8sectpfe.txt
Documentation/devicetree/bindings/mfd/as3722.txt
Documentation/devicetree/bindings/mfd/mt6397.txt
Documentation/devicetree/bindings/mfd/stm32-timers.txt
Documentation/devicetree/bindings/mfd/sun6i-prcm.txt
Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
Documentation/devicetree/bindings/mmc/microchip,sdhci-pic32.txt
Documentation/devicetree/bindings/mmc/sdhci-st.txt
Documentation/devicetree/bindings/net/dsa/ksz.txt
Documentation/devicetree/bindings/net/dsa/mt7530.txt
Documentation/devicetree/bindings/nvmem/zii,rave-sp-eeprom.txt
Documentation/devicetree/bindings/pci/hisilicon-pcie.txt
Documentation/devicetree/bindings/pci/kirin-pcie.txt
Documentation/devicetree/bindings/pci/pci-keystone.txt
Documentation/devicetree/bindings/pinctrl/pinctrl-max77620.txt
Documentation/devicetree/bindings/pinctrl/pinctrl-mcp23s08.txt
Documentation/devicetree/bindings/pinctrl/pinctrl-rk805.txt
Documentation/devicetree/bindings/power/fsl,imx-gpc.txt
Documentation/devicetree/bindings/power/supply/ab8500/btemp.txt
Documentation/devicetree/bindings/power/supply/ab8500/chargalg.txt
Documentation/devicetree/bindings/power/supply/ab8500/charger.txt
Documentation/devicetree/bindings/power/wakeup-source.txt
Documentation/devicetree/bindings/serial/microchip,pic32-uart.txt
Documentation/devicetree/bindings/sound/st,stm32-i2s.txt
Documentation/devicetree/bindings/sound/st,stm32-sai.txt
Documentation/devicetree/bindings/spi/spi-st-ssc.txt
Documentation/devicetree/bindings/usb/rockchip,dwc3.txt
Documentation/driver-api/gpio/consumer.rst
Documentation/features/debug/stackprotector/arch-support.txt
Documentation/filesystems/ceph.txt
Documentation/filesystems/cifs/AUTHORS
Documentation/filesystems/cifs/CHANGES
Documentation/filesystems/cifs/TODO
Documentation/hwmon/ina2xx
Documentation/i2c/busses/i2c-mlxcpld
Documentation/i2c/busses/i2c-ocores
Documentation/i2c/muxes/i2c-mux-gpio
Documentation/kbuild/kconfig-language.txt
Documentation/kprobes.txt
Documentation/laptops/thinkpad-acpi.txt
Documentation/maintainer/pull-requests.rst
Documentation/networking/can.rst
Documentation/riscv/pmu.txt [new file with mode: 0644]
Documentation/security/self-protection.rst
Documentation/sphinx/rstFlatTable.py
Documentation/trace/coresight.txt
Documentation/trace/events.rst
Documentation/trace/ftrace-uses.rst
Documentation/trace/histogram.txt
Documentation/trace/intel_th.rst
Documentation/trace/tracepoint-analysis.rst
Documentation/translations/ja_JP/howto.rst
Documentation/translations/ko_KR/howto.rst
Documentation/translations/zh_CN/SubmittingDrivers
Documentation/translations/zh_CN/gpio.txt
Documentation/translations/zh_CN/io_ordering.txt
Documentation/translations/zh_CN/magic-number.txt
Documentation/translations/zh_CN/video4linux/omap3isp.txt
Documentation/translations/zh_CN/video4linux/v4l2-framework.txt
MAINTAINERS
Makefile
arch/Kconfig
arch/arm/Kconfig
arch/arm/boot/compressed/Makefile
arch/arm/include/asm/cacheflush.h
arch/arm/kernel/asm-offsets.c
arch/arm/kernel/entry-armv.S
arch/arm/kernel/process.c
arch/arm/kvm/hyp/Makefile
arch/arm/mach-ks8695/board-acs5k.c
arch/arm/mach-omap1/board-htcherald.c
arch/arm/mach-omap1/common.h
arch/arm/mach-omap1/i2c.c
arch/arm/mach-omap2/common.h
arch/arm/mach-omap2/omap_hwmod_2420_data.c
arch/arm/mach-omap2/omap_hwmod_2430_data.c
arch/arm/mach-omap2/omap_hwmod_33xx_data.c
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
arch/arm/mach-omap2/omap_hwmod_44xx_data.c
arch/arm/mach-omap2/omap_hwmod_54xx_data.c
arch/arm/mach-omap2/omap_hwmod_7xx_data.c
arch/arm/mach-pxa/palmz72.c
arch/arm/mach-pxa/viper.c
arch/arm/mach-sa1100/simpad.c
arch/arm/vdso/Makefile
arch/arm64/Kconfig
arch/arm64/include/asm/cacheflush.h
arch/arm64/kernel/process.c
arch/arm64/mm/init.c
arch/hexagon/include/asm/pgtable.h
arch/hexagon/kernel/setup.c
arch/hexagon/mm/init.c
arch/microblaze/include/asm/cacheflush.h
arch/mips/Kconfig
arch/mips/alchemy/board-gpr.c
arch/mips/kernel/asm-offsets.c
arch/mips/kernel/octeon_switch.S
arch/mips/kernel/process.c
arch/mips/kernel/r2300_switch.S
arch/mips/kernel/r4k_switch.S
arch/mips/kernel/setup.c
arch/parisc/Kconfig
arch/powerpc/include/asm/asm-prototypes.h
arch/powerpc/include/asm/kvm_book3s.h
arch/powerpc/include/asm/kvm_book3s_64.h
arch/powerpc/include/asm/kvm_booke.h
arch/powerpc/include/asm/kvm_host.h
arch/powerpc/include/asm/kvm_ppc.h
arch/powerpc/include/asm/reg.h
arch/powerpc/include/uapi/asm/kvm.h
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kvm/Makefile
arch/powerpc/kvm/book3s.c
arch/powerpc/kvm/book3s.h
arch/powerpc/kvm/book3s_32_mmu.c
arch/powerpc/kvm/book3s_64_mmu.c
arch/powerpc/kvm/book3s_64_mmu_hv.c
arch/powerpc/kvm/book3s_64_mmu_radix.c
arch/powerpc/kvm/book3s_64_vio.c
arch/powerpc/kvm/book3s_64_vio_hv.c
arch/powerpc/kvm/book3s_emulate.c
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_hv_builtin.c
arch/powerpc/kvm/book3s_hv_interrupts.S
arch/powerpc/kvm/book3s_hv_rm_mmu.c
arch/powerpc/kvm/book3s_hv_rm_xics.c
arch/powerpc/kvm/book3s_hv_rmhandlers.S
arch/powerpc/kvm/book3s_hv_tm.c
arch/powerpc/kvm/book3s_hv_tm_builtin.c
arch/powerpc/kvm/book3s_pr.c
arch/powerpc/kvm/book3s_segment.S
arch/powerpc/kvm/book3s_xive_template.c
arch/powerpc/kvm/booke.c
arch/powerpc/kvm/booke_emulate.c
arch/powerpc/kvm/e500_emulate.c
arch/powerpc/kvm/e500_mmu.c
arch/powerpc/kvm/e500_mmu_host.c
arch/powerpc/kvm/emulate_loadstore.c
arch/powerpc/kvm/powerpc.c
arch/powerpc/kvm/tm.S [new file with mode: 0644]
arch/powerpc/mm/mem.c
arch/riscv/Kconfig
arch/riscv/Makefile
arch/riscv/configs/defconfig
arch/riscv/include/asm/Kbuild
arch/riscv/include/asm/cacheflush.h
arch/riscv/include/asm/perf_event.h [new file with mode: 0644]
arch/riscv/include/asm/tlbflush.h
arch/riscv/include/asm/uaccess.h
arch/riscv/kernel/Makefile
arch/riscv/kernel/mcount.S
arch/riscv/kernel/module.c
arch/riscv/kernel/perf_event.c [new file with mode: 0644]
arch/riscv/kernel/riscv_ksyms.c
arch/riscv/kernel/traps.c
arch/riscv/lib/uaccess.S
arch/s390/include/asm/css_chars.h
arch/sh/Kconfig
arch/sh/boards/board-sh7785lcr.c
arch/sh/kernel/process.c
arch/sh/kernel/process_32.c
arch/sparc/Kconfig
arch/sparc/mm/init_64.c
arch/um/Kconfig.um
arch/um/drivers/vector_kern.c
arch/um/include/asm/common.lds.S
arch/um/include/shared/init.h
arch/um/os-Linux/main.c
arch/unicore32/include/asm/cacheflush.h
arch/x86/Kconfig
arch/x86/entry/entry_32.S
arch/x86/entry/entry_64.S
arch/x86/entry/vsyscall/vsyscall_64.c
arch/x86/include/asm/processor.h
arch/x86/include/asm/segment.h
arch/x86/include/asm/stackprotector.h
arch/x86/kernel/asm-offsets.c
arch/x86/kernel/asm-offsets_32.c
arch/x86/kernel/asm-offsets_64.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/head_32.S
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/mm/init.c
arch/x86/mm/init_32.c
arch/x86/mm/init_64.c
arch/xtensa/Kconfig
arch/xtensa/include/asm/cacheflush.h
arch/xtensa/kernel/asm-offsets.c
arch/xtensa/kernel/entry.S
arch/xtensa/kernel/process.c
block/Kconfig
block/blk-mq-tag.c
block/blk-mq.c
block/blk-tag.c
block/bsg.c
certs/Kconfig
crypto/asymmetric_keys/asymmetric_type.c
crypto/asymmetric_keys/signature.c
drivers/acpi/acpi_lpss.c
drivers/block/rbd.c
drivers/char/Kconfig
drivers/clk/clk.c
drivers/clk/ingenic/cgu.h
drivers/dma/dmaengine.c
drivers/firmware/dmi-id.c
drivers/firmware/dmi_scan.c
drivers/firmware/efi/arm-init.c
drivers/firmware/efi/efi-pstore.c
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
drivers/gpu/drm/amd/amdgpu/df_v3_6.c
drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
drivers/gpu/drm/amd/amdgpu/soc15.c
drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c
drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c
drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c
drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c
drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c
drivers/gpu/drm/amd/display/include/fixed31_32.h
drivers/gpu/drm/amd/include/asic_reg/df/df_3_6_sh_mask.h
drivers/gpu/drm/amd/include/atomfirmware.h
drivers/gpu/drm/amd/powerplay/amd_powerplay.c
drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.c
drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.c
drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c
drivers/gpu/drm/amd/powerplay/hwmgr/processpptables.c
drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c
drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c
drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c
drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c
drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.c
drivers/gpu/drm/scheduler/gpu_scheduler.c
drivers/gpu/drm/shmobile/Kconfig
drivers/gpu/drm/shmobile/shmob_drm_crtc.c
drivers/gpu/drm/shmobile/shmob_drm_crtc.h
drivers/gpu/drm/shmobile/shmob_drm_drv.h
drivers/gpu/drm/shmobile/shmob_drm_kms.c
drivers/gpu/drm/shmobile/shmob_drm_kms.h
drivers/gpu/drm/shmobile/shmob_drm_plane.c
drivers/gpu/vga/Kconfig
drivers/gpu/vga/vgaarb.c
drivers/hid/usbhid/Kconfig
drivers/i2c/algos/i2c-algo-bit.c
drivers/i2c/algos/i2c-algo-pca.c
drivers/i2c/algos/i2c-algo-pcf.c
drivers/i2c/busses/Kconfig
drivers/i2c/busses/Makefile
drivers/i2c/busses/i2c-aspeed.c
drivers/i2c/busses/i2c-at91.c
drivers/i2c/busses/i2c-axxia.c
drivers/i2c/busses/i2c-designware-common.c
drivers/i2c/busses/i2c-designware-core.h
drivers/i2c/busses/i2c-designware-master.c
drivers/i2c/busses/i2c-designware-slave.c
drivers/i2c/busses/i2c-diolan-u2c.c
drivers/i2c/busses/i2c-efm32.c
drivers/i2c/busses/i2c-eg20t.c
drivers/i2c/busses/i2c-emev2.c
drivers/i2c/busses/i2c-exynos5.c
drivers/i2c/busses/i2c-gpio.c
drivers/i2c/busses/i2c-hix5hd2.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-ibm_iic.c
drivers/i2c/busses/i2c-imx-lpi2c.c
drivers/i2c/busses/i2c-imx.c
drivers/i2c/busses/i2c-kempld.c
drivers/i2c/busses/i2c-mlxcpld.c
drivers/i2c/busses/i2c-mt65xx.c
drivers/i2c/busses/i2c-mxs.c
drivers/i2c/busses/i2c-nomadik.c
drivers/i2c/busses/i2c-ocores.c
drivers/i2c/busses/i2c-omap.c
drivers/i2c/busses/i2c-opal.c
drivers/i2c/busses/i2c-pasemi.c
drivers/i2c/busses/i2c-pca-platform.c
drivers/i2c/busses/i2c-pnx.c
drivers/i2c/busses/i2c-qup.c
drivers/i2c/busses/i2c-rcar.c
drivers/i2c/busses/i2c-riic.c
drivers/i2c/busses/i2c-rk3x.c
drivers/i2c/busses/i2c-robotfuzz-osif.c
drivers/i2c/busses/i2c-s3c2410.c
drivers/i2c/busses/i2c-sh_mobile.c
drivers/i2c/busses/i2c-stm32.c [new file with mode: 0644]
drivers/i2c/busses/i2c-stm32.h
drivers/i2c/busses/i2c-stm32f7.c
drivers/i2c/busses/i2c-stu300.c
drivers/i2c/busses/i2c-synquacer.c
drivers/i2c/busses/i2c-tegra.c
drivers/i2c/busses/i2c-xiic.c
drivers/i2c/busses/i2c-xlp9xx.c
drivers/i2c/i2c-core-base.c
drivers/i2c/i2c-core-of.c
drivers/i2c/i2c-core-smbus.c
drivers/i2c/i2c-mux.c
drivers/i2c/muxes/i2c-demux-pinctrl.c
drivers/i2c/muxes/i2c-mux-gpio.c
drivers/i2c/muxes/i2c-mux-ltc4306.c
drivers/i2c/muxes/i2c-mux-pca954x.c
drivers/i2c/muxes/i2c-mux-reg.c
drivers/input/Kconfig
drivers/input/joystick/Kconfig
drivers/input/joystick/iforce/Kconfig
drivers/input/joystick/walkera0701.c
drivers/input/misc/Kconfig
drivers/input/misc/rotary_encoder.c
drivers/input/mouse/Kconfig
drivers/input/mouse/alps.c
drivers/input/serio/Kconfig
drivers/input/touchscreen/wm97xx-core.c
drivers/lightnvm/pblk-rb.c
drivers/md/bcache/Kconfig
drivers/md/bcache/btree.c
drivers/md/bcache/extents.c
drivers/media/dvb-core/dvb_ringbuffer.c
drivers/media/dvb-frontends/Kconfig
drivers/media/dvb-frontends/dib3000.h
drivers/media/dvb-frontends/dib3000mb.c
drivers/media/dvb-frontends/eds1547.h
drivers/media/dvb-frontends/nxt200x.c
drivers/media/dvb-frontends/or51211.c
drivers/media/dvb-frontends/sp8870.c
drivers/media/dvb-frontends/sp887x.c
drivers/media/dvb-frontends/tda1004x.c
drivers/media/dvb-frontends/tda10071.c
drivers/media/dvb-frontends/z0194a.h
drivers/media/i2c/max2175.c
drivers/media/pci/bt8xx/Kconfig
drivers/media/pci/cx18/cx18-dvb.c
drivers/media/pci/cx18/cx18-streams.c
drivers/media/pci/cx23885/cx23885-cards.c
drivers/media/pci/meye/Kconfig
drivers/media/pci/ttpci/Kconfig
drivers/media/platform/marvell-ccic/mmp-driver.c
drivers/media/platform/pxa_camera.c
drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
drivers/media/platform/via-camera.c
drivers/media/radio/Kconfig
drivers/media/radio/si470x/Kconfig
drivers/media/radio/wl128x/Kconfig
drivers/media/usb/dvb-usb-v2/Kconfig
drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
drivers/media/usb/dvb-usb-v2/gl861.c
drivers/media/usb/dvb-usb-v2/lmedm04.c
drivers/media/usb/dvb-usb-v2/lmedm04.h
drivers/media/usb/dvb-usb-v2/mxl111sf.c
drivers/media/usb/dvb-usb-v2/mxl111sf.h
drivers/media/usb/dvb-usb/Kconfig
drivers/media/usb/dvb-usb/a800.c
drivers/media/usb/dvb-usb/af9005-fe.c
drivers/media/usb/dvb-usb/af9005-remote.c
drivers/media/usb/dvb-usb/af9005.c
drivers/media/usb/dvb-usb/af9005.h
drivers/media/usb/dvb-usb/az6027.c
drivers/media/usb/dvb-usb/cxusb.c
drivers/media/usb/dvb-usb/dibusb-common.c
drivers/media/usb/dvb-usb/dibusb-mb.c
drivers/media/usb/dvb-usb/dibusb-mc-common.c
drivers/media/usb/dvb-usb/dibusb-mc.c
drivers/media/usb/dvb-usb/dibusb.h
drivers/media/usb/dvb-usb/digitv.c
drivers/media/usb/dvb-usb/dtt200u-fe.c
drivers/media/usb/dvb-usb/dtt200u.c
drivers/media/usb/dvb-usb/dtt200u.h
drivers/media/usb/dvb-usb/dvb-usb-firmware.c
drivers/media/usb/dvb-usb/dvb-usb-init.c
drivers/media/usb/dvb-usb/dw2102.c
drivers/media/usb/dvb-usb/friio-fe.c
drivers/media/usb/dvb-usb/friio.c
drivers/media/usb/dvb-usb/friio.h
drivers/media/usb/dvb-usb/gp8psk.c
drivers/media/usb/dvb-usb/gp8psk.h
drivers/media/usb/dvb-usb/m920x.c
drivers/media/usb/dvb-usb/nova-t-usb2.c
drivers/media/usb/dvb-usb/opera1.c
drivers/media/usb/dvb-usb/ttusb2.c
drivers/media/usb/dvb-usb/ttusb2.h
drivers/media/usb/dvb-usb/umt-010.c
drivers/media/usb/dvb-usb/vp702x-fe.c
drivers/media/usb/dvb-usb/vp702x.c
drivers/media/usb/dvb-usb/vp7045-fe.c
drivers/media/usb/dvb-usb/vp7045.c
drivers/media/usb/dvb-usb/vp7045.h
drivers/media/usb/gspca/m5602/Kconfig
drivers/media/usb/ttusb-dec/Kconfig
drivers/media/usb/zr364xx/Kconfig
drivers/mfd/sm501.c
drivers/mfd/timberdale.c
drivers/misc/eeprom/at24.c
drivers/net/ethernet/cavium/thunder/nic.h
drivers/net/ethernet/cavium/thunder/nicvf_main.c
drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
drivers/net/ethernet/intel/Kconfig
drivers/net/ethernet/intel/ixgbe/ixgbe.h
drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c
drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
drivers/net/ethernet/netronome/nfp/flower/main.c
drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
drivers/net/ethernet/netronome/nfp/nfp_net.h
drivers/net/ethernet/netronome/nfp/nfp_net_common.c
drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c
drivers/net/ethernet/qualcomm/emac/emac-sgmii.c
drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
drivers/net/ethernet/stmicro/stmmac/hwif.c
drivers/net/ethernet/stmicro/stmmac/stmmac.h
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/xilinx/xilinx_emaclite.c
drivers/net/hyperv/Kconfig
drivers/net/hyperv/hyperv_net.h
drivers/net/hyperv/netvsc_drv.c
drivers/net/phy/mdio-gpio.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/xen-netfront.c
drivers/nvme/host/core.c
drivers/nvme/host/fabrics.c
drivers/nvme/host/fabrics.h
drivers/nvme/host/fc.c
drivers/nvme/host/multipath.c
drivers/nvme/host/nvme.h
drivers/nvme/host/rdma.c
drivers/nvme/target/admin-cmd.c
drivers/nvme/target/loop.c
drivers/parport/Kconfig
drivers/platform/mellanox/mlxreg-hotplug.c
drivers/platform/x86/Kconfig
drivers/platform/x86/acer-wmi.c
drivers/platform/x86/apple-gmux.c
drivers/platform/x86/asus-laptop.c
drivers/platform/x86/asus-wireless.c
drivers/platform/x86/asus-wmi.c
drivers/platform/x86/dell-laptop.c
drivers/platform/x86/dell-smbios-base.c
drivers/platform/x86/dell-wmi.c
drivers/platform/x86/fujitsu-laptop.c
drivers/platform/x86/ideapad-laptop.c
drivers/platform/x86/intel_scu_ipc.c
drivers/platform/x86/mlx-platform.c
drivers/platform/x86/samsung-laptop.c
drivers/platform/x86/silead_dmi.c
drivers/platform/x86/thinkpad_acpi.c
drivers/pwm/Kconfig
drivers/pwm/pwm-atmel-tcb.c
drivers/pwm/pwm-lpss-platform.c
drivers/pwm/pwm-lpss.c
drivers/pwm/pwm-lpss.h
drivers/pwm/pwm-meson.c
drivers/pwm/pwm-rcar.c
drivers/pwm/pwm-stm32.c
drivers/remoteproc/qcom_q6v5_pil.c
drivers/s390/block/dasd.c
drivers/s390/block/dasd_alias.c
drivers/s390/block/dasd_diag.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_eer.c
drivers/s390/block/dasd_fba.c
drivers/s390/block/dasd_int.h
drivers/s390/cio/Makefile
drivers/s390/cio/vfio_ccw_cp.c
drivers/s390/cio/vfio_ccw_drv.c
drivers/s390/cio/vfio_ccw_fsm.c
drivers/s390/cio/vfio_ccw_trace.h [new file with mode: 0644]
drivers/sbus/char/oradax.c
drivers/scsi/aacraid/commctrl.c
drivers/scsi/aic7xxx/aic79xx_core.c
drivers/scsi/hpsa.c
drivers/scsi/mpt3sas/mpt3sas_base.c
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_mbx.c
drivers/scsi/sd_zbc.c
drivers/soc/qcom/mdt_loader.c
drivers/soundwire/stream.c
drivers/staging/fsl-mc/bus/dpio/dpio-driver.txt
drivers/staging/media/bcm2048/TODO
drivers/staging/media/zoran/Kconfig
drivers/tty/tty_io.c
drivers/usb/gadget/function/f_fs.c
drivers/vhost/vhost.c
drivers/video/fbdev/Kconfig
drivers/video/fbdev/Makefile
drivers/video/fbdev/aty/aty128fb.c
drivers/video/fbdev/aty/radeon_pm.c
drivers/video/fbdev/au1100fb.c
drivers/video/fbdev/au1200fb.c
drivers/video/fbdev/auo_k1900fb.c [deleted file]
drivers/video/fbdev/auo_k1901fb.c [deleted file]
drivers/video/fbdev/auo_k190x.c [deleted file]
drivers/video/fbdev/auo_k190x.h [deleted file]
drivers/video/fbdev/core/fb_defio.c
drivers/video/fbdev/mmp/fb/mmpfb.c
drivers/video/fbdev/mmp/hw/mmp_ctrl.c
drivers/video/fbdev/nvidia/nvidia.c
drivers/video/fbdev/omap/lcd_ams_delta.c
drivers/video/fbdev/omap/lcd_h3.c
drivers/video/fbdev/omap/lcd_htcherald.c
drivers/video/fbdev/omap/lcd_inn1510.c
drivers/video/fbdev/omap/lcd_inn1610.c
drivers/video/fbdev/omap/lcd_osk.c
drivers/video/fbdev/omap/lcd_palmte.c
drivers/video/fbdev/omap/lcd_palmtt.c
drivers/video/fbdev/omap/lcd_palmz71.c
drivers/video/fbdev/omap/omapfb_main.c
drivers/video/fbdev/omap2/omapfb/Kconfig
drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c
drivers/video/fbdev/pxafb.c
drivers/video/fbdev/savage/savagefb_driver.c
drivers/video/fbdev/sh_mobile_lcdcfb.c
drivers/video/fbdev/sh_mobile_lcdcfb.h
drivers/video/fbdev/sh_mobile_meram.c [deleted file]
drivers/video/fbdev/skeletonfb.c
drivers/video/fbdev/sm501fb.c
drivers/video/fbdev/via/global.h
drivers/video/fbdev/via/hw.c
drivers/video/fbdev/via/via-core.c
drivers/video/fbdev/via/via_clock.c
drivers/video/fbdev/via/viafbdev.c
drivers/virtio/virtio_pci_common.c
drivers/virtio/virtio_pci_modern.c
fs/Kconfig.binfmt
fs/adfs/inode.c
fs/afs/Makefile
fs/afs/addr_list.c
fs/afs/callback.c
fs/afs/cell.c
fs/afs/cmservice.c
fs/afs/dynroot.c
fs/afs/fsclient.c
fs/afs/internal.h
fs/afs/main.c
fs/afs/netdevices.c
fs/afs/proc.c
fs/afs/rxrpc.c
fs/afs/server.c
fs/afs/super.c
fs/aio.c
fs/attr.c
fs/bad_inode.c
fs/befs/ChangeLog
fs/binfmt_elf.c
fs/binfmt_misc.c
fs/btrfs/ctree.h
fs/btrfs/extent_io.c
fs/btrfs/file.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/root-tree.c
fs/btrfs/scrub.c
fs/btrfs/transaction.c
fs/ceph/addr.c
fs/ceph/cache.c
fs/ceph/caps.c
fs/ceph/dir.c
fs/ceph/file.c
fs/ceph/inode.c
fs/ceph/mds_client.c
fs/ceph/snap.c
fs/ceph/super.c
fs/ceph/xattr.c
fs/cifs/cache.c
fs/cifs/cifs_debug.c
fs/cifs/cifsencrypt.c
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/fscache.c
fs/cifs/inode.c
fs/cifs/misc.c
fs/cifs/smb2misc.c
fs/cifs/smb2ops.c
fs/cifs/smb2pdu.c
fs/cifs/smb2pdu.h
fs/cifs/smb2proto.h
fs/cifs/smb2transport.c
fs/cifs/smbdirect.c
fs/cifs/trace.h
fs/cifs/transport.c
fs/coda/coda_linux.c
fs/configfs/inode.c
fs/cramfs/inode.c
fs/eventfd.c
fs/eventpoll.c
fs/exofs/ore.c
fs/exofs/ore_raid.c
fs/exofs/super.c
fs/ext4/ext4.h
fs/ext4/ialloc.c
fs/ext4/namei.c
fs/f2fs/f2fs.h
fs/f2fs/file.c
fs/f2fs/inode.c
fs/f2fs/namei.c
fs/fat/inode.c
fs/fat/namei_msdos.c
fs/fat/namei_vfat.c
fs/fuse/inode.c
fs/gfs2/dir.c
fs/gfs2/glops.c
fs/hfs/inode.c
fs/hfsplus/inode.c
fs/hostfs/hostfs_kern.c
fs/inode.c
fs/jffs2/dir.c
fs/jffs2/file.c
fs/jffs2/fs.c
fs/jfs/xattr.c
fs/kernfs/dir.c
fs/kernfs/inode.c
fs/locks.c
fs/namei.c
fs/nfs/callback_proc.c
fs/nfs/fscache-index.c
fs/nfs/fscache.c
fs/nfs/inode.c
fs/nfs/nfs2xdr.c
fs/nfs/nfs3xdr.c
fs/nfs/nfs4xdr.c
fs/nfsd/blocklayout.c
fs/nfsd/nfs3xdr.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsxdr.c
fs/notify/dnotify/dnotify.c
fs/notify/fanotify/fanotify.c
fs/notify/fdinfo.c
fs/notify/fsnotify.c
fs/notify/fsnotify.h
fs/notify/group.c
fs/notify/inotify/inotify.h
fs/notify/inotify/inotify_fsnotify.c
fs/notify/inotify/inotify_user.c
fs/notify/mark.c
fs/ntfs/inode.c
fs/ocfs2/dlmglue.c
fs/ocfs2/file.c
fs/orangefs/devorangefs-req.c
fs/orangefs/inode.c
fs/orangefs/orangefs-kernel.h
fs/orangefs/orangefs-sysfs.c
fs/overlayfs/inode.c
fs/overlayfs/overlayfs.h
fs/proc/base.c
fs/proc/generic.c
fs/proc/inode.c
fs/proc/internal.h
fs/proc/proc_net.c
fs/proc/root.c
fs/proc/uptime.c
fs/pstore/platform.c
fs/pstore/ram.c
fs/reiserfs/namei.c
fs/reiserfs/xattr.c
fs/signalfd.c
fs/splice.c
fs/ubifs/dir.c
fs/ubifs/file.c
fs/ubifs/ubifs.h
fs/udf/ialloc.c
fs/udf/inode.c
fs/udf/super.c
fs/udf/udfdecl.h
fs/udf/udftime.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_iops.c
fs/xfs/xfs_trans_inode.c
include/keys/asymmetric-subtype.h
include/keys/asymmetric-type.h
include/linux/assoc_array.h
include/linux/assoc_array_priv.h
include/linux/blk-mq.h
include/linux/blkdev.h
include/linux/ceph/ceph_fs.h
include/linux/ceph/osd_client.h
include/linux/ceph/osdmap.h
include/linux/circ_buf.h
include/linux/fs.h
include/linux/fsnotify_backend.h
include/linux/ftrace.h
include/linux/i2c-gpio.h [deleted file]
include/linux/i2c-mux-gpio.h [deleted file]
include/linux/i2c-ocores.h [deleted file]
include/linux/i2c-omap.h [deleted file]
include/linux/i2c-pca-platform.h [deleted file]
include/linux/i2c-pnx.h [deleted file]
include/linux/i2c-xiic.h [deleted file]
include/linux/i2c.h
include/linux/kcov.h
include/linux/memcontrol.h
include/linux/mod_devicetable.h
include/linux/namei.h
include/linux/netfilter.h
include/linux/netfilter/ipset/ip_set_timeout.h
include/linux/platform_data/i2c-gpio.h [new file with mode: 0644]
include/linux/platform_data/i2c-mux-gpio.h [new file with mode: 0644]
include/linux/platform_data/i2c-ocores.h [new file with mode: 0644]
include/linux/platform_data/i2c-omap.h [new file with mode: 0644]
include/linux/platform_data/i2c-pca-platform.h [new file with mode: 0644]
include/linux/platform_data/i2c-xiic.h [new file with mode: 0644]
include/linux/platform_data/mlxreg.h
include/linux/platform_data/sc18is602.h
include/linux/platform_data/shmob_drm.h
include/linux/proc_fs.h
include/linux/pstore.h
include/linux/rculist_nulls.h
include/linux/sched.h
include/linux/slab.h
include/linux/stackprotector.h
include/linux/stat.h
include/linux/string_helpers.h
include/linux/tracepoint.h
include/linux/virtio_ring.h
include/net/ip_vs.h
include/net/netfilter/nf_conntrack_count.h
include/net/netfilter/nft_dup.h [deleted file]
include/net/sctp/structs.h
include/net/tls.h
include/uapi/linux/aio_abi.h
include/uapi/linux/netfilter/nf_conntrack_common.h
include/uapi/linux/netfilter/nf_tables.h
include/uapi/linux/nl80211.h
include/uapi/linux/prctl.h
include/uapi/linux/usb/audio.h
include/uapi/linux/virtio_config.h
include/video/auo_k190xfb.h [deleted file]
include/video/sh_mobile_lcdc.h
include/video/sh_mobile_meram.h [deleted file]
include/xen/interface/io/kbdif.h
ipc/sem.c
ipc/shm.c
kernel/audit_fsnotify.c
kernel/audit_tree.c
kernel/audit_watch.c
kernel/bpf/inode.c
kernel/cgroup/cpuset.c
kernel/configs/android-recommended.config
kernel/configs/tiny.config
kernel/fork.c
kernel/kcov.c
kernel/kexec_core.c
kernel/module.c
kernel/panic.c
kernel/power/main.c
kernel/relay.c
kernel/sched/core.c
kernel/trace/Kconfig
lib/Kconfig
lib/Kconfig.debug
lib/test_printf.c
mm/cleancache.c
mm/cma_debug.c
mm/compaction.c
mm/dmapool.c
mm/failslab.c
mm/frontswap.c
mm/ksm.c
mm/memblock.c
mm/memcontrol.c
mm/mremap.c
mm/oom_kill.c
mm/page_alloc.c
mm/page_idle.c
mm/page_owner.c
mm/shmem.c
mm/slab_common.c
mm/swapfile.c
mm/vmalloc.c
mm/zsmalloc.c
mm/zswap.c
net/bridge/netfilter/ebtables.c
net/bridge/netfilter/nft_reject_bridge.c
net/ceph/messenger.c
net/ceph/osd_client.c
net/ceph/osdmap.c
net/core/neighbour.c
net/core/sock.c
net/dsa/tag_trailer.c
net/ipv4/netfilter/ip_tables.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_offload.c
net/ipv6/addrconf.c
net/ipv6/ip6_fib.c
net/ipv6/netfilter/ip6_tables.c
net/ipv6/route.c
net/ipv6/tcp_ipv6.c
net/l2tp/l2tp_netlink.c
net/l2tp/l2tp_ppp.c
net/mac80211/main.c
net/netfilter/ipset/ip_set_hash_gen.h
net/netfilter/ipvs/ip_vs_ctl.c
net/netfilter/ipvs/ip_vs_xmit.c
net/netfilter/nf_conncount.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_tables_api.c
net/netfilter/nf_tables_core.c
net/netfilter/nfnetlink.c
net/netfilter/nft_chain_filter.c
net/netfilter/nft_connlimit.c
net/netfilter/nft_dynset.c
net/netfilter/nft_set_rbtree.c
net/netfilter/nft_socket.c
net/netfilter/xt_CT.c
net/netfilter/xt_connmark.c
net/netfilter/xt_set.c
net/rds/loop.c
net/rds/rds.h
net/rds/recv.c
net/sctp/output.c
net/smc/af_smc.c
net/tls/tls_main.c
net/tls/tls_sw.c
net/wireless/core.c
net/wireless/util.c
net/xdp/xdp_umem.c
scripts/documentation-file-ref-check
security/apparmor/audit.c
security/apparmor/domain.c
security/apparmor/include/audit.h
security/apparmor/include/label.h
security/apparmor/include/path.h
security/apparmor/include/secid.h
security/apparmor/label.c
security/apparmor/lib.c
security/apparmor/lsm.c
security/apparmor/match.c
security/apparmor/mount.c
security/apparmor/policy.c
security/apparmor/resource.c
security/apparmor/secid.c
security/device_cgroup.c
security/selinux/hooks.c
sound/core/Kconfig
sound/drivers/Kconfig
sound/pci/Kconfig
sound/pci/emu10k1/emupcm.c
sound/pci/fm801.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_realtek.c
sound/pci/lx6464es/lx6464es.c
sound/pci/sonicvibes.c
sound/usb/card.h
sound/usb/format.c
sound/usb/mixer.c
sound/usb/quirks-table.h
sound/usb/quirks.c
tools/include/uapi/linux/prctl.h
tools/lib/api/fs/fs.c
tools/perf/util/bpf-prologue.c
tools/power/pm-graph/config/custom-timeline-functions.cfg
tools/testing/selftests/bpf/Makefile
tools/testing/selftests/cgroup/cgroup_util.c
tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc
tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_syntax.tc
tools/testing/selftests/tc-testing/tc-tests/actions/ife.json

index 32513dc2eec9bdbf36ebc5117ece8f3577621e94..40d41ea1a3f52f515ac228c1cffa848deb6ede74 100644 (file)
@@ -11,7 +11,7 @@ Description:
   Kernel code may export it for complete or partial access.
 
   GPIOs are identified as they are inside the kernel, using integers in
-  the range 0..INT_MAX.  See Documentation/gpio/gpio.txt for more information.
+  the range 0..INT_MAX.  See Documentation/gpio for more information.
 
     /sys/class/gpio
        /export ... asks the kernel to export a GPIO to userspace
index bd4975e132d3438984d2f838daa814b1397fae5f..9c5e7732d2499995b402ff2b4a725d621d1834f8 100644 (file)
@@ -238,9 +238,6 @@ Description:        Discover and change clock speed of CPUs
 
                See files in Documentation/cpu-freq/ for more information.
 
-               In particular, read Documentation/cpu-freq/user-guide.txt
-               to learn how to control the knobs.
-
 
 What:          /sys/devices/system/cpu/cpu#/cpufreq/freqdomain_cpus
 Date:          June 2013
index 597a2f3d1efceb7383c85dda040f4b1def8adddf..1b31be3f996a40df66299e4715ee4eb984ec12e1 100644 (file)
@@ -25,3 +25,16 @@ Description:
                Control touchpad mode.
                        * 1 -> Switched On
                        * 0 -> Switched Off
+
+What:          /sys/bus/pci/devices/<bdf>/<device>/VPC2004:00/fn_lock
+Date:          May 2018
+KernelVersion: 4.18
+Contact:       "Oleg Keri <ezhi99@gmail.com>"
+Description:
+               Control fn-lock mode.
+                       * 1 -> Switched On
+                       * 0 -> Switched Off
+
+               For example:
+               # echo "0" >    \
+               /sys/bus/pci/devices/0000:00:1f.0/PNP0C09:00/VPC2004:00/fn_lock
index 3e9734bd0e0586bb737e65c45bd2e6d6fbf0e383..6cf81bbd7ce8b86bfcc740abe4e0bde49e239700 100644 (file)
@@ -44,8 +44,8 @@ Links
 
 Mailing List - apparmor@lists.ubuntu.com
 
-Wiki - http://apparmor.wiki.kernel.org/
+Wiki - http://wiki.apparmor.net
 
-User space tools - https://launchpad.net/apparmor
+User space tools - https://gitlab.com/apparmor
 
-Kernel module - git://git.kernel.org/pub/scm/linux/kernel/git/jj/apparmor-dev.git
+Kernel module - git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor
index 638342d0a0957741608c7f810c01aa9e810aea0f..efc7aa7a067099f6bacdb860cde13f2d876030a8 100644 (file)
                                (may crash computer or cause data corruption)
 
        ALSA            [HW,ALSA]
-                       See Documentation/sound/alsa/alsa-parameters.txt
+                       See Documentation/sound/alsa-configuration.rst
 
        alignment=      [KNL,ARM]
                        Allow the default userspace alignment fault handler
                        This will also cause panics on machine check exceptions.
                        Useful together with panic=30 to trigger a reboot.
 
-       OSS             [HW,OSS]
-                       See Documentation/sound/oss/oss-parameters.txt
-
        page_owner=     [KNL] Boot-time page_owner enabling option.
                        Storage of the information about who allocated
                        each page is disabled in default. With this switch,
                        [FTRACE] Set and start specified trace events in order
                        to facilitate early boot debugging. The event-list is a
                        comma separated list of trace events to enable. See
-                       also Documentation/trace/events.txt
+                       also Documentation/trace/events.rst
 
        trace_options=[option-list]
                        [FTRACE] Enable or disable tracer options at boot.
 
                              trace_options=stacktrace
 
-                       See also Documentation/trace/ftrace.txt "trace options"
+                       See also Documentation/trace/ftrace.rst "trace options"
                        section.
 
        tp_printk[FTRACE]
index 86927029a52db81ed81547fac93b09a6ffdd08da..207eca58efaaa2c652d63412b115acd0ec36a32f 100644 (file)
@@ -752,18 +752,6 @@ completion of the request to the block layer. This means ending tag
 operations before calling end_that_request_last()! For an example of a user
 of these helpers, see the IDE tagged command queueing support.
 
-Certain hardware conditions may dictate a need to invalidate the block tag
-queue. For instance, on IDE any tagged request error needs to clear both
-the hardware and software block queue and enable the driver to sanely restart
-all the outstanding requests. There's a third helper to do that:
-
-       blk_queue_invalidate_tags(struct request_queue *q)
-
-       Clear the internal block tag queue and re-add all the pending requests
-       to the request queue. The driver will receive them again on the
-       next request_fn run, just like it did the first time it encountered
-       them.
-
 3.2.5.2 Tag info
 
 Some block functions exist to query current tag status or to go from a
@@ -805,8 +793,7 @@ Internally, block manages tags in the blk_queue_tag structure:
 Most of the above is simple and straight forward, however busy_list may need
 a bit of explaining. Normally we don't care too much about request ordering,
 but in the event of any barrier requests in the tag queue we need to ensure
-that requests are restarted in the order they were queue. This may happen
-if the driver needs to use blk_queue_invalidate_tags().
+that requests are restarted in the order they were queue.
 
 3.3 I/O Submission
 
index 8e44aea366c262068900cddaabd240d8615ac552..76fe2d0f5e7d7db307bfa4ead890ead2d8840bdd 100644 (file)
@@ -284,7 +284,7 @@ Resources Management
 MTRR Handling
 -------------
 
-.. kernel-doc:: arch/x86/kernel/cpu/mtrr/main.c
+.. kernel-doc:: arch/x86/kernel/cpu/mtrr/mtrr.c
    :export:
 
 Security Framework
index 8272ac92a14fcd5a55f6607c1586ba04a7629c17..1d56221dfe355ad82ef5e391e2851d612206316c 100644 (file)
@@ -8,11 +8,13 @@ The crypto engine API (CE), is a crypto queue manager.
 
 Requirement
 -----------
-You have to put at start of your tfm_ctx the struct crypto_engine_ctx
-struct your_tfm_ctx {
+You have to put at start of your tfm_ctx the struct crypto_engine_ctx::
+
+  struct your_tfm_ctx {
         struct crypto_engine_ctx enginectx;
         ...
-};
+  };
+
 Why: Since CE manage only crypto_async_request, it cannot know the underlying
 request_type and so have access only on the TFM.
 So using container_of for accessing __ctx is impossible.
index 7364953d0d0bd8c22699366a50981bef3adb5386..45ac19bfa0a9ff4d73cb6cffcd16560dd0fe6b0c 100644 (file)
@@ -31,10 +31,10 @@ This binding uses the common clock binding[1].
 Each subnode should use the binding described in [2]..[7]
 
 [1] Documentation/devicetree/bindings/clock/clock-bindings.txt
-[3] Documentation/devicetree/bindings/clock/st,clkgen-mux.txt
-[4] Documentation/devicetree/bindings/clock/st,clkgen-pll.txt
-[7] Documentation/devicetree/bindings/clock/st,quadfs.txt
-[8] Documentation/devicetree/bindings/clock/st,flexgen.txt
+[3] Documentation/devicetree/bindings/clock/st/st,clkgen-mux.txt
+[4] Documentation/devicetree/bindings/clock/st/st,clkgen-pll.txt
+[7] Documentation/devicetree/bindings/clock/st/st,quadfs.txt
+[8] Documentation/devicetree/bindings/clock/st/st,flexgen.txt
 
 
 Required properties:
index 03f8fdee62a7e3e2c559789eb501f9f12d6542a5..56d603c1f71685678a6cf9d8a52da537cff721bd 100644 (file)
@@ -10,7 +10,7 @@ will be controlled instead and the corresponding hw-ops for
 that is used.
 
 [1] Documentation/devicetree/bindings/clock/clock-bindings.txt
-[2] Documentation/devicetree/bindings/clock/gate-clock.txt
+[2] Documentation/devicetree/bindings/clock/gpio-gate-clock.txt
 [3] Documentation/devicetree/bindings/clock/ti/clockdomain.txt
 
 Required properties:
index 3111a409fea6cebb739a01592874d2c88d56328b..3f4704040140d1dd350148da2dff43cff63f9120 100644 (file)
@@ -9,7 +9,7 @@ companion clock finding (match corresponding functional gate
 clock) and hardware autoidle enable / disable.
 
 [1] Documentation/devicetree/bindings/clock/clock-bindings.txt
-[2] Documentation/devicetree/bindings/clock/gate-clock.txt
+[2] Documentation/devicetree/bindings/clock/gpio-gate-clock.txt
 
 Required properties:
 - compatible : shall be one of:
index d36f07e0a2bb43af831d64c6b671f18a6e7a82ef..0551c78619de807b99908d76eaf76cd6831ee3a5 100644 (file)
@@ -8,7 +8,7 @@ Required properties:
        "intermediate"  - A parent of "cpu" clock which is used as "intermediate" clock
                          source (usually MAINPLL) when the original CPU PLL is under
                          transition and not stable yet.
-       Please refer to Documentation/devicetree/bindings/clk/clock-bindings.txt for
+       Please refer to Documentation/devicetree/bindings/clock/clock-bindings.txt for
        generic clock consumer properties.
 - operating-points-v2: Please refer to Documentation/devicetree/bindings/opp/opp.txt
        for detail.
index d6d2833482c9b09ba1f7c664ea4952b8f2b63464..fc2bcbe26b1e5fae443fdaa96a016a48655e8870 100644 (file)
@@ -12,7 +12,7 @@ Required properties:
 - clocks:               Phandles for clock specified in "clock-names" property
 - clock-names :                 The name of clock used by the DFI, must be
                         "pclk_ddr_mon";
-- operating-points-v2:  Refer to Documentation/devicetree/bindings/power/opp.txt
+- operating-points-v2:  Refer to Documentation/devicetree/bindings/opp/opp.txt
                         for details.
 - center-supply:        DMC supply node.
 - status:               Marks the node enabled/disabled.
index 1a4eaca40d941e60835accac50d23a6d5f43e054..f5a02f61dd36f1c68acc89f15507a144188db8c0 100644 (file)
@@ -30,7 +30,7 @@ Optional properties:
   - nxp,calib-gpios: calibration GPIO, which must correspond with the
        gpio used for the TDA998x interrupt pin.
 
-[1] Documentation/sound/alsa/soc/DAI.txt
+[1] Documentation/sound/soc/dai.rst
 [2] include/dt-bindings/display/tda998x.h
 
 Example:
index 039219df05c5f69836a39bac48bac64ce33d476a..18a2cde2e5f3a96c89067ea5cafd60fe4c71a0bc 100644 (file)
@@ -34,7 +34,7 @@ Optional properties:
 - mali-supply : Phandle to regulator for the Mali device. Refer to
   Documentation/devicetree/bindings/regulator/regulator.txt for details.
 
-- operating-points-v2 : Refer to Documentation/devicetree/bindings/power/opp.txt
+- operating-points-v2 : Refer to Documentation/devicetree/bindings/opp/opp.txt
   for details.
 
 
index c1f65d1dac1db5db178f8766e61eb8a22bf88f1f..63cd91176a688b5faf24b37dfd959dbeb1c7376d 100644 (file)
@@ -44,7 +44,7 @@ Optional properties:
 
   - memory-region:
     Memory region to allocate from, as defined in
-    Documentation/devicetree/bindi/reserved-memory/reserved-memory.txt
+    Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt
 
   - mali-supply:
     Phandle to regulator for the Mali device, as defined in
index 64e6e656c345c29c6b626100ffe74e47398959d1..b745f3706120f0605f43642af2750832832c75db 100644 (file)
@@ -24,7 +24,7 @@ Recommended properties :
 - clock-frequency : desired I2C bus clock frequency in Hz.
 - ti,has-pfunc: boolean; if defined, it indicates that SoC supports PFUNC
        registers. PFUNC registers allow to switch I2C pins to function as
-       GPIOs, so they can by toggled manually.
+       GPIOs, so they can be toggled manually.
 
 Example (enbw_cmc board):
        i2c@1c22000 {
index 4a7811ecd95447c8d1026b578f0bd557b65a07d7..7ce8fae55537046beb460436c025fb7bed2cddd2 100644 (file)
@@ -15,6 +15,7 @@ Required properties:
        "renesas,i2c-r8a7796" if the device is a part of a R8A7796 SoC.
        "renesas,i2c-r8a77965" if the device is a part of a R8A77965 SoC.
        "renesas,i2c-r8a77970" if the device is a part of a R8A77970 SoC.
+       "renesas,i2c-r8a77980" if the device is a part of a R8A77980 SoC.
        "renesas,i2c-r8a77995" if the device is a part of a R8A77995 SoC.
        "renesas,rcar-gen1-i2c" for a generic R-Car Gen1 compatible device.
        "renesas,rcar-gen2-i2c" for a generic R-Car Gen2 or RZ/G1 compatible
index 89b3250f049b6ead36b110df609a1ab340ac0fb8..66ae46d3bc2ff410b5be06a8f1fd288c306c6c4e 100644 (file)
@@ -8,9 +8,7 @@ Required properties:
       (b) "samsung, s3c2440-i2c", for i2c compatible with s3c2440 i2c.
       (c) "samsung, s3c2440-hdmiphy-i2c", for s3c2440-like i2c used
           inside HDMIPHY block found on several samsung SoCs
-      (d) "samsung, exynos5440-i2c", for s3c2440-like i2c used
-          on EXYNOS5440 which does not need GPIO configuration.
-      (e) "samsung, exynos5-sata-phy-i2c", for s3c2440-like i2c used as
+      (d) "samsung, exynos5-sata-phy-i2c", for s3c2440-like i2c used as
           a host to SATA PHY controller on an internal bus.
   - reg: physical base address of the controller and length of memory mapped
     region.
index f2c30c8b725dff3f6ba8c2b55b4f4e2e416e97a7..9afffbdf6e285bc3c57673e86b4aac3e805aa855 100644 (file)
@@ -12,7 +12,7 @@ Additional documentation for F11 can be found at:
 http://www.synaptics.com/sites/default/files/511-000136-01-Rev-E-RMI4-Interfacing-Guide.pdf
 
 Optional Touch Properties:
-Description in Documentation/devicetree/bindings/input/touch
+Description in Documentation/devicetree/bindings/input/touchscreen
 - touchscreen-inverted-x
 - touchscreen-inverted-y
 - touchscreen-swapped-x-y
index f99fe5cdeaec6b6c4d841bfa49603e84495a1b16..a644408b33b8f17d1d00be1177a259e8780a9c97 100644 (file)
@@ -28,7 +28,7 @@ Deprecated properties:
   This property is deprecated. Instead, a 'steps-per-period ' value should
   be used, such as "rotary-encoder,steps-per-period = <2>".
 
-See Documentation/input/rotary-encoder.txt for more information.
+See Documentation/input/devices/rotary-encoder.rst for more information.
 
 Example:
 
index c7888d6f640874df3607a578e68cb124d0b8cfa8..880d4d70c9fd741ac13101721ced18f04336c373 100644 (file)
@@ -28,7 +28,7 @@ See: Documentation/devicetree/bindings/clock/clock-bindings.txt
 - pinctrl-names        : a pinctrl state named tsin%d-serial or tsin%d-parallel (where %d is tsin-num)
                   must be defined for each tsin child node.
 - pinctrl-0    : phandle referencing pin configuration for this tsin configuration
-See: Documentation/devicetree/bindings/pinctrl/pinctrl-binding.txt
+See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
 
 
 Required properties (tsin (child) node):
index 0b2a6099aa20a25cdbddc537c3318b0c20116d52..5297b22107040046a2bf6ddf1213941a3ddc15f8 100644 (file)
@@ -46,7 +46,7 @@ is required:
        Following properties are require if pin control setting is required
        at boot.
        - pinctrl-names: A pinctrl state named "default" be defined, using the
-               bindings in pinctrl/pinctrl-binding.txt.
+               bindings in pinctrl/pinctrl-bindings.txt.
        - pinctrl[0...n]: Properties to contain the phandle that refer to
                different nodes of pin control settings. These nodes represents
                the pin control setting of state 0 to state n. Each of these
index d1df77f4d6554ba6d54056a76a2a03bc1adb2c3a..0ebd08af777d4d461c13e1d414627ea209d4af81 100644 (file)
@@ -12,7 +12,7 @@ MT6397/MT6323 is a multifunction device with the following sub modules:
 It is interfaced to host controller using SPI interface by a proprietary hardware
 called PMIC wrapper or pwrap. MT6397/MT6323 MFD is a child device of pwrap.
 See the following for pwarp node definitions:
-Documentation/devicetree/bindings/soc/pwrap.txt
+Documentation/devicetree/bindings/soc/mediatek/pwrap.txt
 
 This document describes the binding for MFD device and its sub module.
 
index 1db6e0057a638e09a5346956a70620c31276fdf6..0e900b52e8959cf2653c554f6f179bb2a44adab6 100644 (file)
@@ -19,6 +19,11 @@ Required parameters:
 Optional parameters:
 - resets:              Phandle to the parent reset controller.
                        See ../reset/st,stm32-rcc.txt
+- dmas:                        List of phandle to dma channels that can be used for
+                       this timer instance. There may be up to 7 dma channels.
+- dma-names:           List of dma names. Must match 'dmas' property. Valid
+                       names are: "ch1", "ch2", "ch3", "ch4", "up", "trig",
+                       "com".
 
 Optional subnodes:
 - pwm:                 See ../pwm/pwm-stm32.txt
@@ -44,3 +49,18 @@ Example:
                        reg = <0>;
                };
        };
+
+Example with all dmas:
+       timer@40010000 {
+               ...
+               dmas = <&dmamux1 11 0x400 0x0>,
+                      <&dmamux1 12 0x400 0x0>,
+                      <&dmamux1 13 0x400 0x0>,
+                      <&dmamux1 14 0x400 0x0>,
+                      <&dmamux1 15 0x400 0x0>,
+                      <&dmamux1 16 0x400 0x0>,
+                      <&dmamux1 17 0x400 0x0>;
+               dma-names = "ch1", "ch2", "ch3", "ch4", "up", "trig", "com";
+               ...
+               child nodes...
+       };
index dd2c06540485bd94c8ee7197d5e052f4dbef4de1..daa091c2e67ba06063e778ce0ca0c012c808a590 100644 (file)
@@ -8,8 +8,8 @@ Required properties:
  - reg: The PRCM registers range
 
 The prcm node may contain several subdevices definitions:
- - see Documentation/devicetree/clk/sunxi.txt for clock devices
- - see Documentation/devicetree/reset/allwinner,sunxi-clock-reset.txt for reset
+ - see Documentation/devicetree/bindings/clock/sunxi.txt for clock devices
+ - see Documentation/devicetree/bindings/reset/allwinner,sunxi-clock-reset.txt for reset
    controller devices
 
 
index a58c173b7ab9882091fe26e378ce655610f17455..0419a63f73a01457a88e79bb9b61ff4b606fd011 100644 (file)
@@ -62,7 +62,7 @@ Required properties for a slot (Deprecated - Recommend to use one slot per host)
   rest of the gpios (depending on the bus-width property) are the data lines in
   no particular order. The format of the gpio specifier depends on the gpio
   controller.
-(Deprecated - Refer to Documentation/devicetree/binding/pinctrl/samsung-pinctrl.txt)
+(Deprecated - Refer to Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt)
 
 Example:
 
index 3149297b3933293c35647ef8ae215684f2d1fc5c..f064528effed31f30d1d1c6e0b49c02e215d99af 100644 (file)
@@ -12,7 +12,7 @@ Required properties:
           See: Documentation/devicetree/bindings/clock/clock-bindings.txt
 - pinctrl-names: A pinctrl state names "default" must be defined.
 - pinctrl-0: Phandle referencing pin configuration of the SDHCI controller.
-             See: Documentation/devicetree/bindings/pinctrl/pinctrl-binding.txt
+             See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
 
 Example:
 
index 6b3d40ca395eb47c59696766f45cf22a6fc8de77..ccf82b4ee838e0c86f5bfef9b1f14b19d3323fc4 100644 (file)
@@ -20,7 +20,7 @@ Required properties:
 
 - pinctrl-names:       A pinctrl state names "default" must be defined.
 - pinctrl-0:           Phandle referencing pin configuration of the sd/emmc controller.
-                       See: Documentation/devicetree/bindings/pinctrl/pinctrl-binding.txt
+                       See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
 
 - reg:                 This must provide the host controller base address and it can also
                        contain the FlashSS Top register for TX/RX delay used by the driver
index fd23904ac68e929adcc6657b6cde29ea4206fd7e..a700943218cac9892a58df1c51b603e5003d029f 100644 (file)
@@ -6,7 +6,7 @@ Required properties:
 - compatible: For external switch chips, compatible string must be exactly one
   of: "microchip,ksz9477"
 
-See Documentation/devicetree/bindings/dsa/dsa.txt for a list of additional
+See Documentation/devicetree/bindings/net/dsa/dsa.txt for a list of additional
 required and optional properties.
 
 Examples:
index a9bc27b93ee326fe2ac665ffc143b0e3e345c0a0..aa3527f71fdc7ee9377b95fba69adad5d2264955 100644 (file)
@@ -31,7 +31,7 @@ Required properties for the child nodes within ports container:
 - phy-mode: String, must be either "trgmii" or "rgmii" for port labeled
         "cpu".
 
-See Documentation/devicetree/bindings/dsa/dsa.txt for a list of additional
+See Documentation/devicetree/bindings/net/dsa/dsa.txt for a list of additional
 required, optional properties and how the integrated switch subnodes must
 be specified.
 
index d5e22fc67d66a5ba1a51d6d0c01ab098f5356e03..0df79d9e07ec22f50ef7c6641afea3ba6c311aa0 100644 (file)
@@ -18,7 +18,7 @@ Optional properties:
 Data cells:
 
 Data cells are child nodes of eerpom node, bindings for which are
-documented in Documentation/bindings/nvmem/nvmem.txt
+documented in Documentation/devicetree/bindings/nvmem/nvmem.txt
 
 Example:
 
index 7bf9df047a1ee4992ee7f8b9f8e3f742b26bc8a0..0dcb87d6554fdaa2f8c36dc37ab6ea545f80bc86 100644 (file)
@@ -3,7 +3,7 @@ HiSilicon Hip05 and Hip06 PCIe host bridge DT description
 HiSilicon PCIe host controller is based on the Synopsys DesignWare PCI core.
 It shares common functions with the PCIe DesignWare core driver and inherits
 common properties defined in
-Documentation/devicetree/bindings/pci/designware-pci.txt.
+Documentation/devicetree/bindings/pci/designware-pcie.txt.
 
 Additional properties are described here:
 
index 6e217c63123db6c1021dba04d09ec419be05fd67..6bbe43818ad5d23d1e726cbc408ef08a86ea46fb 100644 (file)
@@ -3,7 +3,7 @@ HiSilicon Kirin SoCs PCIe host DT description
 Kirin PCIe host controller is based on the Synopsys DesignWare PCI core.
 It shares common functions with the PCIe DesignWare core driver and
 inherits common properties defined in
-Documentation/devicetree/bindings/pci/designware-pci.txt.
+Documentation/devicetree/bindings/pci/designware-pcie.txt.
 
 Additional properties are described here:
 
index 7e05487544edffae025e1071406fe711cf220773..3d4a209b0fd057e173fa24c7e20bc75c234445d5 100644 (file)
@@ -3,9 +3,9 @@ TI Keystone PCIe interface
 Keystone PCI host Controller is based on the Synopsys DesignWare PCI
 hardware version 3.65.  It shares common functions with the PCIe DesignWare
 core driver and inherits common properties defined in
-Documentation/devicetree/bindings/pci/designware-pci.txt
+Documentation/devicetree/bindings/pci/designware-pcie.txt
 
-Please refer to Documentation/devicetree/bindings/pci/designware-pci.txt
+Please refer to Documentation/devicetree/bindings/pci/designware-pcie.txt
 for the details of DesignWare DT bindings.  Additional properties are
 described here as well as properties that are not applicable.
 
index ad4fce3552bbec734726f08a694294512a3f7038..511fc234558bf1743c76c2f2d03c4c40b2a22bfd 100644 (file)
@@ -11,9 +11,9 @@ Optional Pinmux properties:
 --------------------------
 Following properties are required if default setting of pins are required
 at boot.
-- pinctrl-names: A pinctrl state named per <pinctrl-binding.txt>.
+- pinctrl-names: A pinctrl state named per <pinctrl-bindings.txt>.
 - pinctrl[0...n]: Properties to contain the phandle for pinctrl states per
-               <pinctrl-binding.txt>.
+               <pinctrl-bindings.txt>.
 
 The pin configurations are defined as child of the pinctrl states node. Each
 sub-node have following properties:
index a677145ae6d1f6f69a765f785ccaeaf25f49912b..625a22e2f2115050477e59c076203be38346ae91 100644 (file)
@@ -101,9 +101,9 @@ Optional Pinmux properties:
 --------------------------
 Following properties are required if default setting of pins are required
 at boot.
-- pinctrl-names: A pinctrl state named per <pinctrl-binding.txt>.
+- pinctrl-names: A pinctrl state named per <pinctrl-bindings.txt>.
 - pinctrl[0...n]: Properties to contain the phandle for pinctrl states per
-               <pinctrl-binding.txt>.
+               <pinctrl-bindings.txt>.
 
 The pin configurations are defined as child of the pinctrl states node. Each
 sub-node have following properties:
index eee3dc26093437e22b2271dda50c627eafcfe39f..cbcbd31e3ce850bf9d3cd501027350991bfefaf4 100644 (file)
@@ -10,9 +10,9 @@ Optional Pinmux properties:
 --------------------------
 Following properties are required if default setting of pins are required
 at boot.
-- pinctrl-names: A pinctrl state named per <pinctrl-binding.txt>.
+- pinctrl-names: A pinctrl state named per <pinctrl-bindings.txt>.
 - pinctrl[0...n]: Properties to contain the phandle for pinctrl states per
-               <pinctrl-binding.txt>.
+               <pinctrl-bindings.txt>.
 
 The pin configurations are defined as child of the pinctrl states node. Each
 sub-node have following properties:
index b31d6bbeee1644e7a553cb69fab1da5e9a225ec6..726ec2875223d8038b2a8fa7300d7ccfd8db2884 100644 (file)
@@ -14,7 +14,7 @@ Required properties:
   datasheet
 - interrupts: Should contain one interrupt specifier for the GPC interrupt
 - clocks: Must contain an entry for each entry in clock-names.
-  See Documentation/devicetree/bindings/clocks/clock-bindings.txt for details.
+  See Documentation/devicetree/bindings/clock/clock-bindings.txt for details.
 - clock-names: Must include the following entries:
   - ipg
 
index 0ba1bcc7f33aad00408c287f8d1fd95911443c41..f181e46d8e077c333fe3e6ea71d976bee0ec61a0 100644 (file)
@@ -13,4 +13,4 @@ Required Properties:
        };
 
 For information on battery specific node, Ref:
-Documentation/devicetree/bindings/power_supply/ab8500/fg.txt
+Documentation/devicetree/bindings/power/supply/ab8500/fg.txt
index ef5328371122c58a3ecb7ed359873de4c8a6203a..56636f927203e8398a6430d61b47da4b65cfed49 100644 (file)
@@ -13,4 +13,4 @@ ab8500_chargalg {
 };
 
 For information on battery specific node, Ref:
-Documentation/devicetree/bindings/power_supply/ab8500/fg.txt
+Documentation/devicetree/bindings/power/supply/ab8500/fg.txt
index 6bdbb08ea9e0f78a82f52c7aac9a5f7dee180c9b..24ada03e07b4dda824fc479a61ce35ea18834dea 100644 (file)
@@ -22,4 +22,4 @@ Required Properties:
        };
 
 For information on battery specific node, Ref:
-Documentation/devicetree/bindings/power_supply/ab8500/fg.txt
+Documentation/devicetree/bindings/power/supply/ab8500/fg.txt
index 5d254ab13ebf384034b7e8629365a7b0070c2af3..cfd74659fbed03e00a6de0e7f0150b32fbf3713b 100644 (file)
@@ -22,7 +22,7 @@ List of legacy properties and respective binding document
 3. "has-tpo"                   Documentation/devicetree/bindings/rtc/rtc-opal.txt
 4. "linux,wakeup"              Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt
                                Documentation/devicetree/bindings/mfd/tc3589x.txt
-                               Documentation/devicetree/bindings/input/ads7846.txt
+                               Documentation/devicetree/bindings/input/touchscreen/ads7846.txt
 5. "linux,keypad-wakeup"       Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt
 6. "linux,input-wakeup"                Documentation/devicetree/bindings/input/samsung-keypad.txt
 7. "nvidia,wakeup-source"      Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt
index 7a34345d0ca368e05cd036e01c58920313cb6f70..c8dd440e97470b3f3c237545d2b7ba879caae411 100644 (file)
@@ -8,7 +8,7 @@ Required properties:
           See: Documentation/devicetree/bindings/clock/clock-bindings.txt
 - pinctrl-names: A pinctrl state names "default" must be defined.
 - pinctrl-0: Phandle referencing pin configuration of the UART peripheral.
-             See: Documentation/devicetree/bindings/pinctrl/pinctrl-binding.txt
+             See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
 
 Optional properties:
 - cts-gpios: CTS pin for UART
index 4bda52042402600cfdab48c466e84d35d2f5bea4..58c341300552578018be27280517d36a24da35e5 100644 (file)
@@ -18,7 +18,7 @@ Required properties:
     See Documentation/devicetree/bindings/dma/stm32-dma.txt.
   - dma-names: Identifier for each DMA request line. Must be "tx" and "rx".
   - pinctrl-names: should contain only value "default"
-  - pinctrl-0: see Documentation/devicetree/bindings/pinctrl/pinctrl-stm32.txt
+  - pinctrl-0: see Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt
 
 Optional properties:
   - resets: Reference to a reset controller asserting the reset controller
index f301cdf0b7e68942172253f077a93c8abb923b95..3a3fc506e43ae8ce727e03f14f0073a10008adfa 100644 (file)
@@ -37,7 +37,7 @@ SAI subnodes required properties:
        "tx": if sai sub-block is configured as playback DAI
        "rx": if sai sub-block is configured as capture DAI
   - pinctrl-names: should contain only value "default"
-  - pinctrl-0: see Documentation/devicetree/bindings/pinctrl/pinctrl-stm32.txt
+  - pinctrl-0: see Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt
 
 SAI subnodes Optional properties:
   - st,sync: specify synchronization mode.
index fe54959ec95774407471885f89e9aacc2cb59b20..1bdc4709e4743c5599d790e09ff68295c05f9fa0 100644 (file)
@@ -9,7 +9,7 @@ Required properties:
 - clocks       : Must contain an entry for each name in clock-names
                    See ../clk/*
 - pinctrl-names        : Uses "default", can use "sleep" if provided
-                   See ../pinctrl/pinctrl-binding.txt
+                   See ../pinctrl/pinctrl-bindings.txt
 
 Optional properties:
 - cs-gpios     : List of GPIO chip selects
index 50a31536e975ef915defb7fd35db914f3b0d6cf6..252a05c5d976d56b039bcf04069ec9c6e9595dea 100644 (file)
@@ -16,7 +16,7 @@ A child node must exist to represent the core DWC3 IP block. The name of
 the node is not important. The content of the node is defined in dwc3.txt.
 
 Phy documentation is provided in the following places:
-Documentation/devicetree/bindings/phy/rockchip,dwc3-usb-phy.txt
+Documentation/devicetree/bindings/phy/qcom-dwc3-usb-phy.txt
 
 Example device nodes:
 
index c71a50d85b50170dcfbb0323f24c29a0494d1648..aa03f389d41d6a794f16607ee076f248848da17a 100644 (file)
@@ -57,7 +57,7 @@ device that displays digits), an additional index argument can be specified::
                                          enum gpiod_flags flags)
 
 For a more detailed description of the con_id parameter in the DeviceTree case
-see Documentation/gpio/board.txt
+see Documentation/driver-api/gpio/board.rst
 
 The flags parameter is used to optionally specify a direction and initial value
 for the GPIO. Values can be:
index 74b89a9c8b3a312ba0fa110f646bcb9f6c03f0ce..954ac1c95553ef095040d3c862767aaf021cf7b5 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Feature name:          stackprotector
-#         Kconfig:       HAVE_CC_STACKPROTECTOR
+#         Kconfig:       HAVE_STACKPROTECTOR
 #         description:   arch supports compiler driven stack overflow protection
 #
     -----------------------
index d7f011ddc1500cdf8e705430c90ed60deb7a2ecc..8bf62240e10d35a7dc99fac14f86afeb14313490 100644 (file)
@@ -105,15 +105,13 @@ Mount Options
        address its connection to the monitor originates from.
 
   wsize=X
-       Specify the maximum write size in bytes.  By default there is no
-       maximum.  Ceph will normally size writes based on the file stripe
-       size.
+       Specify the maximum write size in bytes.  Default: 16 MB.
 
   rsize=X
-       Specify the maximum read size in bytes.  Default: 64 MB.
+       Specify the maximum read size in bytes.  Default: 16 MB.
 
   rasize=X
-       Specify the maximum readahead.  Default: 8 MB.
+       Specify the maximum readahead size in bytes.  Default: 8 MB.
 
   mount_timeout=X
        Specify the timeout value for mount (in seconds), in the case
index 9f4f87e1624036349533adf9534bfd3c4b08535d..75865da2ce1475c27bea1050b3e80ff7160f6d6f 100644 (file)
@@ -42,9 +42,11 @@ Jeff Layton (many, many fixes, as well as great work on the cifs Kerberos code)
 Scott Lovenberg
 Pavel Shilovsky (for great work adding SMB2 support, and various SMB3 features)
 Aurelien Aptel (for DFS SMB3 work and some key bug fixes)
-Ronnie Sahlberg (for SMB3 xattr work and bug fixes)
+Ronnie Sahlberg (for SMB3 xattr work, bug fixes, and lots of great work on compounding)
 Shirish Pargaonkar (for many ACL patches over the years)
 Sachin Prabhu (many bug fixes, including for reconnect, copy offload and security)
+Paulo Alcantara
+Long Li (some great work on RDMA, SMB Direct)
 
 
 Test case and Bug Report contributors
@@ -58,5 +60,4 @@ mention to the Stanford Checker (SWAT) which pointed out many minor
 bugs in error paths.  Valuable suggestions also have come from Al Viro
 and Dave Miller.
 
-And thanks to the IBM LTC and Power test teams and SuSE testers for
-finding multiple bugs during excellent stress test runs.
+And thanks to the IBM LTC and Power test teams and SuSE and Citrix and RedHat testers for finding multiple bugs during excellent stress test runs.
index bc0025cdd1c9c0d285c32e8d7656103868126ca8..455e1cc494a9f2e78ee1d45b89bfbe5ee55048eb 100644 (file)
@@ -1,3 +1,6 @@
+See https://wiki.samba.org/index.php/LinuxCIFSKernel for
+more current information.
+
 Version 1.62
 ------------
 Add sockopt=TCP_NODELAY mount option. EA (xattr) routines hardened
index c5adf149b57f7f8f6e2d0b104d5b74f6bc7f5f84..852499aed64b52bb321c0b9656b0b606a4710772 100644 (file)
@@ -9,14 +9,14 @@ is a partial list of the known problems and missing features:
 
 a) SMB3 (and SMB3.02) missing optional features:
    - multichannel (started), integration with RDMA
-   - directory leases (improved metadata caching)
-   - T10 copy offload (copy chunk, and "Duplicate Extents" ioctl
+   - directory leases (improved metadata caching), started (root dir only)
+   - T10 copy offload ie "ODX" (copy chunk, and "Duplicate Extents" ioctl
      currently the only two server side copy mechanisms supported)
 
 b) improved sparse file support
 
 c) Directory entry caching relies on a 1 second timer, rather than
-using Directory Leases
+using Directory Leases, currently only the root file handle is cached longer
 
 d) quota support (needs minor kernel change since quota calls
 to make it to network filesystems or deviceless filesystems)
@@ -42,6 +42,8 @@ mount or a per server basis to client UIDs or nobody if no mapping
 exists. Also better integration with winbind for resolving SID owners
 
 k) Add tools to take advantage of more smb3 specific ioctls and features
+(passthrough ioctl/fsctl for sending various SMB3 fsctls to the server
+is in progress)
 
 l) encrypted file support
 
@@ -71,9 +73,8 @@ t) split cifs and smb3 support into separate modules so legacy (and less
 secure) CIFS dialect can be disabled in environments that don't need it
 and simplify the code.
 
-u) Finish up SMB3.1.1 dialect support
-
-v) POSIX Extensions for SMB3.1.1
+v) POSIX Extensions for SMB3.1.1 (started, create and mkdir support added
+so far).
 
 KNOWN BUGS
 ====================================
@@ -92,8 +93,8 @@ Misc testing to do
 1) check out max path names and max path name components against various server
 types. Try nested symlinks (8 deep). Return max path name in stat -f information
 
-2) Improve xfstest's cifs enablement and adapt xfstests where needed to test
-cifs better
+2) Improve xfstest's cifs/smb3 enablement and adapt xfstests where needed to test
+cifs/smb3 better
 
 3) Additional performance testing and optimization using iozone and similar - 
 there are some easy changes that can be done to parallelize sequential writes,
index cfd31d94c8727251179a0c2afcc4f9b2a4580156..72d16f08e431c674c62738641d7c28926d6331cb 100644 (file)
@@ -53,7 +53,7 @@ bus supply voltage.
 
 The shunt value in micro-ohms can be set via platform data or device tree at
 compile-time or via the shunt_resistor attribute in sysfs at run-time. Please
-refer to the Documentation/devicetree/bindings/i2c/ina2xx.txt for bindings
+refer to the Documentation/devicetree/bindings/hwmon/ina2xx.txt for bindings
 if the device tree is used.
 
 Additionally ina226 supports update_interval attribute as described in
index 4e46c440b38d9a07046f43323cc011fcffa10838..925904aa9b57c787c750e83cdc3975cc1862e5d8 100644 (file)
@@ -20,6 +20,10 @@ The next transaction types are supported:
  - Write Byte/Block.
 
 Registers:
+CPBLTY         0x0 - capability reg.
+                       Bits [6:5] - transaction length. b01 - 72B is supported,
+                       36B in other case.
+                       Bit 7 - SMBus block read support.
 CTRL           0x1 - control reg.
                        Resets all the registers.
 HALF_CYC       0x4 - cycle reg.
index 9e1dfe7553ad8ee39b5ff69d81f4ca4b672c554a..4e713f4cdb2f9cfc23a206918937c964b0a70113 100644 (file)
@@ -18,7 +18,7 @@ Usage
 i2c-ocores uses the platform bus, so you need to provide a struct
 platform_device with the base address and interrupt number. The
 dev.platform_data of the device should also point to a struct
-ocores_i2c_platform_data (see linux/i2c-ocores.h) describing the
+ocores_i2c_platform_data (see linux/platform_data/i2c-ocores.h) describing the
 distance between registers and the input clock speed.
 There is also a possibility to attach a list of i2c_board_info which
 the i2c-ocores driver will add to the bus upon creation.
index 7a8d7d261632e6d68a738bbb6395c6054eed44b8..893ecdfe6e43c3e297f725237f6a3fe8b93e7d61 100644 (file)
@@ -30,12 +30,12 @@ i2c-mux-gpio uses the platform bus, so you need to provide a struct
 platform_device with the platform_data pointing to a struct
 i2c_mux_gpio_platform_data with the I2C adapter number of the master
 bus, the number of bus segments to create and the GPIO pins used
-to control it. See include/linux/i2c-mux-gpio.h for details.
+to control it. See include/linux/platform_data/i2c-mux-gpio.h for details.
 
 E.G. something like this for a MUX providing 4 bus segments
 controlled through 3 GPIO pins:
 
-#include <linux/i2c-mux-gpio.h>
+#include <linux/platform_data/i2c-mux-gpio.h>
 #include <linux/platform_device.h>
 
 static const unsigned myboard_gpiomux_gpios[] = {
index a4eb01843c0413e96422d4e873fb54b0855ec142..3534a84d206caf324423a9422eb985b48c97813b 100644 (file)
@@ -480,7 +480,7 @@ There are several features that need compiler support. The recommended way
 to describe the dependency on the compiler feature is to use "depends on"
 followed by a test macro.
 
-config CC_STACKPROTECTOR
+config STACKPROTECTOR
        bool "Stack Protector buffer overflow detection"
        depends on $(cc-option,-fstack-protector)
        ...
index 22208bf2386d1dac06b04f4b8c064286885f9d55..cb3b0de83fc6db83d9a5739bdaa0eb199ae5250d 100644 (file)
@@ -724,8 +724,8 @@ migrate your tool to one of the following options:
 
   See following documents:
 
-  - Documentation/trace/kprobetrace.txt
-  - Documentation/trace/events.txt
+  - Documentation/trace/kprobetrace.rst
+  - Documentation/trace/events.rst
   - tools/perf/Documentation/perf-probe.txt
 
 
index 00b6dfed573cf595594714df451621eb2f991893..6cced88de6da08134d35c4a3678a3ed119736958 100644 (file)
@@ -540,8 +540,10 @@ Events that are propagated by the driver to userspace:
 0x6021         ALARM: a sensor is too hot
 0x6022         ALARM: a sensor is extremely hot
 0x6030         System thermal table changed
+0x6032         Thermal Control command set completion  (DYTC, Windows)
 0x6040         Nvidia Optimus/AC adapter related (TO BE VERIFIED)
 0x60C0         X1 Yoga 2016, Tablet mode status changed
+0x60F0         Thermal Transformation changed (GMTS, Windows)
 
 Battery nearly empty alarms are a last resort attempt to get the
 operating system to hibernate or shutdown cleanly (0x2313), or shutdown
index a19db3458b56b7aedfc09004166a46606ab7fe51..22b271de030474c1dbbcadd7cfdef88b95a5766e 100644 (file)
@@ -41,7 +41,7 @@ named ``char-misc-next``, you would be using the following command::
 
 that will create a signed tag called ``char-misc-4.15-rc1`` based on the
 last commit in the ``char-misc-next`` branch, and sign it with your gpg key
-(see :ref:`Documentation/maintainer/configure_git.rst <configuregit>`).
+(see :ref:`Documentation/maintainer/configure-git.rst <configuregit>`).
 
 Linus will only accept pull requests based on a signed tag. Other
 maintainers may differ.
index d23c51abf8c6d3806c7209fd8e620a69cb75a608..2fd0b51a8c529da1f6e0f18cfc4da4f9bbd3b40e 100644 (file)
@@ -164,7 +164,7 @@ The Linux network devices (by default) just can handle the
 transmission and reception of media dependent frames. Due to the
 arbitration on the CAN bus the transmission of a low prio CAN-ID
 may be delayed by the reception of a high prio CAN frame. To
-reflect the correct [*]_ traffic on the node the loopback of the sent
+reflect the correct [#f1]_ traffic on the node the loopback of the sent
 data has to be performed right after a successful transmission. If
 the CAN network interface is not capable of performing the loopback for
 some reason the SocketCAN core can do this task as a fallback solution.
@@ -175,7 +175,7 @@ networking behaviour for CAN applications. Due to some requests from
 the RT-SocketCAN group the loopback optionally may be disabled for each
 separate socket. See sockopts from the CAN RAW sockets in :ref:`socketcan-raw-sockets`.
 
-.. [*] you really like to have this when you're running analyser
+.. [#f1] you really like to have this when you're running analyser
        tools like 'candump' or 'cansniffer' on the (same) node.
 
 
diff --git a/Documentation/riscv/pmu.txt b/Documentation/riscv/pmu.txt
new file mode 100644 (file)
index 0000000..b29f03a
--- /dev/null
@@ -0,0 +1,249 @@
+Supporting PMUs on RISC-V platforms
+==========================================
+Alan Kao <alankao@andestech.com>, Mar 2018
+
+Introduction
+------------
+
+As of this writing, perf_event-related features mentioned in The RISC-V ISA
+Privileged Version 1.10 are as follows:
+(please check the manual for more details)
+
+* [m|s]counteren
+* mcycle[h], cycle[h]
+* minstret[h], instret[h]
+* mhpeventx, mhpcounterx[h]
+
+With such function set only, porting perf would require a lot of work, due to
+the lack of the following general architectural performance monitoring features:
+
+* Enabling/Disabling counters
+  Counters are just free-running all the time in our case.
+* Interrupt caused by counter overflow
+  No such feature in the spec.
+* Interrupt indicator
+  It is not possible to have many interrupt ports for all counters, so an
+  interrupt indicator is required for software to tell which counter has
+  just overflowed.
+* Writing to counters
+  There will be an SBI to support this since the kernel cannot modify the
+  counters [1].  Alternatively, some vendor considers to implement
+  hardware-extension for M-S-U model machines to write counters directly.
+
+This document aims to provide developers a quick guide on supporting their
+PMUs in the kernel.  The following sections briefly explain perf' mechanism
+and todos.
+
+You may check previous discussions here [1][2].  Also, it might be helpful
+to check the appendix for related kernel structures.
+
+
+1. Initialization
+-----------------
+
+*riscv_pmu* is a global pointer of type *struct riscv_pmu*, which contains
+various methods according to perf's internal convention and PMU-specific
+parameters.  One should declare such instance to represent the PMU.  By default,
+*riscv_pmu* points to a constant structure *riscv_base_pmu*, which has very
+basic support to a baseline QEMU model.
+
+Then he/she can either assign the instance's pointer to *riscv_pmu* so that
+the minimal and already-implemented logic can be leveraged, or invent his/her
+own *riscv_init_platform_pmu* implementation.
+
+In other words, existing sources of *riscv_base_pmu* merely provide a
+reference implementation.  Developers can flexibly decide how many parts they
+can leverage, and in the most extreme case, they can customize every function
+according to their needs.
+
+
+2. Event Initialization
+-----------------------
+
+When a user launches a perf command to monitor some events, it is first
+interpreted by the userspace perf tool into multiple *perf_event_open*
+system calls, and then each of them calls to the body of *event_init*
+member function that was assigned in the previous step.  In *riscv_base_pmu*'s
+case, it is *riscv_event_init*.
+
+The main purpose of this function is to translate the event provided by user
+into bitmap, so that HW-related control registers or counters can directly be
+manipulated.  The translation is based on the mappings and methods provided in
+*riscv_pmu*.
+
+Note that some features can be done in this stage as well:
+
+(1) interrupt setting, which is stated in the next section;
+(2) privilege level setting (user space only, kernel space only, both);
+(3) destructor setting.  Normally it is sufficient to apply *riscv_destroy_event*;
+(4) tweaks for non-sampling events, which will be utilized by functions such as
+*perf_adjust_period*, usually something like the follows:
+
+if (!is_sampling_event(event)) {
+        hwc->sample_period = x86_pmu.max_period;
+        hwc->last_period = hwc->sample_period;
+        local64_set(&hwc->period_left, hwc->sample_period);
+}
+
+In the case of *riscv_base_pmu*, only (3) is provided for now.
+
+
+3. Interrupt
+------------
+
+3.1. Interrupt Initialization
+
+This often occurs at the beginning of the *event_init* method. In common
+practice, this should be a code segment like
+
+int x86_reserve_hardware(void)
+{
+        int err = 0;
+
+        if (!atomic_inc_not_zero(&pmc_refcount)) {
+                mutex_lock(&pmc_reserve_mutex);
+                if (atomic_read(&pmc_refcount) == 0) {
+                        if (!reserve_pmc_hardware())
+                                err = -EBUSY;
+                        else
+                                reserve_ds_buffers();
+                }
+                if (!err)
+                        atomic_inc(&pmc_refcount);
+                mutex_unlock(&pmc_reserve_mutex);
+        }
+
+        return err;
+}
+
+And the magic is in *reserve_pmc_hardware*, which usually does atomic
+operations to make implemented IRQ accessible from some global function pointer.
+*release_pmc_hardware* serves the opposite purpose, and it is used in event
+destructors mentioned in previous section.
+
+(Note: From the implementations in all the architectures, the *reserve/release*
+pair are always IRQ settings, so the *pmc_hardware* seems somehow misleading.
+It does NOT deal with the binding between an event and a physical counter,
+which will be introduced in the next section.)
+
+3.2. IRQ Structure
+
+Basically, a IRQ runs the following pseudo code:
+
+for each hardware counter that triggered this overflow
+
+    get the event of this counter
+
+    // following two steps are defined as *read()*,
+    // check the section Reading/Writing Counters for details.
+    count the delta value since previous interrupt
+    update the event->count (# event occurs) by adding delta, and
+               event->hw.period_left by subtracting delta
+
+    if the event overflows
+        sample data
+        set the counter appropriately for the next overflow
+
+        if the event overflows again
+            too frequently, throttle this event
+        fi
+    fi
+
+end for
+
+However as of this writing, none of the RISC-V implementations have designed an
+interrupt for perf, so the details are to be completed in the future.
+
+4. Reading/Writing Counters
+---------------------------
+
+They seem symmetric but perf treats them quite differently.  For reading, there
+is a *read* interface in *struct pmu*, but it serves more than just reading.
+According to the context, the *read* function not only reads the content of the
+counter (event->count), but also updates the left period to the next interrupt
+(event->hw.period_left).
+
+But the core of perf does not need direct write to counters.  Writing counters
+is hidden behind the abstraction of 1) *pmu->start*, literally start counting so one
+has to set the counter to a good value for the next interrupt; 2) inside the IRQ
+it should set the counter to the same resonable value.
+
+Reading is not a problem in RISC-V but writing would need some effort, since
+counters are not allowed to be written by S-mode.
+
+
+5. add()/del()/start()/stop()
+-----------------------------
+
+Basic idea: add()/del() adds/deletes events to/from a PMU, and start()/stop()
+starts/stop the counter of some event in the PMU.  All of them take the same
+arguments: *struct perf_event *event* and *int flag*.
+
+Consider perf as a state machine, then you will find that these functions serve
+as the state transition process between those states.
+Three states (event->hw.state) are defined:
+
+* PERF_HES_STOPPED:    the counter is stopped
+* PERF_HES_UPTODATE:   the event->count is up-to-date
+* PERF_HES_ARCH:       arch-dependent usage ... we don't need this for now
+
+A normal flow of these state transitions are as follows:
+
+* A user launches a perf event, resulting in calling to *event_init*.
+* When being context-switched in, *add* is called by the perf core, with a flag
+  PERF_EF_START, which means that the event should be started after it is added.
+  At this stage, a general event is bound to a physical counter, if any.
+  The state changes to PERF_HES_STOPPED and PERF_HES_UPTODATE, because it is now
+  stopped, and the (software) event count does not need updating.
+** *start* is then called, and the counter is enabled.
+   With flag PERF_EF_RELOAD, it writes an appropriate value to the counter (check
+   previous section for detail).
+   Nothing is written if the flag does not contain PERF_EF_RELOAD.
+   The state now is reset to none, because it is neither stopped nor updated
+   (the counting already started)
+* When being context-switched out, *del* is called.  It then checks out all the
+  events in the PMU and calls *stop* to update their counts.
+** *stop* is called by *del*
+   and the perf core with flag PERF_EF_UPDATE, and it often shares the same
+   subroutine as *read* with the same logic.
+   The state changes to PERF_HES_STOPPED and PERF_HES_UPTODATE, again.
+
+** Life cycle of these two pairs: *add* and *del* are called repeatedly as
+  tasks switch in-and-out; *start* and *stop* is also called when the perf core
+  needs a quick stop-and-start, for instance, when the interrupt period is being
+  adjusted.
+
+Current implementation is sufficient for now and can be easily extended to
+features in the future.
+
+A. Related Structures
+---------------------
+
+* struct pmu: include/linux/perf_event.h
+* struct riscv_pmu: arch/riscv/include/asm/perf_event.h
+
+  Both structures are designed to be read-only.
+
+  *struct pmu* defines some function pointer interfaces, and most of them take
+*struct perf_event* as a main argument, dealing with perf events according to
+perf's internal state machine (check kernel/events/core.c for details).
+
+  *struct riscv_pmu* defines PMU-specific parameters.  The naming follows the
+convention of all other architectures.
+
+* struct perf_event: include/linux/perf_event.h
+* struct hw_perf_event
+
+  The generic structure that represents perf events, and the hardware-related
+details.
+
+* struct riscv_hw_events: arch/riscv/include/asm/perf_event.h
+
+  The structure that holds the status of events, has two fixed members:
+the number of events and the array of the events.
+
+References
+----------
+
+[1] https://github.com/riscv/riscv-linux/pull/124
+[2] https://groups.google.com/a/groups.riscv.org/forum/#!topic/sw-dev/f19TmCNP6yA
index 0f53826c78b9f6449cbd3ccf620fc34712ac24c9..e1ca698e000639720e9c718ec28613177cad189e 100644 (file)
@@ -156,7 +156,7 @@ The classic stack buffer overflow involves writing past the expected end
 of a variable stored on the stack, ultimately writing a controlled value
 to the stack frame's stored return address. The most widely used defense
 is the presence of a stack canary between the stack variables and the
-return address (``CONFIG_CC_STACKPROTECTOR``), which is verified just before
+return address (``CONFIG_STACKPROTECTOR``), which is verified just before
 the function returns. Other defenses include things like shadow stacks.
 
 Stack depth overflow
index 25feb0d35e7abc7f6ff7797faf02e9e79321e644..2019a55f6b182a4a5306b204b096739bfae143bb 100755 (executable)
@@ -53,8 +53,6 @@ from docutils.utils import SystemMessagePropagation
 # common globals
 # ==============================================================================
 
-# The version numbering follows numbering of the specification
-# (Documentation/books/kernel-doc-HOWTO).
 __version__  = '1.0'
 
 PY3 = sys.version_info[0] == 3
index 1d74ad0202b6525c4ce4b257d0db1ba466226b0d..efbc832146e77f8e2f1a4a107364e40ca082569f 100644 (file)
@@ -426,5 +426,5 @@ root@genericarmv8:~#
 Details on how to use the generic STM API can be found here [2].
 
 [1]. Documentation/ABI/testing/sysfs-bus-coresight-devices-stm
-[2]. Documentation/trace/stm.txt
+[2]. Documentation/trace/stm.rst
 [3]. https://github.com/Linaro/perf-opencsd
index 1afae55dc55caceceac0a5c6c0a8b6a1abb748d4..696dc69b8158bf6c15484c44b26d3eaf5e6c3a51 100644 (file)
@@ -8,7 +8,7 @@ Event Tracing
 1. Introduction
 ===============
 
-Tracepoints (see Documentation/trace/tracepoints.txt) can be used
+Tracepoints (see Documentation/trace/tracepoints.rst) can be used
 without creating custom kernel modules to register probe functions
 using the event tracing infrastructure.
 
index 00283b6dd101dbc210055b20cf360d9a959eb480..1fbc69894eed0b552dd04dd0037e810ba499331f 100644 (file)
@@ -199,7 +199,7 @@ If @buf is NULL and reset is set, all functions will be enabled for tracing.
 The @buf can also be a glob expression to enable all functions that
 match a specific pattern.
 
-See Filter Commands in :file:`Documentation/trace/ftrace.txt`.
+See Filter Commands in :file:`Documentation/trace/ftrace.rst`.
 
 To just trace the schedule function:
 
index b13771cb12c1ba7adc3b2a8b086068de351ff98a..e73bcf9cb5f31cc756521702bbc15fd142e09c71 100644 (file)
@@ -7,7 +7,7 @@
 
   Histogram triggers are special event triggers that can be used to
   aggregate trace event data into histograms.  For information on
-  trace events and event triggers, see Documentation/trace/events.txt.
+  trace events and event triggers, see Documentation/trace/events.rst.
 
 
 2. Histogram Trigger Command
index 990f132651785b54996fdd5b835da479b78a2694..19e2d633f3c71f453fd0d2c1d9905d939a6326d6 100644 (file)
@@ -38,7 +38,7 @@ description is at Documentation/ABI/testing/sysfs-bus-intel_th-devices-gth.
 
 STH registers an stm class device, through which it provides interface
 to userspace and kernelspace software trace sources. See
-Documentation/trace/stm.txt for more information on that.
+Documentation/trace/stm.rst for more information on that.
 
 MSU can be configured to collect trace data into a system memory
 buffer, which can later on be read from its device nodes via read() or
index a4d3ff2e5efb616a9bc91fd814b4bb193961217d..716326b9f152516ad5af0c36f23444f1b6470667 100644 (file)
@@ -6,7 +6,7 @@ Notes on Analysing Behaviour Using Events and Tracepoints
 1. Introduction
 ===============
 
-Tracepoints (see Documentation/trace/tracepoints.txt) can be used without
+Tracepoints (see Documentation/trace/tracepoints.rst) can be used without
 creating custom kernel modules to register probe functions using the event
 tracing infrastructure.
 
@@ -55,7 +55,7 @@ simple case of::
 3.1 System-Wide Event Enabling
 ------------------------------
 
-See Documentation/trace/events.txt for a proper description on how events
+See Documentation/trace/events.rst for a proper description on how events
 can be enabled system-wide. A short example of enabling all events related
 to page allocation would look something like::
 
@@ -112,7 +112,7 @@ at that point.
 3.4 Local Event Enabling
 ------------------------
 
-Documentation/trace/ftrace.txt describes how to enable events on a per-thread
+Documentation/trace/ftrace.rst describes how to enable events on a per-thread
 basis using set_ftrace_pid.
 
 3.5 Local Event Enablement with PCL
@@ -137,7 +137,7 @@ basis using PCL such as follows.
 4. Event Filtering
 ==================
 
-Documentation/trace/ftrace.txt covers in-depth how to filter events in
+Documentation/trace/ftrace.rst covers in-depth how to filter events in
 ftrace.  Obviously using grep and awk of trace_pipe is an option as well
 as any script reading trace_pipe.
 
index 8d7ed0cbbf5fb76cfdaa3c228a6c5f60069732c0..f3116381c26bd86399f11cce0e8ab1b39eed760b 100644 (file)
@@ -1,5 +1,5 @@
 NOTE:
-This is a version of Documentation/HOWTO translated into Japanese.
+This is a version of Documentation/process/howto.rst translated into Japanese.
 This document is maintained by Tsugikazu Shibata <tshibata@ab.jp.nec.com>
 If you find any difference between this document and the original file or
 a problem with the translation, please contact the maintainer of this file.
@@ -109,7 +109,7 @@ linux-api@vger.kernel.org に送ることを勧めます。
     ています。 カーネルに関して初めての人はここからスタートすると良い
     でしょう。
 
-  :ref:`Documentation/Process/changes.rst <changes>`
+  :ref:`Documentation/process/changes.rst <changes>`
     このファイルはカーネルをうまく生成(訳注 build )し、走らせるのに最
     小限のレベルで必要な数々のソフトウェアパッケージの一覧を示してい
     ます。
index 624654bdcd8ad3b54362be65d60f1d9f7aa121b7..a8197e072599a9bdded162198a62810cb8b9ff2c 100644 (file)
@@ -160,7 +160,7 @@ mtk.manpages@gmail.com의 메인테이너에게 보낼 것을 권장한다.
     독특한 행동에 관하여 흔히 있는 오해들과 혼란들을 해소하고 있기
     때문이다.
 
-  :ref:`Documentation/process/stable_kernel_rules.rst <stable_kernel_rules>`
+  :ref:`Documentation/process/stable-kernel-rules.rst <stable_kernel_rules>`
     이 문서는 안정적인 커널 배포가 이루어지는 규칙을 설명하고 있으며
     여러분들이 이러한 배포들 중 하나에 변경을 하길 원한다면
     무엇을 해야 하는지를 설명한다.
index 929385e4b1941b6c063d0eb96d5a389c3fa787d3..15e73562f710c9002a154b4d6864ceb8d41b8b96 100644 (file)
@@ -107,7 +107,7 @@ Linux 2.6:
                程序测试的指导,请参阅
                Documentation/power/drivers-testing.txt。有关驱动程序电
                源管理问题相对全面的概述,请参阅
-               Documentation/power/admin-guide/devices.rst。
+               Documentation/driver-api/pm/devices.rst。
 
 管理:              如果一个驱动程序的作者还在进行有效的维护,那么通常除了那
                些明显正确且不需要任何检查的补丁以外,其他所有的补丁都会
index 4f8bf30a41dc59ea52b0a77d5816cb6b1716f105..4cb1ba8b8fed50470dd641197b54f14706cb9b8c 100644 (file)
@@ -1,4 +1,4 @@
-Chinese translated version of Documentation/gpio.txt
+Chinese translated version of Documentation/gpio
 
 If you have any comment or update to the content, please contact the
 original document maintainer directly.  However, if you have a problem
@@ -10,7 +10,7 @@ Maintainer: Grant Likely <grant.likely@secretlab.ca>
                Linus Walleij <linus.walleij@linaro.org>
 Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
 ---------------------------------------------------------------------
-Documentation/gpio.txt 的中文翻译
+Documentation/gpio 的中文翻译
 
 如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
 交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
index e592daf4e0143b4a00ee213a2d167e53eff94ca6..1f8127bdd415a64a0f6eccd03eaae126231cd8c6 100644 (file)
@@ -1,4 +1,4 @@
-Chinese translated version of Documentation/io_orderings.txt
+Chinese translated version of Documentation/io_ordering.txt
 
 If you have any comment or update to the content, please contact the
 original document maintainer directly.  However, if you have a problem
index e9db693c0a2302d2fc05d005b604e347fde1b09c..7159cec04090d8f0243090b18a53f227a942e4e1 100644 (file)
@@ -1,4 +1,4 @@
-Chinese translated version of Documentation/magic-number.txt
+Chinese translated version of Documentation/process/magic-number.rst
 
 If you have any comment or update to the content, please post to LKML directly.
 However, if you have problem communicating in English you can also ask the
@@ -7,7 +7,7 @@ translation is outdated or there is problem with translation.
 
 Chinese maintainer: Jia Wei Wei <harryxiyou@gmail.com>
 ---------------------------------------------------------------------
-Documentation/magic-number.txt的中文翻译
+Documentation/process/magic-number.rst的中文翻译
 
 如果想评论或更新本文的内容,请直接发信到LKML。如果你使用英文交流有困难的话,也可
 以向中文版维护者求助。如果本翻译更新不及时或者翻译存在问题,请联系中文版维护者。
index 67ffbf352ae0c252d67d8c262d4a416de97ce6f7..e9f29375aa952d01748954b9b3fe287f215f2f58 100644 (file)
@@ -1,4 +1,4 @@
-Chinese translated version of Documentation/video4linux/omap3isp.txt
+Chinese translated version of Documentation/media/v4l-drivers/omap3isp.rst
 
 If you have any comment or update to the content, please contact the
 original document maintainer directly.  However, if you have a problem
@@ -11,7 +11,7 @@ Maintainer: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
          David Cohen <dacohen@gmail.com>
 Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
 ---------------------------------------------------------------------
-Documentation/video4linux/omap3isp.txt 的中文翻译
+Documentation/media/v4l-drivers/omap3isp.rst 的中文翻译
 
 如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
 交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
index c77c0f0608647ea9432597aa0e0a2ee70c892fa9..66c7c568bd866cf07ca9869e51a1600cb17e1f0c 100644 (file)
@@ -1,4 +1,4 @@
-Chinese translated version of Documentation/video4linux/v4l2-framework.txt
+Chinese translated version of Documentation/media/media_kapi.rst
 
 If you have any comment or update to the content, please contact the
 original document maintainer directly.  However, if you have a problem
@@ -9,7 +9,7 @@ or if there is a problem with the translation.
 Maintainer: Mauro Carvalho Chehab <mchehab@kernel.org>
 Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
 ---------------------------------------------------------------------
-Documentation/video4linux/v4l2-framework.txt 的中文翻译
+Documentation/media/media_kapi.rst 的中文翻译
 
 如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
 交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
@@ -777,7 +777,7 @@ v4l2 核心 API 提供了一个处理视频缓冲的标准方法(称为“videob
 线性 DMA(videobuf-dma-contig)以及大多用于 USB 设备的用 vmalloc
 分配的缓冲(videobuf-vmalloc)。
 
-请参阅 Documentation/video4linux/videobuf,以获得更多关于 videobuf
+请参阅 Documentation/media/kapi/v4l2-videobuf.rst,以获得更多关于 videobuf
 层的使用信息。
 
 v4l2_fh 结构体
index a6844a9e2f64034a3e86e4968239bacfd115f595..1d7d648d8aadf4c5cbae9682ec56070c3d5e99bd 100644 (file)
@@ -1732,7 +1732,8 @@ F:        arch/arm/mach-npcm/
 F:     arch/arm/boot/dts/nuvoton-npcm*
 F:     include/dt-bindings/clock/nuvoton,npcm7xx-clks.h
 F:     drivers/*/*npcm*
-F:     Documentation/*/*npcm*
+F:     Documentation/devicetree/bindings/*/*npcm*
+F:     Documentation/devicetree/bindings/*/*/*npcm*
 
 ARM/NUVOTON W90X900 ARM ARCHITECTURE
 M:     Wan ZongShun <mcuos.com@gmail.com>
@@ -3079,7 +3080,7 @@ M:        Clemens Ladisch <clemens@ladisch.de>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 T:     git git://git.alsa-project.org/alsa-kernel.git
 S:     Maintained
-F:     Documentation/sound/alsa/Bt87x.txt
+F:     Documentation/sound/cards/bt87x.rst
 F:     sound/pci/bt87x.c
 
 BT8XXGPIO DRIVER
@@ -3375,7 +3376,7 @@ M:        David Howells <dhowells@redhat.com>
 M:     David Woodhouse <dwmw2@infradead.org>
 L:     keyrings@vger.kernel.org
 S:     Maintained
-F:     Documentation/module-signing.txt
+F:     Documentation/admin-guide/module-signing.rst
 F:     certs/
 F:     scripts/sign-file.c
 F:     scripts/extract-cert.c
@@ -4508,7 +4509,7 @@ DRM DRIVER FOR ILITEK ILI9225 PANELS
 M:     David Lechner <david@lechnology.com>
 S:     Maintained
 F:     drivers/gpu/drm/tinydrm/ili9225.c
-F:     Documentation/devicetree/bindings/display/ili9225.txt
+F:     Documentation/devicetree/bindings/display/ilitek,ili9225.txt
 
 DRM DRIVER FOR INTEL I810 VIDEO CARDS
 S:     Orphan / Obsolete
@@ -4594,13 +4595,13 @@ DRM DRIVER FOR SITRONIX ST7586 PANELS
 M:     David Lechner <david@lechnology.com>
 S:     Maintained
 F:     drivers/gpu/drm/tinydrm/st7586.c
-F:     Documentation/devicetree/bindings/display/st7586.txt
+F:     Documentation/devicetree/bindings/display/sitronix,st7586.txt
 
 DRM DRIVER FOR SITRONIX ST7735R PANELS
 M:     David Lechner <david@lechnology.com>
 S:     Maintained
 F:     drivers/gpu/drm/tinydrm/st7735r.c
-F:     Documentation/devicetree/bindings/display/st7735r.txt
+F:     Documentation/devicetree/bindings/display/sitronix,st7735r.txt
 
 DRM DRIVER FOR TDFX VIDEO CARDS
 S:     Orphan / Obsolete
@@ -4633,7 +4634,6 @@ F:        drivers/gpu/drm/
 F:     drivers/gpu/vga/
 F:     Documentation/devicetree/bindings/display/
 F:     Documentation/devicetree/bindings/gpu/
-F:     Documentation/devicetree/bindings/video/
 F:     Documentation/gpu/
 F:     include/drm/
 F:     include/uapi/drm/
@@ -4678,7 +4678,7 @@ M:        Boris Brezillon <boris.brezillon@bootlin.com>
 L:     dri-devel@lists.freedesktop.org
 S:     Supported
 F:     drivers/gpu/drm/atmel-hlcdc/
-F:     Documentation/devicetree/bindings/drm/atmel/
+F:     Documentation/devicetree/bindings/display/atmel/
 T:     git git://anongit.freedesktop.org/drm/drm-misc
 
 DRM DRIVERS FOR BRIDGE CHIPS
@@ -4709,7 +4709,7 @@ S:        Supported
 F:     drivers/gpu/drm/fsl-dcu/
 F:     Documentation/devicetree/bindings/display/fsl,dcu.txt
 F:     Documentation/devicetree/bindings/display/fsl,tcon.txt
-F:     Documentation/devicetree/bindings/display/panel/nec,nl4827hc19_05b.txt
+F:     Documentation/devicetree/bindings/display/panel/nec,nl4827hc19-05b.txt
 
 DRM DRIVERS FOR FREESCALE IMX
 M:     Philipp Zabel <p.zabel@pengutronix.de>
@@ -4819,7 +4819,7 @@ M:        Eric Anholt <eric@anholt.net>
 S:     Supported
 F:     drivers/gpu/drm/v3d/
 F:     include/uapi/drm/v3d_drm.h
-F:     Documentation/devicetree/bindings/display/brcm,bcm-v3d.txt
+F:     Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.txt
 T:     git git://anongit.freedesktop.org/drm/drm-misc
 
 DRM DRIVERS FOR VC4
@@ -5730,7 +5730,7 @@ M:        Madalin Bucur <madalin.bucur@nxp.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
 F:     drivers/net/ethernet/freescale/fman
-F:     Documentation/devicetree/bindings/powerpc/fsl/fman.txt
+F:     Documentation/devicetree/bindings/net/fsl-fman.txt
 
 FREESCALE QORIQ PTP CLOCK DRIVER
 M:     Yangbo Lu <yangbo.lu@nxp.com>
@@ -5948,14 +5948,14 @@ GENERIC GPIO I2C DRIVER
 M:     Haavard Skinnemoen <hskinnemoen@gmail.com>
 S:     Supported
 F:     drivers/i2c/busses/i2c-gpio.c
-F:     include/linux/i2c-gpio.h
+F:     include/linux/platform_data/i2c-gpio.h
 
 GENERIC GPIO I2C MULTIPLEXER DRIVER
 M:     Peter Korsgaard <peter.korsgaard@barco.com>
 L:     linux-i2c@vger.kernel.org
 S:     Supported
 F:     drivers/i2c/muxes/i2c-mux-gpio.c
-F:     include/linux/i2c-mux-gpio.h
+F:     include/linux/platform_data/i2c-mux-gpio.h
 F:     Documentation/i2c/muxes/i2c-mux-gpio
 
 GENERIC HDLC (WAN) DRIVERS
@@ -6496,7 +6496,7 @@ L:        linux-mm@kvack.org
 S:     Maintained
 F:     mm/hmm*
 F:     include/linux/hmm*
-F:     Documentation/vm/hmm.txt
+F:     Documentation/vm/hmm.rst
 
 HOST AP DRIVER
 M:     Jouni Malinen <j@w1.fi>
@@ -6961,7 +6961,7 @@ IIO MULTIPLEXER
 M:     Peter Rosin <peda@axentia.se>
 L:     linux-iio@vger.kernel.org
 S:     Maintained
-F:     Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
+F:     Documentation/devicetree/bindings/iio/multiplexer/io-channel-mux.txt
 F:     drivers/iio/multiplexer/iio-mux.c
 
 IIO SUBSYSTEM AND DRIVERS
@@ -7396,7 +7396,7 @@ F:        drivers/platform/x86/intel-wmi-thunderbolt.c
 INTEL(R) TRACE HUB
 M:     Alexander Shishkin <alexander.shishkin@linux.intel.com>
 S:     Supported
-F:     Documentation/trace/intel_th.txt
+F:     Documentation/trace/intel_th.rst
 F:     drivers/hwtracing/intel_th/
 
 INTEL(R) TRUSTED EXECUTION TECHNOLOGY (TXT)
@@ -7420,7 +7420,7 @@ M:        Linus Walleij <linus.walleij@linaro.org>
 L:     linux-iio@vger.kernel.org
 S:     Maintained
 F:     drivers/iio/gyro/mpu3050*
-F:     Documentation/devicetree/bindings/iio/gyroscope/inv,mpu3050.txt
+F:     Documentation/devicetree/bindings/iio/gyroscope/invensense,mpu3050.txt
 
 IOC3 ETHERNET DRIVER
 M:     Ralf Baechle <ralf@linux-mips.org>
@@ -8695,7 +8695,7 @@ M:        Guenter Roeck <linux@roeck-us.net>
 L:     linux-hwmon@vger.kernel.org
 S:     Maintained
 F:     Documentation/hwmon/max6697
-F:     Documentation/devicetree/bindings/i2c/max6697.txt
+F:     Documentation/devicetree/bindings/hwmon/max6697.txt
 F:     drivers/hwmon/max6697.c
 F:     include/linux/platform_data/max6697.h
 
@@ -9075,7 +9075,7 @@ M:        Martin Donnelly <martin.donnelly@ge.com>
 M:     Martyn Welch <martyn.welch@collabora.co.uk>
 S:     Maintained
 F:     drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
-F:     Documentation/devicetree/bindings/video/bridge/megachips-stdpxxxx-ge-b850v3-fw.txt
+F:     Documentation/devicetree/bindings/display/bridge/megachips-stdpxxxx-ge-b850v3-fw.txt
 
 MEGARAID SCSI/SAS DRIVERS
 M:     Kashyap Desai <kashyap.desai@broadcom.com>
@@ -9660,7 +9660,7 @@ F:        include/uapi/linux/mmc/
 MULTIPLEXER SUBSYSTEM
 M:     Peter Rosin <peda@axentia.se>
 S:     Maintained
-F:     Documentation/ABI/testing/mux/sysfs-class-mux*
+F:     Documentation/ABI/testing/sysfs-class-mux*
 F:     Documentation/devicetree/bindings/mux/
 F:     include/linux/dt-bindings/mux/
 F:     include/linux/mux/
@@ -9691,7 +9691,7 @@ MXSFB DRM DRIVER
 M:     Marek Vasut <marex@denx.de>
 S:     Supported
 F:     drivers/gpu/drm/mxsfb/
-F:     Documentation/devicetree/bindings/display/mxsfb-drm.txt
+F:     Documentation/devicetree/bindings/display/mxsfb.txt
 
 MYRICOM MYRI-10G 10GbE DRIVER (MYRI10GE)
 M:     Chris Lee <christopher.lee@cspi.com>
@@ -10239,7 +10239,7 @@ F:      arch/powerpc/include/asm/pnv-ocxl.h
 F:     drivers/misc/ocxl/
 F:     include/misc/ocxl*
 F:     include/uapi/misc/ocxl.h
-F:     Documentation/accelerators/ocxl.txt
+F:     Documentation/accelerators/ocxl.rst
 
 OMAP AUDIO SUPPORT
 M:     Peter Ujfalusi <peter.ujfalusi@ti.com>
@@ -10268,18 +10268,16 @@ F:    arch/arm/boot/dts/*am5*
 F:     arch/arm/boot/dts/*dra7*
 
 OMAP DISPLAY SUBSYSTEM and FRAMEBUFFER SUPPORT (DSS2)
-M:     Tomi Valkeinen <tomi.valkeinen@ti.com>
 L:     linux-omap@vger.kernel.org
 L:     linux-fbdev@vger.kernel.org
-S:     Maintained
+S:     Orphan
 F:     drivers/video/fbdev/omap2/
 F:     Documentation/arm/OMAP/DSS
 
 OMAP FRAMEBUFFER SUPPORT
-M:     Tomi Valkeinen <tomi.valkeinen@ti.com>
 L:     linux-fbdev@vger.kernel.org
 L:     linux-omap@vger.kernel.org
-S:     Maintained
+S:     Orphan
 F:     drivers/video/fbdev/omap/
 
 OMAP GENERAL PURPOSE MEMORY CONTROLLER SUPPORT
@@ -10387,7 +10385,7 @@ F:      arch/arm/mach-omap1/
 F:     arch/arm/plat-omap/
 F:     arch/arm/configs/omap1_defconfig
 F:     drivers/i2c/busses/i2c-omap.c
-F:     include/linux/i2c-omap.h
+F:     include/linux/platform_data/i2c-omap.h
 
 OMAP2+ SUPPORT
 M:     Tony Lindgren <tony@atomide.com>
@@ -10419,7 +10417,7 @@ F:      drivers/regulator/tps65218-regulator.c
 F:     drivers/regulator/tps65910-regulator.c
 F:     drivers/regulator/twl-regulator.c
 F:     drivers/regulator/twl6030-regulator.c
-F:     include/linux/i2c-omap.h
+F:     include/linux/platform_data/i2c-omap.h
 
 ONION OMEGA2+ BOARD
 M:     Harvey Hunt <harveyhuntnexus@gmail.com>
@@ -10723,7 +10721,7 @@ PARALLEL LCD/KEYPAD PANEL DRIVER
 M:     Willy Tarreau <willy@haproxy.com>
 M:     Ksenija Stanojevic <ksenija.stanojevic@gmail.com>
 S:     Odd Fixes
-F:     Documentation/misc-devices/lcd-panel-cgram.txt
+F:     Documentation/auxdisplay/lcd-panel-cgram.txt
 F:     drivers/misc/panel.c
 
 PARALLEL PORT SUBSYSTEM
@@ -10880,7 +10878,7 @@ M:      Will Deacon <will.deacon@arm.com>
 L:     linux-pci@vger.kernel.org
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-F:     Documentation/devicetree/bindings/pci/controller-generic-pci.txt
+F:     Documentation/devicetree/bindings/pci/host-generic-pci.txt
 F:     drivers/pci/controller/pci-host-common.c
 F:     drivers/pci/controller/pci-host-generic.c
 
@@ -11061,7 +11059,7 @@ M:      Xiaowei Song <songxiaowei@hisilicon.com>
 M:     Binghui Wang <wangbinghui@hisilicon.com>
 L:     linux-pci@vger.kernel.org
 S:     Maintained
-F:     Documentation/devicetree/bindings/pci/pcie-kirin.txt
+F:     Documentation/devicetree/bindings/pci/kirin-pcie.txt
 F:     drivers/pci/controller/dwc/pcie-kirin.c
 
 PCIE DRIVER FOR HISILICON STB
@@ -12174,7 +12172,7 @@ F:      drivers/mtd/nand/raw/r852.h
 
 RISC-V ARCHITECTURE
 M:     Palmer Dabbelt <palmer@sifive.com>
-M:     Albert Ou <albert@sifive.com>
+M:     Albert Ou <aou@eecs.berkeley.edu>
 L:     linux-riscv@lists.infradead.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/palmer/riscv-linux.git
 S:     Supported
@@ -12452,7 +12450,7 @@ L:      linux-crypto@vger.kernel.org
 L:     linux-samsung-soc@vger.kernel.org
 S:     Maintained
 F:     drivers/crypto/exynos-rng.c
-F:     Documentation/devicetree/bindings/crypto/samsung,exynos-rng4.txt
+F:     Documentation/devicetree/bindings/rng/samsung,exynos4-rng.txt
 
 SAMSUNG EXYNOS TRUE RANDOM NUMBER GENERATOR (TRNG) DRIVER
 M:     Łukasz Stelmach <l.stelmach@samsung.com>
@@ -12934,6 +12932,14 @@ F:     drivers/media/usb/siano/
 F:     drivers/media/usb/siano/
 F:     drivers/media/mmc/siano/
 
+SIFIVE DRIVERS
+M:     Palmer Dabbelt <palmer@sifive.com>
+L:     linux-riscv@lists.infradead.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/palmer/riscv-linux.git
+S:     Supported
+K:     sifive
+N:     sifive
+
 SILEAD TOUCHSCREEN DRIVER
 M:     Hans de Goede <hdegoede@redhat.com>
 L:     linux-input@vger.kernel.org
@@ -13286,7 +13292,7 @@ M:      Vinod Koul <vkoul@kernel.org>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
 S:     Supported
-F:     Documentation/sound/alsa/compress_offload.txt
+F:     Documentation/sound/designs/compress-offload.rst
 F:     include/sound/compress_driver.h
 F:     include/uapi/sound/compress_*
 F:     sound/core/compress_offload.c
@@ -13307,7 +13313,7 @@ L:      alsa-devel@alsa-project.org (moderated for non-subscribers)
 W:     http://alsa-project.org/main/index.php/ASoC
 S:     Supported
 F:     Documentation/devicetree/bindings/sound/
-F:     Documentation/sound/alsa/soc/
+F:     Documentation/sound/soc/
 F:     sound/soc/
 F:     include/sound/soc*
 
@@ -13566,7 +13572,7 @@ F:      drivers/*/stm32-*timer*
 F:     drivers/pwm/pwm-stm32*
 F:     include/linux/*/stm32-*tim*
 F:     Documentation/ABI/testing/*timer-stm32
-F:     Documentation/devicetree/bindings/*/stm32-*timer
+F:     Documentation/devicetree/bindings/*/stm32-*timer*
 F:     Documentation/devicetree/bindings/pwm/pwm-stm32*
 
 STMMAC ETHERNET DRIVER
@@ -13789,7 +13795,7 @@ SYSTEM TRACE MODULE CLASS
 M:     Alexander Shishkin <alexander.shishkin@linux.intel.com>
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ash/stm.git
-F:     Documentation/trace/stm.txt
+F:     Documentation/trace/stm.rst
 F:     drivers/hwtracing/stm/
 F:     include/linux/stm.h
 F:     include/uapi/linux/stm.h
@@ -14466,7 +14472,7 @@ M:      Steven Rostedt <rostedt@goodmis.org>
 M:     Ingo Molnar <mingo@redhat.com>
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git perf/core
 S:     Maintained
-F:     Documentation/trace/ftrace.txt
+F:     Documentation/trace/ftrace.rst
 F:     arch/*/*/*/ftrace.h
 F:     arch/*/kernel/ftrace.c
 F:     include/*/ftrace.h
@@ -14935,7 +14941,7 @@ M:      Heikki Krogerus <heikki.krogerus@linux.intel.com>
 L:     linux-usb@vger.kernel.org
 S:     Maintained
 F:     Documentation/ABI/testing/sysfs-class-typec
-F:     Documentation/usb/typec.rst
+F:     Documentation/driver-api/usb/typec.rst
 F:     drivers/usb/typec/
 F:     include/linux/usb/typec.h
 
@@ -15002,8 +15008,7 @@ F:      drivers/media/usb/zr364xx/
 USER-MODE LINUX (UML)
 M:     Jeff Dike <jdike@addtoit.com>
 M:     Richard Weinberger <richard@nod.at>
-L:     user-mode-linux-devel@lists.sourceforge.net
-L:     user-mode-linux-user@lists.sourceforge.net
+L:     linux-um@lists.infradead.org
 W:     http://user-mode-linux.sourceforge.net
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml.git
 S:     Maintained
@@ -15565,6 +15570,13 @@ S:     Maintained
 F:     Documentation/x86/
 F:     arch/x86/
 
+X86 ENTRY CODE
+M:     Andy Lutomirski <luto@kernel.org>
+L:     linux-kernel@vger.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/asm
+S:     Maintained
+F:     arch/x86/entry/
+
 X86 MCE INFRASTRUCTURE
 M:     Tony Luck <tony.luck@intel.com>
 M:     Borislav Petkov <bp@alien8.de>
@@ -15587,7 +15599,7 @@ F:      drivers/platform/x86/
 F:     drivers/platform/olpc/
 
 X86 VDSO
-M:     Andy Lutomirski <luto@amacapital.net>
+M:     Andy Lutomirski <luto@kernel.org>
 L:     linux-kernel@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/vdso
 S:     Maintained
@@ -15765,7 +15777,7 @@ YEALINK PHONE DRIVER
 M:     Henk Vergonet <Henk.Vergonet@gmail.com>
 L:     usbb2k-api-dev@nongnu.org
 S:     Maintained
-F:     Documentation/input/yealink.rst
+F:     Documentation/input/devices/yealink.rst
 F:     drivers/input/misc/yealink.*
 
 Z8530 DRIVER FOR AX.25
index 73f0bb2c7a984c595dc1ab6ac62b0438daf96367..ca2af1ab91ebadf6ac5c62150b4e72f2a1f1441d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
 # SPDX-License-Identifier: GPL-2.0
 VERSION = 4
-PATCHLEVEL = 17
+PATCHLEVEL = 18
 SUBLEVEL = 0
-EXTRAVERSION =
+EXTRAVERSION = -rc1
 NAME = Merciless Moray
 
 # *DOCUMENTATION*
@@ -687,8 +687,8 @@ KBUILD_CFLAGS += $(call cc-option,-Wframe-larger-than=${CONFIG_FRAME_WARN})
 endif
 
 stackp-flags-$(CONFIG_CC_HAS_STACKPROTECTOR_NONE) := -fno-stack-protector
-stackp-flags-$(CONFIG_CC_STACKPROTECTOR)          := -fstack-protector
-stackp-flags-$(CONFIG_CC_STACKPROTECTOR_STRONG)   := -fstack-protector-strong
+stackp-flags-$(CONFIG_STACKPROTECTOR)             := -fstack-protector
+stackp-flags-$(CONFIG_STACKPROTECTOR_STRONG)      := -fstack-protector-strong
 
 KBUILD_CFLAGS += $(stackp-flags-y)
 
index ebbb450961919a31256f5c1c6408c6df6fee7a05..1aa59063f1fd9b29ccec8339c614c42b09f176f2 100644 (file)
@@ -403,7 +403,7 @@ config SECCOMP_FILTER
          in terms of Berkeley Packet Filter programs which implement
          task-defined system call filtering polices.
 
-         See Documentation/prctl/seccomp_filter.txt for details.
+         See Documentation/userspace-api/seccomp_filter.rst for details.
 
 preferred-plugin-hostcc := $(if-success,[ $(gcc-version) -ge 40800 ],$(HOSTCXX),$(HOSTCC))
 
@@ -549,7 +549,7 @@ config GCC_PLUGIN_RANDSTRUCT_PERFORMANCE
          in structures.  This reduces the performance hit of RANDSTRUCT
          at the cost of weakened randomization.
 
-config HAVE_CC_STACKPROTECTOR
+config HAVE_STACKPROTECTOR
        bool
        help
          An arch should select this symbol if:
@@ -558,9 +558,9 @@ config HAVE_CC_STACKPROTECTOR
 config CC_HAS_STACKPROTECTOR_NONE
        def_bool $(cc-option,-fno-stack-protector)
 
-config CC_STACKPROTECTOR
+config STACKPROTECTOR
        bool "Stack Protector buffer overflow detection"
-       depends on HAVE_CC_STACKPROTECTOR
+       depends on HAVE_STACKPROTECTOR
        depends on $(cc-option,-fstack-protector)
        default y
        help
@@ -582,9 +582,9 @@ config CC_STACKPROTECTOR
          about 3% of all kernel functions, which increases kernel code size
          by about 0.3%.
 
-config CC_STACKPROTECTOR_STRONG
+config STACKPROTECTOR_STRONG
        bool "Strong Stack Protector"
-       depends on CC_STACKPROTECTOR
+       depends on STACKPROTECTOR
        depends on $(cc-option,-fstack-protector-strong)
        default y
        help
index 2a78bdef9a246a76716b07e3ac8527dab2a950f5..54eeb8d00bc62a9f818aa9a833cbc15e7a1d9324 100644 (file)
@@ -8,9 +8,10 @@ config ARM
        select ARCH_HAS_DEVMEM_IS_ALLOWED
        select ARCH_HAS_ELF_RANDOMIZE
        select ARCH_HAS_FORTIFY_SOURCE
+       select ARCH_HAS_KCOV
        select ARCH_HAS_PTE_SPECIAL if ARM_LPAE
-       select ARCH_HAS_SET_MEMORY
        select ARCH_HAS_PHYS_TO_DMA
+       select ARCH_HAS_SET_MEMORY
        select ARCH_HAS_STRICT_KERNEL_RWX if MMU && !XIP_KERNEL
        select ARCH_HAS_STRICT_MODULE_RWX if MMU
        select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
@@ -57,7 +58,6 @@ config ARM
        select HAVE_ARCH_TRACEHOOK
        select HAVE_ARM_SMCCC if CPU_V7
        select HAVE_EBPF_JIT if !CPU_ENDIAN_BE32
-       select HAVE_CC_STACKPROTECTOR
        select HAVE_CONTEXT_TRACKING
        select HAVE_C_RECORDMCOUNT
        select HAVE_DEBUG_KMEMLEAK
@@ -92,6 +92,7 @@ config ARM
        select HAVE_RCU_TABLE_FREE if (SMP && ARM_LPAE)
        select HAVE_REGS_AND_STACK_ACCESS_API
        select HAVE_RSEQ
+       select HAVE_STACKPROTECTOR
        select HAVE_SYSCALL_TRACEPOINTS
        select HAVE_UID16
        select HAVE_VIRT_CPU_ACCOUNTING_GEN
@@ -1301,7 +1302,7 @@ config SMP
          will run faster if you say N here.
 
          See also <file:Documentation/x86/i386/IO-APIC.txt>,
-         <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
+         <file:Documentation/lockup-watchdogs.txt> and the SMP-HOWTO available at
          <http://tldp.org/HOWTO/SMP-HOWTO.html>.
 
          If you don't know what to do here, say N.
index a3c5fbcad4abf08bebc2e7303309eea156bd6b01..1f5a5ffe7fcf84b5da64bc74747c50384f5bfeea 100644 (file)
@@ -25,6 +25,9 @@ endif
 
 GCOV_PROFILE           := n
 
+# Prevents link failures: __sanitizer_cov_trace_pc() is not linked in.
+KCOV_INSTRUMENT                := n
+
 #
 # Architecture dependencies
 #
index 869080bedb89f031dd3295702cd1466c919a3113..ec1a5fd0d2948987cb1fbccf8b477cd82b16838e 100644 (file)
@@ -35,7 +35,7 @@
  *     Start addresses are inclusive and end addresses are exclusive;
  *     start addresses should be rounded down, end addresses up.
  *
- *     See Documentation/cachetlb.txt for more information.
+ *     See Documentation/core-api/cachetlb.rst for more information.
  *     Please note that the implementation of these, and the required
  *     effects are cache-type (VIVT/VIPT/PIPT) specific.
  *
index 27c5381518d8878d664fd3e9575b3f0aaf963417..974d8d7d1bcdd2a68e101296a4fd9649cb4cebe9 100644 (file)
@@ -61,7 +61,7 @@
 int main(void)
 {
   DEFINE(TSK_ACTIVE_MM,                offsetof(struct task_struct, active_mm));
-#ifdef CONFIG_CC_STACKPROTECTOR
+#ifdef CONFIG_STACKPROTECTOR
   DEFINE(TSK_STACK_CANARY,     offsetof(struct task_struct, stack_canary));
 #endif
   BLANK();
index 1752033b00700c780666352d6b256f5d36396d28..179a9f6bd1e31c63564fd3e67444d41916939617 100644 (file)
@@ -791,7 +791,7 @@ ENTRY(__switch_to)
        ldr     r6, [r2, #TI_CPU_DOMAIN]
 #endif
        switch_tls r1, r4, r5, r3, r7
-#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
+#if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_SMP)
        ldr     r7, [r2, #TI_TASK]
        ldr     r8, =__stack_chk_guard
        .if (TSK_STACK_CANARY > IMM12_MASK)
@@ -807,7 +807,7 @@ ENTRY(__switch_to)
        ldr     r0, =thread_notify_head
        mov     r1, #THREAD_NOTIFY_SWITCH
        bl      atomic_notifier_call_chain
-#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
+#if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_SMP)
        str     r7, [r8]
 #endif
  THUMB(        mov     ip, r4                     )
index 1523cb18b10994dd3ba186de0da5aff6dc5762be..225d1c58d2de98d5c4a92de4905052203f1e25b6 100644 (file)
@@ -39,7 +39,7 @@
 #include <asm/tls.h>
 #include <asm/vdso.h>
 
-#ifdef CONFIG_CC_STACKPROTECTOR
+#ifdef CONFIG_STACKPROTECTOR
 #include <linux/stackprotector.h>
 unsigned long __stack_chk_guard __read_mostly;
 EXPORT_SYMBOL(__stack_chk_guard);
index 7fc0638f263ac975dc3a4bddd0c1ec00adc2348f..d2b5ec9c4b9293758626d35ce49b6ba226140b73 100644 (file)
@@ -23,3 +23,11 @@ obj-$(CONFIG_KVM_ARM_HOST) += hyp-entry.o
 obj-$(CONFIG_KVM_ARM_HOST) += switch.o
 CFLAGS_switch.o                   += $(CFLAGS_ARMV7VE)
 obj-$(CONFIG_KVM_ARM_HOST) += s2-setup.o
+
+# KVM code is run at a different exception code with a different map, so
+# compiler instrumentation that inserts callbacks or checks into the code may
+# cause crashes. Just disable it.
+GCOV_PROFILE   := n
+KASAN_SANITIZE := n
+UBSAN_SANITIZE := n
+KCOV_INSTRUMENT        := n
index 937eb1d47e7bb793a774e06c015347e726abc513..ef835d82cdb95ecb7f43d36a80f1dc7c9870a5b6 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/gpio/machine.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
-#include <linux/i2c-gpio.h>
+#include <linux/platform_data/i2c-gpio.h>
 #include <linux/platform_data/pca953x.h>
 
 #include <linux/mtd/mtd.h>
index 67d46690a56e470d98c7a22792e856b237809a23..da8f3fc3180f55c2366ed9f68afb2fe116cf7a75 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/gpio.h>
 #include <linux/gpio_keys.h>
 #include <linux/i2c.h>
-#include <linux/i2c-gpio.h>
+#include <linux/platform_data/i2c-gpio.h>
 #include <linux/htcpld.h>
 #include <linux/leds.h>
 #include <linux/spi/spi.h>
index d83ff257eaa8fb5decb1fca1388989243dac3f2c..c6537d2c28597ac1f8296322085d591198d508f4 100644 (file)
@@ -27,7 +27,7 @@
 #define __ARCH_ARM_MACH_OMAP1_COMMON_H
 
 #include <linux/mtd/mtd.h>
-#include <linux/i2c-omap.h>
+#include <linux/platform_data/i2c-omap.h>
 #include <linux/reboot.h>
 
 #include <asm/exception.h>
index 5bdf3c4190f97221e3db0d090e558476d5091579..9250f263ac5117a4b02a7f1672fcbf63547d34d8 100644 (file)
@@ -20,7 +20,7 @@
  */
 
 #include <linux/i2c.h>
-#include <linux/i2c-omap.h>
+#include <linux/platform_data/i2c-omap.h>
 #include <mach/mux.h>
 #include "soc.h"
 
index dff3750e432f56fdceee074af22fa75339d94edd..129455e822e42564fbeefffabe2d3dbb5eed3102 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/mfd/twl.h>
-#include <linux/i2c-omap.h>
+#include <linux/platform_data/i2c-omap.h>
 #include <linux/reboot.h>
 #include <linux/irqchip/irq-omap-intc.h>
 
index fe66cf2478741c00a48f82addf68ef7782d8a7c6..d684fac8f592846ced792ac45a87f3c297b01baa 100644 (file)
@@ -13,7 +13,7 @@
  * XXX these should be marked initdata for multi-OMAP kernels
  */
 
-#include <linux/i2c-omap.h>
+#include <linux/platform_data/i2c-omap.h>
 #include <linux/omap-dma.h>
 
 #include "omap_hwmod.h"
index 74eefd30518c9dd59420ce9f3517987cac897df4..abef9f6f9bf57dd95452c73c22c41168aa7c5de2 100644 (file)
@@ -13,7 +13,7 @@
  * XXX these should be marked initdata for multi-OMAP kernels
  */
 
-#include <linux/i2c-omap.h>
+#include <linux/platform_data/i2c-omap.h>
 #include <linux/platform_data/hsmmc-omap.h>
 #include <linux/omap-dma.h>
 
index 53e1ac3724f287fb94c803a07d50a2eb3436f32f..c9483bc062280bf2174ee83730a7455d93591161 100644 (file)
@@ -14,7 +14,7 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/i2c-omap.h>
+#include <linux/platform_data/i2c-omap.h>
 
 #include "omap_hwmod.h"
 #include "omap_hwmod_common_data.h"
index d93f9ea4119ef21058c638c0a8462577752b9b18..23e6a41a18eb3c184f562215c0970a4d9d828268 100644 (file)
@@ -15,7 +15,7 @@
  * XXX these should be marked initdata for multi-OMAP kernels
  */
 
-#include <linux/i2c-omap.h>
+#include <linux/platform_data/i2c-omap.h>
 #include <linux/power/smartreflex.h>
 #include <linux/platform_data/hsmmc-omap.h>
 
index 234ee0eec81575c5e2e921955f0dd0171cd4ae48..a95dbac57a814a92d23e660f2273549da6cce2cc 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/io.h>
 #include <linux/platform_data/hsmmc-omap.h>
 #include <linux/power/smartreflex.h>
-#include <linux/i2c-omap.h>
+#include <linux/platform_data/i2c-omap.h>
 
 #include <linux/omap-dma.h>
 
index 887a30fa775bd587f485d4f024ebaf85919eff7c..115473d441cde08bdbf360572b35ca41ae500ebd 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/io.h>
 #include <linux/platform_data/hsmmc-omap.h>
 #include <linux/power/smartreflex.h>
-#include <linux/i2c-omap.h>
+#include <linux/platform_data/i2c-omap.h>
 
 #include <linux/omap-dma.h>
 
index a27c2fed298c95bc2ad7c51c4be55c759dda1036..e6c7061a8e73679695f7816c0461ccccf66151c6 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/io.h>
 #include <linux/platform_data/hsmmc-omap.h>
 #include <linux/power/smartreflex.h>
-#include <linux/i2c-omap.h>
+#include <linux/platform_data/i2c-omap.h>
 
 #include <linux/omap-dma.h>
 
index 0adb1bd6208e27ab349c88ce2e912ad6a22109e2..4d475f6f4a777081d2e0c9c695ad7ceb26ab399f 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/wm97xx.h>
 #include <linux/power_supply.h>
 #include <linux/usb/gpio_vbus.h>
-#include <linux/i2c-gpio.h>
+#include <linux/platform_data/i2c-gpio.h>
 #include <linux/gpio/machine.h>
 
 #include <asm/mach-types.h>
index 207dcc2e94e70694376423a4a3c938d434368ff8..ab2f89266bbd44d1ebc8ff0e3018ae3a0dc09636 100644 (file)
@@ -35,7 +35,7 @@
 #include <linux/sched.h>
 #include <linux/gpio.h>
 #include <linux/jiffies.h>
-#include <linux/i2c-gpio.h>
+#include <linux/platform_data/i2c-gpio.h>
 #include <linux/gpio/machine.h>
 #include <linux/platform_data/i2c-pxa.h>
 #include <linux/serial_8250.h>
index f45aed2519ba21979ce107b492059e26857bbae3..406487e76a5cec4d6f0e7e60849f5ddc4e02c763 100644 (file)
@@ -37,7 +37,7 @@
 #include <linux/input.h>
 #include <linux/gpio_keys.h>
 #include <linux/leds.h>
-#include <linux/i2c-gpio.h>
+#include <linux/platform_data/i2c-gpio.h>
 
 #include "generic.h"
 
index bb4118213feee5ae9b33f85abb853ae20d51721b..f4efff9d3afbb68e6ae9d09f0b4cd3538bb66f63 100644 (file)
@@ -30,6 +30,9 @@ CFLAGS_vgettimeofday.o = -O2
 # Disable gcov profiling for VDSO code
 GCOV_PROFILE := n
 
+# Prevents link failures: __sanitizer_cov_trace_pc() is not linked in.
+KCOV_INSTRUMENT := n
+
 # Force dependency
 $(obj)/vdso.o : $(obj)/vdso.so
 
index 14f204c454505931da3f80affb97a059fa093499..42c090cf02927283ccb2dc597e30205a11050ecb 100644 (file)
@@ -103,7 +103,6 @@ config ARM64
        select HAVE_ARM_SMCCC
        select HAVE_EBPF_JIT
        select HAVE_C_RECORDMCOUNT
-       select HAVE_CC_STACKPROTECTOR
        select HAVE_CMPXCHG_DOUBLE
        select HAVE_CMPXCHG_LOCAL
        select HAVE_CONTEXT_TRACKING
@@ -128,6 +127,7 @@ config ARM64
        select HAVE_PERF_USER_STACK_DUMP
        select HAVE_REGS_AND_STACK_ACCESS_API
        select HAVE_RCU_TABLE_FREE
+       select HAVE_STACKPROTECTOR
        select HAVE_SYSCALL_TRACEPOINTS
        select HAVE_KPROBES
        select HAVE_KRETPROBES
index 0094c6653b06b44ac1172688fac240bae37fe24d..d264a7274811fece4035a054a9f97e01e2ca8aac 100644 (file)
@@ -36,7 +36,7 @@
  *     Start addresses are inclusive and end addresses are exclusive; start
  *     addresses should be rounded down, end addresses up.
  *
- *     See Documentation/cachetlb.txt for more information. Please note that
+ *     See Documentation/core-api/cachetlb.rst for more information. Please note that
  *     the implementation assumes non-aliasing VIPT D-cache and (aliasing)
  *     VIPT I-cache.
  *
index f08a2ed9db0db31c8d911ab1e8be3c98953a2f27..e10bc363f533df53f7a9d6e343f6d1b4e7996909 100644 (file)
@@ -59,7 +59,7 @@
 #include <asm/processor.h>
 #include <asm/stacktrace.h>
 
-#ifdef CONFIG_CC_STACKPROTECTOR
+#ifdef CONFIG_STACKPROTECTOR
 #include <linux/stackprotector.h>
 unsigned long __stack_chk_guard __read_mostly;
 EXPORT_SYMBOL(__stack_chk_guard);
index 1b18b472242034b2cfe90ff91a27da8b850bcdaa..325cfb3b858aa698a96b23433230503063375b17 100644 (file)
@@ -310,7 +310,7 @@ static void __init arm64_memory_present(void)
 }
 #endif
 
-static phys_addr_t memory_limit = (phys_addr_t)ULLONG_MAX;
+static phys_addr_t memory_limit = PHYS_ADDR_MAX;
 
 /*
  * Limit the memory size that was specified via FDT.
@@ -401,7 +401,7 @@ void __init arm64_memblock_init(void)
         * high up in memory, add back the kernel region that must be accessible
         * via the linear mapping.
         */
-       if (memory_limit != (phys_addr_t)ULLONG_MAX) {
+       if (memory_limit != PHYS_ADDR_MAX) {
                memblock_mem_limit_remove_map(memory_limit);
                memblock_add(__pa_symbol(_text), (u64)(_end - _text));
        }
@@ -666,7 +666,7 @@ __setup("keepinitrd", keepinitrd_setup);
  */
 static int dump_mem_limit(struct notifier_block *self, unsigned long v, void *p)
 {
-       if (memory_limit != (phys_addr_t)ULLONG_MAX) {
+       if (memory_limit != PHYS_ADDR_MAX) {
                pr_emerg("Memory Limit: %llu MB\n", memory_limit >> 20);
        } else {
                pr_emerg("Memory Limit: none\n");
index aef02f7ca8aaa26f020454b91d785b1614dbb060..65125d0b02dd5102639f01dd39156b3bf133bfd9 100644 (file)
@@ -30,7 +30,6 @@
 
 /* A handy thing to have if one has the RAM. Declared in head.S */
 extern unsigned long empty_zero_page;
-extern unsigned long zero_page_mask;
 
 /*
  * The PTE model described here is that of the Hexagon Virtual Machine,
index 6981949f5df3c3b8a2adef85d99de7501636d045..dc8c7e75b5d1121ac9e6febce5e341a45778b59f 100644 (file)
@@ -66,7 +66,7 @@ void __init setup_arch(char **cmdline_p)
         */
        __vmsetvec(_K_VM_event_vector);
 
-       printk(KERN_INFO "PHYS_OFFSET=0x%08x\n", PHYS_OFFSET);
+       printk(KERN_INFO "PHYS_OFFSET=0x%08lx\n", PHYS_OFFSET);
 
        /*
         * Simulator has a few differences from the hardware.
index 192584d5ac2fb8b5d131379db487968b446643bd..1495d45e472d880a0e484ed8b567435414d91884 100644 (file)
@@ -39,9 +39,6 @@ unsigned long __phys_offset;  /*  physical kernel offset >> 12  */
 /*  Set as variable to limit PMD copies  */
 int max_kernel_seg = 0x303;
 
-/*  think this should be (page_size-1) the way it's used...*/
-unsigned long zero_page_mask;
-
 /*  indicate pfn's of high memory  */
 unsigned long highstart_pfn, highend_pfn;
 
index ffea82a16d2cb0897c7d2d4b6a79a67cf1130f44..b091de77b15b517960b3af941a6f5aadad936b3d 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/mm.h>
 #include <linux/io.h>
 
-/* Look at Documentation/cachetlb.txt */
+/* Look at Documentation/core-api/cachetlb.rst */
 
 /*
  * Cache handling functions.
index fe98e459a416dfbf0eb22e4b72a583cbf9981250..3f9deec70b92383130b847ef3d9585db5134675e 100644 (file)
@@ -41,7 +41,6 @@ config MIPS
        select HAVE_ARCH_TRANSPARENT_HUGEPAGE if CPU_SUPPORTS_HUGEPAGES && 64BIT
        select HAVE_CBPF_JIT if (!64BIT && !CPU_MICROMIPS)
        select HAVE_EBPF_JIT if (64BIT && !CPU_MICROMIPS)
-       select HAVE_CC_STACKPROTECTOR
        select HAVE_CONTEXT_TRACKING
        select HAVE_COPY_THREAD_TLS
        select HAVE_C_RECORDMCOUNT
@@ -66,6 +65,7 @@ config MIPS
        select HAVE_OPROFILE
        select HAVE_PERF_EVENTS
        select HAVE_REGS_AND_STACK_ACCESS_API
+       select HAVE_STACKPROTECTOR
        select HAVE_SYSCALL_TRACEPOINTS
        select HAVE_VIRT_CPU_ACCOUNTING_GEN if 64BIT || !SMP
        select IRQ_FORCED_THREADING
index 4e79dbd54a339143e3a3810ec45b0ee5fb734f2d..fa75d75b5ba9177f669e6f61f6395a6db28563d0 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/leds.h>
 #include <linux/gpio.h>
 #include <linux/i2c.h>
-#include <linux/i2c-gpio.h>
+#include <linux/platform_data/i2c-gpio.h>
 #include <linux/gpio/machine.h>
 #include <asm/bootinfo.h>
 #include <asm/idle.h>
index c1cd41456d42f5dd6b5e45b62eee8f6b2393c2aa..cbe4742d2fffe1d8857bef4cf83cb4d7f0185882 100644 (file)
@@ -83,7 +83,7 @@ void output_task_defines(void)
        OFFSET(TASK_FLAGS, task_struct, flags);
        OFFSET(TASK_MM, task_struct, mm);
        OFFSET(TASK_PID, task_struct, pid);
-#if defined(CONFIG_CC_STACKPROTECTOR)
+#if defined(CONFIG_STACKPROTECTOR)
        OFFSET(TASK_STACK_CANARY, task_struct, stack_canary);
 #endif
        DEFINE(TASK_STRUCT_SIZE, sizeof(struct task_struct));
index e42113fe2762b5e8298f40a64d0d635799334d5d..896080b445c2db7e4c02adb85ad59a92d2809b2f 100644 (file)
@@ -61,7 +61,7 @@
 #endif
 3:
 
-#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
+#if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_SMP)
        PTR_LA  t8, __stack_chk_guard
        LONG_L  t9, TASK_STACK_CANARY(a1)
        LONG_S  t9, 0(t8)
index 3775a8d694fb0879ba0abed7b2edc34a06a52a28..8d85046adcc8dd858cb5b392b68dc22da19185c4 100644 (file)
@@ -180,7 +180,7 @@ int copy_thread_tls(unsigned long clone_flags, unsigned long usp,
        return 0;
 }
 
-#ifdef CONFIG_CC_STACKPROTECTOR
+#ifdef CONFIG_STACKPROTECTOR
 #include <linux/stackprotector.h>
 unsigned long __stack_chk_guard __read_mostly;
 EXPORT_SYMBOL(__stack_chk_guard);
index 665897139f30c08985ed38352192cabf0148c0f4..71b1aafae1bb1c1a209e4722043b369a34dbfc3e 100644 (file)
@@ -36,7 +36,7 @@ LEAF(resume)
        cpu_save_nonscratch a0
        sw      ra, THREAD_REG31(a0)
 
-#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
+#if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_SMP)
        PTR_LA  t8, __stack_chk_guard
        LONG_L  t9, TASK_STACK_CANARY(a1)
        LONG_S  t9, 0(t8)
index 17cf9341c1cf0c1ad34dc0362b85ee550a82f9ca..58232ae6cfae3e4c26aa96afd09eb3adb378184e 100644 (file)
@@ -31,7 +31,7 @@
        cpu_save_nonscratch a0
        LONG_S  ra, THREAD_REG31(a0)
 
-#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
+#if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_SMP)
        PTR_LA  t8, __stack_chk_guard
        LONG_L  t9, TASK_STACK_CANARY(a1)
        LONG_S  t9, 0(t8)
index 563188ac6fa264ab930cab5a6040d173e21b542c..2c96c0c68116252e2965a4d4ff395a71603779fd 100644 (file)
@@ -93,7 +93,7 @@ void __init add_memory_region(phys_addr_t start, phys_addr_t size, long type)
         * If the region reaches the top of the physical address space, adjust
         * the size slightly so that (start + size) doesn't overflow
         */
-       if (start + size - 1 == (phys_addr_t)ULLONG_MAX)
+       if (start + size - 1 == PHYS_ADDR_MAX)
                --size;
 
        /* Sanity check */
@@ -376,7 +376,7 @@ static void __init bootmem_init(void)
        unsigned long reserved_end;
        unsigned long mapstart = ~0UL;
        unsigned long bootmap_size;
-       phys_addr_t ramstart = (phys_addr_t)ULLONG_MAX;
+       phys_addr_t ramstart = PHYS_ADDR_MAX;
        bool bootmap_valid = false;
        int i;
 
index 4d8f64d4859790b97b11f337f8e7774164f1ee59..c480770fabcd6287571dacb9d40ccc224f8e13b1 100644 (file)
@@ -275,7 +275,7 @@ config SMP
          machines, but will use only one CPU of a multiprocessor machine.
          On a uniprocessor machine, the kernel will run faster if you say N.
 
-         See also <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO
+         See also <file:Documentation/lockup-watchdogs.txt> and the SMP-HOWTO
          available at <http://www.tldp.org/docs.html#howto>.
 
          If you don't know what to do here, say N.
index aa9e785c59c230c69208bf4c32dfc60fadebc2bb..7841b8a60657906535c3973cd366f5fe8a4a19a8 100644 (file)
@@ -134,7 +134,13 @@ unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip);
 void pnv_power9_force_smt4_catch(void);
 void pnv_power9_force_smt4_release(void);
 
+/* Transaction memory related */
 void tm_enable(void);
 void tm_disable(void);
 void tm_abort(uint8_t cause);
+
+struct kvm_vcpu;
+void _kvmppc_restore_tm_pr(struct kvm_vcpu *vcpu, u64 guest_msr);
+void _kvmppc_save_tm_pr(struct kvm_vcpu *vcpu, u64 guest_msr);
+
 #endif /* _ASM_POWERPC_ASM_PROTOTYPES_H */
index e7377b73cfecaa2874fe240ee861e472cfa9309d..1f345a0b6ba20b24b5408f21099fb10f68e9ff82 100644 (file)
@@ -104,6 +104,7 @@ struct kvmppc_vcore {
        ulong vtb;              /* virtual timebase */
        ulong conferring_threads;
        unsigned int halt_poll_ns;
+       atomic_t online_count;
 };
 
 struct kvmppc_vcpu_book3s {
@@ -209,6 +210,7 @@ extern void kvmppc_book3s_queue_irqprio(struct kvm_vcpu *vcpu, unsigned int vec)
 extern void kvmppc_book3s_dequeue_irqprio(struct kvm_vcpu *vcpu,
                                          unsigned int vec);
 extern void kvmppc_inject_interrupt(struct kvm_vcpu *vcpu, int vec, u64 flags);
+extern void kvmppc_trigger_fac_interrupt(struct kvm_vcpu *vcpu, ulong fac);
 extern void kvmppc_set_bat(struct kvm_vcpu *vcpu, struct kvmppc_bat *bat,
                           bool upper, u32 val);
 extern void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr);
@@ -256,6 +258,21 @@ extern int kvmppc_hcall_impl_pr(unsigned long cmd);
 extern int kvmppc_hcall_impl_hv_realmode(unsigned long cmd);
 extern void kvmppc_copy_to_svcpu(struct kvm_vcpu *vcpu);
 extern void kvmppc_copy_from_svcpu(struct kvm_vcpu *vcpu);
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+void kvmppc_save_tm_pr(struct kvm_vcpu *vcpu);
+void kvmppc_restore_tm_pr(struct kvm_vcpu *vcpu);
+void kvmppc_save_tm_sprs(struct kvm_vcpu *vcpu);
+void kvmppc_restore_tm_sprs(struct kvm_vcpu *vcpu);
+#else
+static inline void kvmppc_save_tm_pr(struct kvm_vcpu *vcpu) {}
+static inline void kvmppc_restore_tm_pr(struct kvm_vcpu *vcpu) {}
+static inline void kvmppc_save_tm_sprs(struct kvm_vcpu *vcpu) {}
+static inline void kvmppc_restore_tm_sprs(struct kvm_vcpu *vcpu) {}
+#endif
+
+void kvmppc_giveup_fac(struct kvm_vcpu *vcpu, ulong fac);
+
 extern int kvm_irq_bypass;
 
 static inline struct kvmppc_vcpu_book3s *to_book3s(struct kvm_vcpu *vcpu)
@@ -274,12 +291,12 @@ static inline struct kvmppc_vcpu_book3s *to_book3s(struct kvm_vcpu *vcpu)
 
 static inline void kvmppc_set_gpr(struct kvm_vcpu *vcpu, int num, ulong val)
 {
-       vcpu->arch.gpr[num] = val;
+       vcpu->arch.regs.gpr[num] = val;
 }
 
 static inline ulong kvmppc_get_gpr(struct kvm_vcpu *vcpu, int num)
 {
-       return vcpu->arch.gpr[num];
+       return vcpu->arch.regs.gpr[num];
 }
 
 static inline void kvmppc_set_cr(struct kvm_vcpu *vcpu, u32 val)
@@ -294,42 +311,42 @@ static inline u32 kvmppc_get_cr(struct kvm_vcpu *vcpu)
 
 static inline void kvmppc_set_xer(struct kvm_vcpu *vcpu, ulong val)
 {
-       vcpu->arch.xer = val;
+       vcpu->arch.regs.xer = val;
 }
 
 static inline ulong kvmppc_get_xer(struct kvm_vcpu *vcpu)
 {
-       return vcpu->arch.xer;
+       return vcpu->arch.regs.xer;
 }
 
 static inline void kvmppc_set_ctr(struct kvm_vcpu *vcpu, ulong val)
 {
-       vcpu->arch.ctr = val;
+       vcpu->arch.regs.ctr = val;
 }
 
 static inline ulong kvmppc_get_ctr(struct kvm_vcpu *vcpu)
 {
-       return vcpu->arch.ctr;
+       return vcpu->arch.regs.ctr;
 }
 
 static inline void kvmppc_set_lr(struct kvm_vcpu *vcpu, ulong val)
 {
-       vcpu->arch.lr = val;
+       vcpu->arch.regs.link = val;
 }
 
 static inline ulong kvmppc_get_lr(struct kvm_vcpu *vcpu)
 {
-       return vcpu->arch.lr;
+       return vcpu->arch.regs.link;
 }
 
 static inline void kvmppc_set_pc(struct kvm_vcpu *vcpu, ulong val)
 {
-       vcpu->arch.pc = val;
+       vcpu->arch.regs.nip = val;
 }
 
 static inline ulong kvmppc_get_pc(struct kvm_vcpu *vcpu)
 {
-       return vcpu->arch.pc;
+       return vcpu->arch.regs.nip;
 }
 
 static inline u64 kvmppc_get_msr(struct kvm_vcpu *vcpu);
index c424e44f4c0010e4e6f12f36fac1a792575948be..dc435a5af7d6cfd04ddb81e81d0476f8b214bdb2 100644 (file)
@@ -483,15 +483,15 @@ static inline u64 sanitize_msr(u64 msr)
 static inline void copy_from_checkpoint(struct kvm_vcpu *vcpu)
 {
        vcpu->arch.cr  = vcpu->arch.cr_tm;
-       vcpu->arch.xer = vcpu->arch.xer_tm;
-       vcpu->arch.lr  = vcpu->arch.lr_tm;
-       vcpu->arch.ctr = vcpu->arch.ctr_tm;
+       vcpu->arch.regs.xer = vcpu->arch.xer_tm;
+       vcpu->arch.regs.link  = vcpu->arch.lr_tm;
+       vcpu->arch.regs.ctr = vcpu->arch.ctr_tm;
        vcpu->arch.amr = vcpu->arch.amr_tm;
        vcpu->arch.ppr = vcpu->arch.ppr_tm;
        vcpu->arch.dscr = vcpu->arch.dscr_tm;
        vcpu->arch.tar = vcpu->arch.tar_tm;
-       memcpy(vcpu->arch.gpr, vcpu->arch.gpr_tm,
-              sizeof(vcpu->arch.gpr));
+       memcpy(vcpu->arch.regs.gpr, vcpu->arch.gpr_tm,
+              sizeof(vcpu->arch.regs.gpr));
        vcpu->arch.fp  = vcpu->arch.fp_tm;
        vcpu->arch.vr  = vcpu->arch.vr_tm;
        vcpu->arch.vrsave = vcpu->arch.vrsave_tm;
@@ -500,15 +500,15 @@ static inline void copy_from_checkpoint(struct kvm_vcpu *vcpu)
 static inline void copy_to_checkpoint(struct kvm_vcpu *vcpu)
 {
        vcpu->arch.cr_tm  = vcpu->arch.cr;
-       vcpu->arch.xer_tm = vcpu->arch.xer;
-       vcpu->arch.lr_tm  = vcpu->arch.lr;
-       vcpu->arch.ctr_tm = vcpu->arch.ctr;
+       vcpu->arch.xer_tm = vcpu->arch.regs.xer;
+       vcpu->arch.lr_tm  = vcpu->arch.regs.link;
+       vcpu->arch.ctr_tm = vcpu->arch.regs.ctr;
        vcpu->arch.amr_tm = vcpu->arch.amr;
        vcpu->arch.ppr_tm = vcpu->arch.ppr;
        vcpu->arch.dscr_tm = vcpu->arch.dscr;
        vcpu->arch.tar_tm = vcpu->arch.tar;
-       memcpy(vcpu->arch.gpr_tm, vcpu->arch.gpr,
-              sizeof(vcpu->arch.gpr));
+       memcpy(vcpu->arch.gpr_tm, vcpu->arch.regs.gpr,
+              sizeof(vcpu->arch.regs.gpr));
        vcpu->arch.fp_tm  = vcpu->arch.fp;
        vcpu->arch.vr_tm  = vcpu->arch.vr;
        vcpu->arch.vrsave_tm = vcpu->arch.vrsave;
index bc6e29e4dfd4a125406a5736b995b8fa8500052e..d513e3ed1c659c711d4a68e5db5924f720c66833 100644 (file)
 
 static inline void kvmppc_set_gpr(struct kvm_vcpu *vcpu, int num, ulong val)
 {
-       vcpu->arch.gpr[num] = val;
+       vcpu->arch.regs.gpr[num] = val;
 }
 
 static inline ulong kvmppc_get_gpr(struct kvm_vcpu *vcpu, int num)
 {
-       return vcpu->arch.gpr[num];
+       return vcpu->arch.regs.gpr[num];
 }
 
 static inline void kvmppc_set_cr(struct kvm_vcpu *vcpu, u32 val)
@@ -56,12 +56,12 @@ static inline u32 kvmppc_get_cr(struct kvm_vcpu *vcpu)
 
 static inline void kvmppc_set_xer(struct kvm_vcpu *vcpu, ulong val)
 {
-       vcpu->arch.xer = val;
+       vcpu->arch.regs.xer = val;
 }
 
 static inline ulong kvmppc_get_xer(struct kvm_vcpu *vcpu)
 {
-       return vcpu->arch.xer;
+       return vcpu->arch.regs.xer;
 }
 
 static inline bool kvmppc_need_byteswap(struct kvm_vcpu *vcpu)
@@ -72,32 +72,32 @@ static inline bool kvmppc_need_byteswap(struct kvm_vcpu *vcpu)
 
 static inline void kvmppc_set_ctr(struct kvm_vcpu *vcpu, ulong val)
 {
-       vcpu->arch.ctr = val;
+       vcpu->arch.regs.ctr = val;
 }
 
 static inline ulong kvmppc_get_ctr(struct kvm_vcpu *vcpu)
 {
-       return vcpu->arch.ctr;
+       return vcpu->arch.regs.ctr;
 }
 
 static inline void kvmppc_set_lr(struct kvm_vcpu *vcpu, ulong val)
 {
-       vcpu->arch.lr = val;
+       vcpu->arch.regs.link = val;
 }
 
 static inline ulong kvmppc_get_lr(struct kvm_vcpu *vcpu)
 {
-       return vcpu->arch.lr;
+       return vcpu->arch.regs.link;
 }
 
 static inline void kvmppc_set_pc(struct kvm_vcpu *vcpu, ulong val)
 {
-       vcpu->arch.pc = val;
+       vcpu->arch.regs.nip = val;
 }
 
 static inline ulong kvmppc_get_pc(struct kvm_vcpu *vcpu)
 {
-       return vcpu->arch.pc;
+       return vcpu->arch.regs.nip;
 }
 
 static inline ulong kvmppc_get_fault_dar(struct kvm_vcpu *vcpu)
index 17498e9a26e443cb67b6e631f0c5b626f06cfc9a..fa4efa7e88f703b10b7a35a22947f1d98d2c5880 100644 (file)
@@ -269,7 +269,6 @@ struct kvm_arch {
        unsigned long host_lpcr;
        unsigned long sdr1;
        unsigned long host_sdr1;
-       int tlbie_lock;
        unsigned long lpcr;
        unsigned long vrma_slb_v;
        int mmu_ready;
@@ -454,6 +453,12 @@ struct mmio_hpte_cache {
 #define KVMPPC_VSX_COPY_WORD           1
 #define KVMPPC_VSX_COPY_DWORD          2
 #define KVMPPC_VSX_COPY_DWORD_LOAD_DUMP        3
+#define KVMPPC_VSX_COPY_WORD_LOAD_DUMP 4
+
+#define KVMPPC_VMX_COPY_BYTE           8
+#define KVMPPC_VMX_COPY_HWORD          9
+#define KVMPPC_VMX_COPY_WORD           10
+#define KVMPPC_VMX_COPY_DWORD          11
 
 struct openpic;
 
@@ -486,7 +491,7 @@ struct kvm_vcpu_arch {
        struct kvmppc_book3s_shadow_vcpu *shadow_vcpu;
 #endif
 
-       ulong gpr[32];
+       struct pt_regs regs;
 
        struct thread_fp_state fp;
 
@@ -521,14 +526,10 @@ struct kvm_vcpu_arch {
        u32 qpr[32];
 #endif
 
-       ulong pc;
-       ulong ctr;
-       ulong lr;
 #ifdef CONFIG_PPC_BOOK3S
        ulong tar;
 #endif
 
-       ulong xer;
        u32 cr;
 
 #ifdef CONFIG_PPC_BOOK3S
@@ -626,7 +627,6 @@ struct kvm_vcpu_arch {
 
        struct thread_vr_state vr_tm;
        u32 vrsave_tm; /* also USPRG0 */
-
 #endif
 
 #ifdef CONFIG_KVM_EXIT_TIMING
@@ -681,16 +681,17 @@ struct kvm_vcpu_arch {
         * Number of simulations for vsx.
         * If we use 2*8bytes to simulate 1*16bytes,
         * then the number should be 2 and
-        * mmio_vsx_copy_type=KVMPPC_VSX_COPY_DWORD.
+        * mmio_copy_type=KVMPPC_VSX_COPY_DWORD.
         * If we use 4*4bytes to simulate 1*16bytes,
         * the number should be 4 and
         * mmio_vsx_copy_type=KVMPPC_VSX_COPY_WORD.
         */
        u8 mmio_vsx_copy_nums;
        u8 mmio_vsx_offset;
-       u8 mmio_vsx_copy_type;
        u8 mmio_vsx_tx_sx_enabled;
        u8 mmio_vmx_copy_nums;
+       u8 mmio_vmx_offset;
+       u8 mmio_copy_type;
        u8 osi_needed;
        u8 osi_enabled;
        u8 papr_enabled;
@@ -772,6 +773,8 @@ struct kvm_vcpu_arch {
        u64 busy_preempt;
 
        u32 emul_inst;
+
+       u32 online;
 #endif
 
 #ifdef CONFIG_KVM_BOOK3S_HV_EXIT_TIMING
index abe7032cdb541df18eeb9d4981d974216c0ac7a0..e991821dd7fa1ccd422c4f2859892c3f4370b645 100644 (file)
@@ -52,7 +52,7 @@ enum emulation_result {
        EMULATE_EXIT_USER,    /* emulation requires exit to user-space */
 };
 
-enum instruction_type {
+enum instruction_fetch_type {
        INST_GENERIC,
        INST_SC,                /* system call */
 };
@@ -81,10 +81,10 @@ extern int kvmppc_handle_loads(struct kvm_run *run, struct kvm_vcpu *vcpu,
 extern int kvmppc_handle_vsx_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
                                unsigned int rt, unsigned int bytes,
                        int is_default_endian, int mmio_sign_extend);
-extern int kvmppc_handle_load128_by2x64(struct kvm_run *run,
-               struct kvm_vcpu *vcpu, unsigned int rt, int is_default_endian);
-extern int kvmppc_handle_store128_by2x64(struct kvm_run *run,
-               struct kvm_vcpu *vcpu, unsigned int rs, int is_default_endian);
+extern int kvmppc_handle_vmx_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
+               unsigned int rt, unsigned int bytes, int is_default_endian);
+extern int kvmppc_handle_vmx_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
+               unsigned int rs, unsigned int bytes, int is_default_endian);
 extern int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
                               u64 val, unsigned int bytes,
                               int is_default_endian);
@@ -93,7 +93,7 @@ extern int kvmppc_handle_vsx_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
                                int is_default_endian);
 
 extern int kvmppc_load_last_inst(struct kvm_vcpu *vcpu,
-                                enum instruction_type type, u32 *inst);
+                                enum instruction_fetch_type type, u32 *inst);
 
 extern int kvmppc_ld(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr,
                     bool data);
@@ -265,6 +265,8 @@ union kvmppc_one_reg {
        vector128 vval;
        u64     vsxval[2];
        u32     vsx32val[4];
+       u16     vsx16val[8];
+       u8      vsx8val[16];
        struct {
                u64     addr;
                u64     length;
@@ -324,13 +326,14 @@ struct kvmppc_ops {
        int (*get_rmmu_info)(struct kvm *kvm, struct kvm_ppc_rmmu_info *info);
        int (*set_smt_mode)(struct kvm *kvm, unsigned long mode,
                            unsigned long flags);
+       void (*giveup_ext)(struct kvm_vcpu *vcpu, ulong msr);
 };
 
 extern struct kvmppc_ops *kvmppc_hv_ops;
 extern struct kvmppc_ops *kvmppc_pr_ops;
 
 static inline int kvmppc_get_last_inst(struct kvm_vcpu *vcpu,
-                                       enum instruction_type type, u32 *inst)
+                               enum instruction_fetch_type type, u32 *inst)
 {
        int ret = EMULATE_DONE;
        u32 fetched_inst;
index 75c5b2cd9d667fefa2e0f628b5a06c9a2489ad3a..562568414cf42ace1e40a012ced84d17abff7295 100644 (file)
 #define SPRN_PSSCR     0x357   /* Processor Stop Status and Control Register (ISA 3.0) */
 #define SPRN_PSSCR_PR  0x337   /* PSSCR ISA 3.0, privileged mode access */
 #define SPRN_PMCR      0x374   /* Power Management Control Register */
+#define SPRN_RWMR      0x375   /* Region-Weighting Mode Register */
 
 /* HFSCR and FSCR bit numbers are the same */
 #define FSCR_SCV_LG    12      /* Enable System Call Vectored */
index 833ed9a16adfd03e0b6cb70adc19fe03055f7344..1b32b56a03d34ce2a5f0b7f79c621f87d8c89dbf 100644 (file)
@@ -633,6 +633,7 @@ struct kvm_ppc_cpu_char {
 #define KVM_REG_PPC_PSSCR      (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xbd)
 
 #define KVM_REG_PPC_DEC_EXPIRY (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xbe)
+#define KVM_REG_PPC_ONLINE     (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xbf)
 
 /* Transactional Memory checkpointed state:
  * This is all GPRs, all VSX regs and a subset of SPRs
index 9fc9e097700990cec7bce9e3e0ac478cfcc31de7..0a05443359503c9f375e2a47953dd8f3aa118bbf 100644 (file)
@@ -426,20 +426,20 @@ int main(void)
        OFFSET(VCPU_HOST_STACK, kvm_vcpu, arch.host_stack);
        OFFSET(VCPU_HOST_PID, kvm_vcpu, arch.host_pid);
        OFFSET(VCPU_GUEST_PID, kvm_vcpu, arch.pid);
-       OFFSET(VCPU_GPRS, kvm_vcpu, arch.gpr);
+       OFFSET(VCPU_GPRS, kvm_vcpu, arch.regs.gpr);
        OFFSET(VCPU_VRSAVE, kvm_vcpu, arch.vrsave);
        OFFSET(VCPU_FPRS, kvm_vcpu, arch.fp.fpr);
 #ifdef CONFIG_ALTIVEC
        OFFSET(VCPU_VRS, kvm_vcpu, arch.vr.vr);
 #endif
-       OFFSET(VCPU_XER, kvm_vcpu, arch.xer);
-       OFFSET(VCPU_CTR, kvm_vcpu, arch.ctr);
-       OFFSET(VCPU_LR, kvm_vcpu, arch.lr);
+       OFFSET(VCPU_XER, kvm_vcpu, arch.regs.xer);
+       OFFSET(VCPU_CTR, kvm_vcpu, arch.regs.ctr);
+       OFFSET(VCPU_LR, kvm_vcpu, arch.regs.link);
 #ifdef CONFIG_PPC_BOOK3S
        OFFSET(VCPU_TAR, kvm_vcpu, arch.tar);
 #endif
        OFFSET(VCPU_CR, kvm_vcpu, arch.cr);
-       OFFSET(VCPU_PC, kvm_vcpu, arch.pc);
+       OFFSET(VCPU_PC, kvm_vcpu, arch.regs.nip);
 #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
        OFFSET(VCPU_MSR, kvm_vcpu, arch.shregs.msr);
        OFFSET(VCPU_SRR0, kvm_vcpu, arch.shregs.srr0);
@@ -696,10 +696,10 @@ int main(void)
 
 #else /* CONFIG_PPC_BOOK3S */
        OFFSET(VCPU_CR, kvm_vcpu, arch.cr);
-       OFFSET(VCPU_XER, kvm_vcpu, arch.xer);
-       OFFSET(VCPU_LR, kvm_vcpu, arch.lr);
-       OFFSET(VCPU_CTR, kvm_vcpu, arch.ctr);
-       OFFSET(VCPU_PC, kvm_vcpu, arch.pc);
+       OFFSET(VCPU_XER, kvm_vcpu, arch.regs.xer);
+       OFFSET(VCPU_LR, kvm_vcpu, arch.regs.link);
+       OFFSET(VCPU_CTR, kvm_vcpu, arch.regs.ctr);
+       OFFSET(VCPU_PC, kvm_vcpu, arch.regs.nip);
        OFFSET(VCPU_SPRG9, kvm_vcpu, arch.sprg9);
        OFFSET(VCPU_LAST_INST, kvm_vcpu, arch.last_inst);
        OFFSET(VCPU_FAULT_DEAR, kvm_vcpu, arch.fault_dear);
index 4b19da8c87aedfac4435c68e18f797c197e834a5..f872c04bb5b1bb1185a7fcc9df1597540d3d3120 100644 (file)
@@ -63,6 +63,9 @@ kvm-pr-y := \
        book3s_64_mmu.o \
        book3s_32_mmu.o
 
+kvm-book3s_64-builtin-objs-$(CONFIG_KVM_BOOK3S_64_HANDLER) += \
+       tm.o
+
 ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE
 kvm-book3s_64-builtin-objs-$(CONFIG_KVM_BOOK3S_64_HANDLER) += \
        book3s_rmhandlers.o
index 97d4a112648fd6540948fc1564f1a77d698f65bc..edaf4720d1567abfd4e44a9ed2dab424c6e6c920 100644 (file)
@@ -134,7 +134,7 @@ void kvmppc_inject_interrupt(struct kvm_vcpu *vcpu, int vec, u64 flags)
 {
        kvmppc_unfixup_split_real(vcpu);
        kvmppc_set_srr0(vcpu, kvmppc_get_pc(vcpu));
-       kvmppc_set_srr1(vcpu, kvmppc_get_msr(vcpu) | flags);
+       kvmppc_set_srr1(vcpu, (kvmppc_get_msr(vcpu) & ~0x783f0000ul) | flags);
        kvmppc_set_pc(vcpu, kvmppc_interrupt_offset(vcpu) + vec);
        vcpu->arch.mmu.reset_msr(vcpu);
 }
@@ -256,18 +256,15 @@ void kvmppc_core_queue_data_storage(struct kvm_vcpu *vcpu, ulong dar,
 {
        kvmppc_set_dar(vcpu, dar);
        kvmppc_set_dsisr(vcpu, flags);
-       kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_DATA_STORAGE);
+       kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_DATA_STORAGE, 0);
 }
-EXPORT_SYMBOL_GPL(kvmppc_core_queue_data_storage);     /* used by kvm_hv */
+EXPORT_SYMBOL_GPL(kvmppc_core_queue_data_storage);
 
 void kvmppc_core_queue_inst_storage(struct kvm_vcpu *vcpu, ulong flags)
 {
-       u64 msr = kvmppc_get_msr(vcpu);
-       msr &= ~(SRR1_ISI_NOPT | SRR1_ISI_N_OR_G | SRR1_ISI_PROT);
-       msr |= flags & (SRR1_ISI_NOPT | SRR1_ISI_N_OR_G | SRR1_ISI_PROT);
-       kvmppc_set_msr_fast(vcpu, msr);
-       kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_INST_STORAGE);
+       kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_INST_STORAGE, flags);
 }
+EXPORT_SYMBOL_GPL(kvmppc_core_queue_inst_storage);
 
 static int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu,
                                         unsigned int priority)
@@ -450,8 +447,8 @@ int kvmppc_xlate(struct kvm_vcpu *vcpu, ulong eaddr, enum xlate_instdata xlid,
        return r;
 }
 
-int kvmppc_load_last_inst(struct kvm_vcpu *vcpu, enum instruction_type type,
-                                        u32 *inst)
+int kvmppc_load_last_inst(struct kvm_vcpu *vcpu,
+               enum instruction_fetch_type type, u32 *inst)
 {
        ulong pc = kvmppc_get_pc(vcpu);
        int r;
@@ -509,8 +506,6 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 {
        int i;
 
-       vcpu_load(vcpu);
-
        regs->pc = kvmppc_get_pc(vcpu);
        regs->cr = kvmppc_get_cr(vcpu);
        regs->ctr = kvmppc_get_ctr(vcpu);
@@ -532,7 +527,6 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
        for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
                regs->gpr[i] = kvmppc_get_gpr(vcpu, i);
 
-       vcpu_put(vcpu);
        return 0;
 }
 
@@ -540,8 +534,6 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 {
        int i;
 
-       vcpu_load(vcpu);
-
        kvmppc_set_pc(vcpu, regs->pc);
        kvmppc_set_cr(vcpu, regs->cr);
        kvmppc_set_ctr(vcpu, regs->ctr);
@@ -562,7 +554,6 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
        for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
                kvmppc_set_gpr(vcpu, i, regs->gpr[i]);
 
-       vcpu_put(vcpu);
        return 0;
 }
 
index 4ad5e287b8bc68f1267cfc163a1c07793e530b4e..14ef03501d2191c42b9dcbd23d6200728b2113db 100644 (file)
@@ -31,4 +31,10 @@ extern int kvmppc_core_emulate_mfspr_pr(struct kvm_vcpu *vcpu,
 extern int kvmppc_book3s_init_pr(void);
 extern void kvmppc_book3s_exit_pr(void);
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+extern void kvmppc_emulate_tabort(struct kvm_vcpu *vcpu, int ra_val);
+#else
+static inline void kvmppc_emulate_tabort(struct kvm_vcpu *vcpu, int ra_val) {}
+#endif
+
 #endif
index 1992676c7a9479f00fe9717b7ff16aeb5204ae8b..45c8ea4a04879f140fcf037a3b33225a75b538cd 100644 (file)
@@ -52,7 +52,7 @@
 static inline bool check_debug_ip(struct kvm_vcpu *vcpu)
 {
 #ifdef DEBUG_MMU_PTE_IP
-       return vcpu->arch.pc == DEBUG_MMU_PTE_IP;
+       return vcpu->arch.regs.nip == DEBUG_MMU_PTE_IP;
 #else
        return true;
 #endif
index a93d719edc906887b0f4bf412b2b76ac04babfec..cf9d686e81621fca1628ae772cb5150b2cb1209d 100644 (file)
 
 static void kvmppc_mmu_book3s_64_reset_msr(struct kvm_vcpu *vcpu)
 {
-       kvmppc_set_msr(vcpu, vcpu->arch.intr_msr);
+       unsigned long msr = vcpu->arch.intr_msr;
+       unsigned long cur_msr = kvmppc_get_msr(vcpu);
+
+       /* If transactional, change to suspend mode on IRQ delivery */
+       if (MSR_TM_TRANSACTIONAL(cur_msr))
+               msr |= MSR_TS_S;
+       else
+               msr |= cur_msr & MSR_TS_MASK;
+
+       kvmppc_set_msr(vcpu, msr);
 }
 
 static struct kvmppc_slb *kvmppc_mmu_book3s_64_find_slbe(
index 1b3fcafc685e25cec0bf7dc045e0895d977a5608..7f3a8cf5d66f338197e84446f8a6685855fff9e2 100644 (file)
@@ -272,6 +272,9 @@ int kvmppc_mmu_hv_init(void)
        if (!cpu_has_feature(CPU_FTR_HVMODE))
                return -EINVAL;
 
+       if (!mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE))
+               return -EINVAL;
+
        /* POWER7 has 10-bit LPIDs (12-bit in POWER8) */
        host_lpid = mfspr(SPRN_LPID);
        rsvd_lpid = LPID_RSVD;
index 481da8f93fa449ac9cb3261755a3d1eeee152006..176f911ee983a6347b9643b925bfcfedb21b9809 100644 (file)
@@ -139,44 +139,24 @@ int kvmppc_mmu_radix_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
        return 0;
 }
 
-#ifdef CONFIG_PPC_64K_PAGES
-#define MMU_BASE_PSIZE MMU_PAGE_64K
-#else
-#define MMU_BASE_PSIZE MMU_PAGE_4K
-#endif
-
 static void kvmppc_radix_tlbie_page(struct kvm *kvm, unsigned long addr,
                                    unsigned int pshift)
 {
-       int psize = MMU_BASE_PSIZE;
-
-       if (pshift >= PUD_SHIFT)
-               psize = MMU_PAGE_1G;
-       else if (pshift >= PMD_SHIFT)
-               psize = MMU_PAGE_2M;
-       addr &= ~0xfffUL;
-       addr |= mmu_psize_defs[psize].ap << 5;
-       asm volatile("ptesync": : :"memory");
-       asm volatile(PPC_TLBIE_5(%0, %1, 0, 0, 1)
-                    : : "r" (addr), "r" (kvm->arch.lpid) : "memory");
-       if (cpu_has_feature(CPU_FTR_P9_TLBIE_BUG))
-               asm volatile(PPC_TLBIE_5(%0, %1, 0, 0, 1)
-                            : : "r" (addr), "r" (kvm->arch.lpid) : "memory");
-       asm volatile("eieio ; tlbsync ; ptesync": : :"memory");
+       unsigned long psize = PAGE_SIZE;
+
+       if (pshift)
+               psize = 1UL << pshift;
+
+       addr &= ~(psize - 1);
+       radix__flush_tlb_lpid_page(kvm->arch.lpid, addr, psize);
 }
 
-static void kvmppc_radix_flush_pwc(struct kvm *kvm, unsigned long addr)
+static void kvmppc_radix_flush_pwc(struct kvm *kvm)
 {
-       unsigned long rb = 0x2 << PPC_BITLSHIFT(53); /* IS = 2 */
-
-       asm volatile("ptesync": : :"memory");
-       /* RIC=1 PRS=0 R=1 IS=2 */
-       asm volatile(PPC_TLBIE_5(%0, %1, 1, 0, 1)
-                    : : "r" (rb), "r" (kvm->arch.lpid) : "memory");
-       asm volatile("eieio ; tlbsync ; ptesync": : :"memory");
+       radix__flush_pwc_lpid(kvm->arch.lpid);
 }
 
-unsigned long kvmppc_radix_update_pte(struct kvm *kvm, pte_t *ptep,
+static unsigned long kvmppc_radix_update_pte(struct kvm *kvm, pte_t *ptep,
                                      unsigned long clr, unsigned long set,
                                      unsigned long addr, unsigned int shift)
 {
@@ -228,6 +208,167 @@ static void kvmppc_pmd_free(pmd_t *pmdp)
        kmem_cache_free(kvm_pmd_cache, pmdp);
 }
 
+static void kvmppc_unmap_pte(struct kvm *kvm, pte_t *pte,
+                            unsigned long gpa, unsigned int shift)
+
+{
+       unsigned long page_size = 1ul << shift;
+       unsigned long old;
+
+       old = kvmppc_radix_update_pte(kvm, pte, ~0UL, 0, gpa, shift);
+       kvmppc_radix_tlbie_page(kvm, gpa, shift);
+       if (old & _PAGE_DIRTY) {
+               unsigned long gfn = gpa >> PAGE_SHIFT;
+               struct kvm_memory_slot *memslot;
+
+               memslot = gfn_to_memslot(kvm, gfn);
+               if (memslot && memslot->dirty_bitmap)
+                       kvmppc_update_dirty_map(memslot, gfn, page_size);
+       }
+}
+
+/*
+ * kvmppc_free_p?d are used to free existing page tables, and recursively
+ * descend and clear and free children.
+ * Callers are responsible for flushing the PWC.
+ *
+ * When page tables are being unmapped/freed as part of page fault path
+ * (full == false), ptes are not expected. There is code to unmap them
+ * and emit a warning if encountered, but there may already be data
+ * corruption due to the unexpected mappings.
+ */
+static void kvmppc_unmap_free_pte(struct kvm *kvm, pte_t *pte, bool full)
+{
+       if (full) {
+               memset(pte, 0, sizeof(long) << PTE_INDEX_SIZE);
+       } else {
+               pte_t *p = pte;
+               unsigned long it;
+
+               for (it = 0; it < PTRS_PER_PTE; ++it, ++p) {
+                       if (pte_val(*p) == 0)
+                               continue;
+                       WARN_ON_ONCE(1);
+                       kvmppc_unmap_pte(kvm, p,
+                                        pte_pfn(*p) << PAGE_SHIFT,
+                                        PAGE_SHIFT);
+               }
+       }
+
+       kvmppc_pte_free(pte);
+}
+
+static void kvmppc_unmap_free_pmd(struct kvm *kvm, pmd_t *pmd, bool full)
+{
+       unsigned long im;
+       pmd_t *p = pmd;
+
+       for (im = 0; im < PTRS_PER_PMD; ++im, ++p) {
+               if (!pmd_present(*p))
+                       continue;
+               if (pmd_is_leaf(*p)) {
+                       if (full) {
+                               pmd_clear(p);
+                       } else {
+                               WARN_ON_ONCE(1);
+                               kvmppc_unmap_pte(kvm, (pte_t *)p,
+                                        pte_pfn(*(pte_t *)p) << PAGE_SHIFT,
+                                        PMD_SHIFT);
+                       }
+               } else {
+                       pte_t *pte;
+
+                       pte = pte_offset_map(p, 0);
+                       kvmppc_unmap_free_pte(kvm, pte, full);
+                       pmd_clear(p);
+               }
+       }
+       kvmppc_pmd_free(pmd);
+}
+
+static void kvmppc_unmap_free_pud(struct kvm *kvm, pud_t *pud)
+{
+       unsigned long iu;
+       pud_t *p = pud;
+
+       for (iu = 0; iu < PTRS_PER_PUD; ++iu, ++p) {
+               if (!pud_present(*p))
+                       continue;
+               if (pud_huge(*p)) {
+                       pud_clear(p);
+               } else {
+                       pmd_t *pmd;
+
+                       pmd = pmd_offset(p, 0);
+                       kvmppc_unmap_free_pmd(kvm, pmd, true);
+                       pud_clear(p);
+               }
+       }
+       pud_free(kvm->mm, pud);
+}
+
+void kvmppc_free_radix(struct kvm *kvm)
+{
+       unsigned long ig;
+       pgd_t *pgd;
+
+       if (!kvm->arch.pgtable)
+               return;
+       pgd = kvm->arch.pgtable;
+       for (ig = 0; ig < PTRS_PER_PGD; ++ig, ++pgd) {
+               pud_t *pud;
+
+               if (!pgd_present(*pgd))
+                       continue;
+               pud = pud_offset(pgd, 0);
+               kvmppc_unmap_free_pud(kvm, pud);
+               pgd_clear(pgd);
+       }
+       pgd_free(kvm->mm, kvm->arch.pgtable);
+       kvm->arch.pgtable = NULL;
+}
+
+static void kvmppc_unmap_free_pmd_entry_table(struct kvm *kvm, pmd_t *pmd,
+                                             unsigned long gpa)
+{
+       pte_t *pte = pte_offset_kernel(pmd, 0);
+
+       /*
+        * Clearing the pmd entry then flushing the PWC ensures that the pte
+        * page no longer be cached by the MMU, so can be freed without
+        * flushing the PWC again.
+        */
+       pmd_clear(pmd);
+       kvmppc_radix_flush_pwc(kvm);
+
+       kvmppc_unmap_free_pte(kvm, pte, false);
+}
+
+static void kvmppc_unmap_free_pud_entry_table(struct kvm *kvm, pud_t *pud,
+                                       unsigned long gpa)
+{
+       pmd_t *pmd = pmd_offset(pud, 0);
+
+       /*
+        * Clearing the pud entry then flushing the PWC ensures that the pmd
+        * page and any children pte pages will no longer be cached by the MMU,
+        * so can be freed without flushing the PWC again.
+        */
+       pud_clear(pud);
+       kvmppc_radix_flush_pwc(kvm);
+
+       kvmppc_unmap_free_pmd(kvm, pmd, false);
+}
+
+/*
+ * There are a number of bits which may differ between different faults to
+ * the same partition scope entry. RC bits, in the course of cleaning and
+ * aging. And the write bit can change, either the access could have been
+ * upgraded, or a read fault could happen concurrently with a write fault
+ * that sets those bits first.
+ */
+#define PTE_BITS_MUST_MATCH (~(_PAGE_WRITE | _PAGE_DIRTY | _PAGE_ACCESSED))
+
 static int kvmppc_create_pte(struct kvm *kvm, pte_t pte, unsigned long gpa,
                             unsigned int level, unsigned long mmu_seq)
 {
@@ -235,7 +376,6 @@ static int kvmppc_create_pte(struct kvm *kvm, pte_t pte, unsigned long gpa,
        pud_t *pud, *new_pud = NULL;
        pmd_t *pmd, *new_pmd = NULL;
        pte_t *ptep, *new_ptep = NULL;
-       unsigned long old;
        int ret;
 
        /* Traverse the guest's 2nd-level tree, allocate new levels needed */
@@ -273,42 +413,39 @@ static int kvmppc_create_pte(struct kvm *kvm, pte_t pte, unsigned long gpa,
        if (pud_huge(*pud)) {
                unsigned long hgpa = gpa & PUD_MASK;
 
+               /* Check if we raced and someone else has set the same thing */
+               if (level == 2) {
+                       if (pud_raw(*pud) == pte_raw(pte)) {
+                               ret = 0;
+                               goto out_unlock;
+                       }
+                       /* Valid 1GB page here already, add our extra bits */
+                       WARN_ON_ONCE((pud_val(*pud) ^ pte_val(pte)) &
+                                                       PTE_BITS_MUST_MATCH);
+                       kvmppc_radix_update_pte(kvm, (pte_t *)pud,
+                                             0, pte_val(pte), hgpa, PUD_SHIFT);
+                       ret = 0;
+                       goto out_unlock;
+               }
                /*
                 * If we raced with another CPU which has just put
                 * a 1GB pte in after we saw a pmd page, try again.
                 */
-               if (level <= 1 && !new_pmd) {
+               if (!new_pmd) {
                        ret = -EAGAIN;
                        goto out_unlock;
                }
-               /* Check if we raced and someone else has set the same thing */
-               if (level == 2 && pud_raw(*pud) == pte_raw(pte)) {
-                       ret = 0;
-                       goto out_unlock;
-               }
                /* Valid 1GB page here already, remove it */
-               old = kvmppc_radix_update_pte(kvm, (pte_t *)pud,
-                                             ~0UL, 0, hgpa, PUD_SHIFT);
-               kvmppc_radix_tlbie_page(kvm, hgpa, PUD_SHIFT);
-               if (old & _PAGE_DIRTY) {
-                       unsigned long gfn = hgpa >> PAGE_SHIFT;
-                       struct kvm_memory_slot *memslot;
-                       memslot = gfn_to_memslot(kvm, gfn);
-                       if (memslot && memslot->dirty_bitmap)
-                               kvmppc_update_dirty_map(memslot,
-                                                       gfn, PUD_SIZE);
-               }
+               kvmppc_unmap_pte(kvm, (pte_t *)pud, hgpa, PUD_SHIFT);
        }
        if (level == 2) {
                if (!pud_none(*pud)) {
                        /*
                         * There's a page table page here, but we wanted to
                         * install a large page, so remove and free the page
-                        * table page.  new_pmd will be NULL since level == 2.
+                        * table page.
                         */
-                       new_pmd = pmd_offset(pud, 0);
-                       pud_clear(pud);
-                       kvmppc_radix_flush_pwc(kvm, gpa);
+                       kvmppc_unmap_free_pud_entry_table(kvm, pud, gpa);
                }
                kvmppc_radix_set_pte_at(kvm, gpa, (pte_t *)pud, pte);
                ret = 0;
@@ -324,42 +461,40 @@ static int kvmppc_create_pte(struct kvm *kvm, pte_t pte, unsigned long gpa,
        if (pmd_is_leaf(*pmd)) {
                unsigned long lgpa = gpa & PMD_MASK;
 
+               /* Check if we raced and someone else has set the same thing */
+               if (level == 1) {
+                       if (pmd_raw(*pmd) == pte_raw(pte)) {
+                               ret = 0;
+                               goto out_unlock;
+                       }
+                       /* Valid 2MB page here already, add our extra bits */
+                       WARN_ON_ONCE((pmd_val(*pmd) ^ pte_val(pte)) &
+                                                       PTE_BITS_MUST_MATCH);
+                       kvmppc_radix_update_pte(kvm, pmdp_ptep(pmd),
+                                             0, pte_val(pte), lgpa, PMD_SHIFT);
+                       ret = 0;
+                       goto out_unlock;
+               }
+
                /*
                 * If we raced with another CPU which has just put
                 * a 2MB pte in after we saw a pte page, try again.
                 */
-               if (level == 0 && !new_ptep) {
+               if (!new_ptep) {
                        ret = -EAGAIN;
                        goto out_unlock;
                }
-               /* Check if we raced and someone else has set the same thing */
-               if (level == 1 && pmd_raw(*pmd) == pte_raw(pte)) {
-                       ret = 0;
-                       goto out_unlock;
-               }
                /* Valid 2MB page here already, remove it */
-               old = kvmppc_radix_update_pte(kvm, pmdp_ptep(pmd),
-                                             ~0UL, 0, lgpa, PMD_SHIFT);
-               kvmppc_radix_tlbie_page(kvm, lgpa, PMD_SHIFT);
-               if (old & _PAGE_DIRTY) {
-                       unsigned long gfn = lgpa >> PAGE_SHIFT;
-                       struct kvm_memory_slot *memslot;
-                       memslot = gfn_to_memslot(kvm, gfn);
-                       if (memslot && memslot->dirty_bitmap)
-                               kvmppc_update_dirty_map(memslot,
-                                                       gfn, PMD_SIZE);
-               }
+               kvmppc_unmap_pte(kvm, pmdp_ptep(pmd), lgpa, PMD_SHIFT);
        }
        if (level == 1) {
                if (!pmd_none(*pmd)) {
                        /*
                         * There's a page table page here, but we wanted to
                         * install a large page, so remove and free the page
-                        * table page.  new_ptep will be NULL since level == 1.
+                        * table page.
                         */
-                       new_ptep = pte_offset_kernel(pmd, 0);
-                       pmd_clear(pmd);
-                       kvmppc_radix_flush_pwc(kvm, gpa);
+                       kvmppc_unmap_free_pmd_entry_table(kvm, pmd, gpa);
                }
                kvmppc_radix_set_pte_at(kvm, gpa, pmdp_ptep(pmd), pte);
                ret = 0;
@@ -378,12 +513,12 @@ static int kvmppc_create_pte(struct kvm *kvm, pte_t pte, unsigned long gpa,
                        ret = 0;
                        goto out_unlock;
                }
-               /* PTE was previously valid, so invalidate it */
-               old = kvmppc_radix_update_pte(kvm, ptep, _PAGE_PRESENT,
-                                             0, gpa, 0);
-               kvmppc_radix_tlbie_page(kvm, gpa, 0);
-               if (old & _PAGE_DIRTY)
-                       mark_page_dirty(kvm, gpa >> PAGE_SHIFT);
+               /* Valid page here already, add our extra bits */
+               WARN_ON_ONCE((pte_val(*ptep) ^ pte_val(pte)) &
+                                                       PTE_BITS_MUST_MATCH);
+               kvmppc_radix_update_pte(kvm, ptep, 0, pte_val(pte), gpa, 0);
+               ret = 0;
+               goto out_unlock;
        }
        kvmppc_radix_set_pte_at(kvm, gpa, ptep, pte);
        ret = 0;
@@ -565,9 +700,13 @@ int kvmppc_book3s_radix_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
                        unsigned long mask = (1ul << shift) - PAGE_SIZE;
                        pte = __pte(pte_val(pte) | (hva & mask));
                }
-               if (!(writing || upgrade_write))
-                       pte = __pte(pte_val(pte) & ~ _PAGE_WRITE);
-               pte = __pte(pte_val(pte) | _PAGE_EXEC);
+               pte = __pte(pte_val(pte) | _PAGE_EXEC | _PAGE_ACCESSED);
+               if (writing || upgrade_write) {
+                       if (pte_val(pte) & _PAGE_WRITE)
+                               pte = __pte(pte_val(pte) | _PAGE_DIRTY);
+               } else {
+                       pte = __pte(pte_val(pte) & ~(_PAGE_WRITE | _PAGE_DIRTY));
+               }
        }
 
        /* Allocate space in the tree and write the PTE */
@@ -734,51 +873,6 @@ int kvmppc_init_vm_radix(struct kvm *kvm)
        return 0;
 }
 
-void kvmppc_free_radix(struct kvm *kvm)
-{
-       unsigned long ig, iu, im;
-       pte_t *pte;
-       pmd_t *pmd;
-       pud_t *pud;
-       pgd_t *pgd;
-
-       if (!kvm->arch.pgtable)
-               return;
-       pgd = kvm->arch.pgtable;
-       for (ig = 0; ig < PTRS_PER_PGD; ++ig, ++pgd) {
-               if (!pgd_present(*pgd))
-                       continue;
-               pud = pud_offset(pgd, 0);
-               for (iu = 0; iu < PTRS_PER_PUD; ++iu, ++pud) {
-                       if (!pud_present(*pud))
-                               continue;
-                       if (pud_huge(*pud)) {
-                               pud_clear(pud);
-                               continue;
-                       }
-                       pmd = pmd_offset(pud, 0);
-                       for (im = 0; im < PTRS_PER_PMD; ++im, ++pmd) {
-                               if (pmd_is_leaf(*pmd)) {
-                                       pmd_clear(pmd);
-                                       continue;
-                               }
-                               if (!pmd_present(*pmd))
-                                       continue;
-                               pte = pte_offset_map(pmd, 0);
-                               memset(pte, 0, sizeof(long) << PTE_INDEX_SIZE);
-                               kvmppc_pte_free(pte);
-                               pmd_clear(pmd);
-                       }
-                       kvmppc_pmd_free(pmd_offset(pud, 0));
-                       pud_clear(pud);
-               }
-               pud_free(kvm->mm, pud_offset(pgd, 0));
-               pgd_clear(pgd);
-       }
-       pgd_free(kvm->mm, kvm->arch.pgtable);
-       kvm->arch.pgtable = NULL;
-}
-
 static void pte_ctor(void *addr)
 {
        memset(addr, 0, RADIX_PTE_TABLE_SIZE);
index 4dffa611376d67850ac4ef8730a547fcccf63491..d066e37551ec861c1d71a8a958784fd792e2dae6 100644 (file)
@@ -176,14 +176,12 @@ extern long kvm_spapr_tce_attach_iommu_group(struct kvm *kvm, int tablefd,
 
                if (!tbltmp)
                        continue;
-               /*
-                * Make sure hardware table parameters are exactly the same;
-                * this is used in the TCE handlers where boundary checks
-                * use only the first attached table.
-                */
-               if ((tbltmp->it_page_shift == stt->page_shift) &&
-                               (tbltmp->it_offset == stt->offset) &&
-                               (tbltmp->it_size == stt->size)) {
+               /* Make sure hardware table parameters are compatible */
+               if ((tbltmp->it_page_shift <= stt->page_shift) &&
+                               (tbltmp->it_offset << tbltmp->it_page_shift ==
+                                stt->offset << stt->page_shift) &&
+                               (tbltmp->it_size << tbltmp->it_page_shift ==
+                                stt->size << stt->page_shift)) {
                        /*
                         * Reference the table to avoid races with
                         * add/remove DMA windows.
@@ -237,7 +235,7 @@ static void release_spapr_tce_table(struct rcu_head *head)
        kfree(stt);
 }
 
-static int kvm_spapr_tce_fault(struct vm_fault *vmf)
+static vm_fault_t kvm_spapr_tce_fault(struct vm_fault *vmf)
 {
        struct kvmppc_spapr_tce_table *stt = vmf->vma->vm_file->private_data;
        struct page *page;
@@ -302,7 +300,8 @@ long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm,
        int ret = -ENOMEM;
        int i;
 
-       if (!args->size)
+       if (!args->size || args->page_shift < 12 || args->page_shift > 34 ||
+               (args->offset + args->size > (ULLONG_MAX >> args->page_shift)))
                return -EINVAL;
 
        size = _ALIGN_UP(args->size, PAGE_SIZE >> 3);
@@ -396,7 +395,7 @@ static long kvmppc_tce_iommu_mapped_dec(struct kvm *kvm,
        return H_SUCCESS;
 }
 
-static long kvmppc_tce_iommu_unmap(struct kvm *kvm,
+static long kvmppc_tce_iommu_do_unmap(struct kvm *kvm,
                struct iommu_table *tbl, unsigned long entry)
 {
        enum dma_data_direction dir = DMA_NONE;
@@ -416,7 +415,24 @@ static long kvmppc_tce_iommu_unmap(struct kvm *kvm,
        return ret;
 }
 
-long kvmppc_tce_iommu_map(struct kvm *kvm, struct iommu_table *tbl,
+static long kvmppc_tce_iommu_unmap(struct kvm *kvm,
+               struct kvmppc_spapr_tce_table *stt, struct iommu_table *tbl,
+               unsigned long entry)
+{
+       unsigned long i, ret = H_SUCCESS;
+       unsigned long subpages = 1ULL << (stt->page_shift - tbl->it_page_shift);
+       unsigned long io_entry = entry * subpages;
+
+       for (i = 0; i < subpages; ++i) {
+               ret = kvmppc_tce_iommu_do_unmap(kvm, tbl, io_entry + i);
+               if (ret != H_SUCCESS)
+                       break;
+       }
+
+       return ret;
+}
+
+long kvmppc_tce_iommu_do_map(struct kvm *kvm, struct iommu_table *tbl,
                unsigned long entry, unsigned long ua,
                enum dma_data_direction dir)
 {
@@ -453,6 +469,27 @@ long kvmppc_tce_iommu_map(struct kvm *kvm, struct iommu_table *tbl,
        return 0;
 }
 
+static long kvmppc_tce_iommu_map(struct kvm *kvm,
+               struct kvmppc_spapr_tce_table *stt, struct iommu_table *tbl,
+               unsigned long entry, unsigned long ua,
+               enum dma_data_direction dir)
+{
+       unsigned long i, pgoff, ret = H_SUCCESS;
+       unsigned long subpages = 1ULL << (stt->page_shift - tbl->it_page_shift);
+       unsigned long io_entry = entry * subpages;
+
+       for (i = 0, pgoff = 0; i < subpages;
+                       ++i, pgoff += IOMMU_PAGE_SIZE(tbl)) {
+
+               ret = kvmppc_tce_iommu_do_map(kvm, tbl,
+                               io_entry + i, ua + pgoff, dir);
+               if (ret != H_SUCCESS)
+                       break;
+       }
+
+       return ret;
+}
+
 long kvmppc_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
                      unsigned long ioba, unsigned long tce)
 {
@@ -491,10 +528,10 @@ long kvmppc_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
 
        list_for_each_entry_lockless(stit, &stt->iommu_tables, next) {
                if (dir == DMA_NONE)
-                       ret = kvmppc_tce_iommu_unmap(vcpu->kvm,
+                       ret = kvmppc_tce_iommu_unmap(vcpu->kvm, stt,
                                        stit->tbl, entry);
                else
-                       ret = kvmppc_tce_iommu_map(vcpu->kvm, stit->tbl,
+                       ret = kvmppc_tce_iommu_map(vcpu->kvm, stt, stit->tbl,
                                        entry, ua, dir);
 
                if (ret == H_SUCCESS)
@@ -570,7 +607,7 @@ long kvmppc_h_put_tce_indirect(struct kvm_vcpu *vcpu,
                        return H_PARAMETER;
 
                list_for_each_entry_lockless(stit, &stt->iommu_tables, next) {
-                       ret = kvmppc_tce_iommu_map(vcpu->kvm,
+                       ret = kvmppc_tce_iommu_map(vcpu->kvm, stt,
                                        stit->tbl, entry + i, ua,
                                        iommu_tce_direction(tce));
 
@@ -615,10 +652,10 @@ long kvmppc_h_stuff_tce(struct kvm_vcpu *vcpu,
                return H_PARAMETER;
 
        list_for_each_entry_lockless(stit, &stt->iommu_tables, next) {
-               unsigned long entry = ioba >> stit->tbl->it_page_shift;
+               unsigned long entry = ioba >> stt->page_shift;
 
                for (i = 0; i < npages; ++i) {
-                       ret = kvmppc_tce_iommu_unmap(vcpu->kvm,
+                       ret = kvmppc_tce_iommu_unmap(vcpu->kvm, stt,
                                        stit->tbl, entry + i);
 
                        if (ret == H_SUCCESS)
index 6651f736a0b1e449e4be6384169e1ced35eff89f..925fc316a104cc1ce33b6630cf9aaa46ffde7c0c 100644 (file)
@@ -221,7 +221,7 @@ static long kvmppc_rm_tce_iommu_mapped_dec(struct kvm *kvm,
        return H_SUCCESS;
 }
 
-static long kvmppc_rm_tce_iommu_unmap(struct kvm *kvm,
+static long kvmppc_rm_tce_iommu_do_unmap(struct kvm *kvm,
                struct iommu_table *tbl, unsigned long entry)
 {
        enum dma_data_direction dir = DMA_NONE;
@@ -245,7 +245,24 @@ static long kvmppc_rm_tce_iommu_unmap(struct kvm *kvm,
        return ret;
 }
 
-static long kvmppc_rm_tce_iommu_map(struct kvm *kvm, struct iommu_table *tbl,
+static long kvmppc_rm_tce_iommu_unmap(struct kvm *kvm,
+               struct kvmppc_spapr_tce_table *stt, struct iommu_table *tbl,
+               unsigned long entry)
+{
+       unsigned long i, ret = H_SUCCESS;
+       unsigned long subpages = 1ULL << (stt->page_shift - tbl->it_page_shift);
+       unsigned long io_entry = entry * subpages;
+
+       for (i = 0; i < subpages; ++i) {
+               ret = kvmppc_rm_tce_iommu_do_unmap(kvm, tbl, io_entry + i);
+               if (ret != H_SUCCESS)
+                       break;
+       }
+
+       return ret;
+}
+
+static long kvmppc_rm_tce_iommu_do_map(struct kvm *kvm, struct iommu_table *tbl,
                unsigned long entry, unsigned long ua,
                enum dma_data_direction dir)
 {
@@ -290,6 +307,27 @@ static long kvmppc_rm_tce_iommu_map(struct kvm *kvm, struct iommu_table *tbl,
        return 0;
 }
 
+static long kvmppc_rm_tce_iommu_map(struct kvm *kvm,
+               struct kvmppc_spapr_tce_table *stt, struct iommu_table *tbl,
+               unsigned long entry, unsigned long ua,
+               enum dma_data_direction dir)
+{
+       unsigned long i, pgoff, ret = H_SUCCESS;
+       unsigned long subpages = 1ULL << (stt->page_shift - tbl->it_page_shift);
+       unsigned long io_entry = entry * subpages;
+
+       for (i = 0, pgoff = 0; i < subpages;
+                       ++i, pgoff += IOMMU_PAGE_SIZE(tbl)) {
+
+               ret = kvmppc_rm_tce_iommu_do_map(kvm, tbl,
+                               io_entry + i, ua + pgoff, dir);
+               if (ret != H_SUCCESS)
+                       break;
+       }
+
+       return ret;
+}
+
 long kvmppc_rm_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
                unsigned long ioba, unsigned long tce)
 {
@@ -327,10 +365,10 @@ long kvmppc_rm_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
 
        list_for_each_entry_lockless(stit, &stt->iommu_tables, next) {
                if (dir == DMA_NONE)
-                       ret = kvmppc_rm_tce_iommu_unmap(vcpu->kvm,
+                       ret = kvmppc_rm_tce_iommu_unmap(vcpu->kvm, stt,
                                        stit->tbl, entry);
                else
-                       ret = kvmppc_rm_tce_iommu_map(vcpu->kvm,
+                       ret = kvmppc_rm_tce_iommu_map(vcpu->kvm, stt,
                                        stit->tbl, entry, ua, dir);
 
                if (ret == H_SUCCESS)
@@ -477,7 +515,7 @@ long kvmppc_rm_h_put_tce_indirect(struct kvm_vcpu *vcpu,
                        return H_PARAMETER;
 
                list_for_each_entry_lockless(stit, &stt->iommu_tables, next) {
-                       ret = kvmppc_rm_tce_iommu_map(vcpu->kvm,
+                       ret = kvmppc_rm_tce_iommu_map(vcpu->kvm, stt,
                                        stit->tbl, entry + i, ua,
                                        iommu_tce_direction(tce));
 
@@ -526,10 +564,10 @@ long kvmppc_rm_h_stuff_tce(struct kvm_vcpu *vcpu,
                return H_PARAMETER;
 
        list_for_each_entry_lockless(stit, &stt->iommu_tables, next) {
-               unsigned long entry = ioba >> stit->tbl->it_page_shift;
+               unsigned long entry = ioba >> stt->page_shift;
 
                for (i = 0; i < npages; ++i) {
-                       ret = kvmppc_rm_tce_iommu_unmap(vcpu->kvm,
+                       ret = kvmppc_rm_tce_iommu_unmap(vcpu->kvm, stt,
                                        stit->tbl, entry + i);
 
                        if (ret == H_SUCCESS)
@@ -571,7 +609,7 @@ long kvmppc_h_get_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
        page = stt->pages[idx / TCES_PER_PAGE];
        tbl = (u64 *)page_address(page);
 
-       vcpu->arch.gpr[4] = tbl[idx % TCES_PER_PAGE];
+       vcpu->arch.regs.gpr[4] = tbl[idx % TCES_PER_PAGE];
 
        return H_SUCCESS;
 }
index 68d68983948e13813221627e0dcfe743d1c91037..36b11c5a0dbb968444da85b230cbc7020f69f583 100644 (file)
@@ -23,7 +23,9 @@
 #include <asm/reg.h>
 #include <asm/switch_to.h>
 #include <asm/time.h>
+#include <asm/tm.h>
 #include "book3s.h"
+#include <asm/asm-prototypes.h>
 
 #define OP_19_XOP_RFID         18
 #define OP_19_XOP_RFI          50
 #define OP_31_XOP_EIOIO                854
 #define OP_31_XOP_SLBMFEE      915
 
+#define OP_31_XOP_TBEGIN       654
+#define OP_31_XOP_TABORT       910
+
+#define OP_31_XOP_TRECLAIM     942
+#define OP_31_XOP_TRCHKPT      1006
+
 /* DCBZ is actually 1014, but we patch it to 1010 so we get a trap */
 #define OP_31_XOP_DCBZ         1010
 
@@ -87,6 +95,157 @@ static bool spr_allowed(struct kvm_vcpu *vcpu, enum priv_level level)
        return true;
 }
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+static inline void kvmppc_copyto_vcpu_tm(struct kvm_vcpu *vcpu)
+{
+       memcpy(&vcpu->arch.gpr_tm[0], &vcpu->arch.regs.gpr[0],
+                       sizeof(vcpu->arch.gpr_tm));
+       memcpy(&vcpu->arch.fp_tm, &vcpu->arch.fp,
+                       sizeof(struct thread_fp_state));
+       memcpy(&vcpu->arch.vr_tm, &vcpu->arch.vr,
+                       sizeof(struct thread_vr_state));
+       vcpu->arch.ppr_tm = vcpu->arch.ppr;
+       vcpu->arch.dscr_tm = vcpu->arch.dscr;
+       vcpu->arch.amr_tm = vcpu->arch.amr;
+       vcpu->arch.ctr_tm = vcpu->arch.regs.ctr;
+       vcpu->arch.tar_tm = vcpu->arch.tar;
+       vcpu->arch.lr_tm = vcpu->arch.regs.link;
+       vcpu->arch.cr_tm = vcpu->arch.cr;
+       vcpu->arch.xer_tm = vcpu->arch.regs.xer;
+       vcpu->arch.vrsave_tm = vcpu->arch.vrsave;
+}
+
+static inline void kvmppc_copyfrom_vcpu_tm(struct kvm_vcpu *vcpu)
+{
+       memcpy(&vcpu->arch.regs.gpr[0], &vcpu->arch.gpr_tm[0],
+                       sizeof(vcpu->arch.regs.gpr));
+       memcpy(&vcpu->arch.fp, &vcpu->arch.fp_tm,
+                       sizeof(struct thread_fp_state));
+       memcpy(&vcpu->arch.vr, &vcpu->arch.vr_tm,
+                       sizeof(struct thread_vr_state));
+       vcpu->arch.ppr = vcpu->arch.ppr_tm;
+       vcpu->arch.dscr = vcpu->arch.dscr_tm;
+       vcpu->arch.amr = vcpu->arch.amr_tm;
+       vcpu->arch.regs.ctr = vcpu->arch.ctr_tm;
+       vcpu->arch.tar = vcpu->arch.tar_tm;
+       vcpu->arch.regs.link = vcpu->arch.lr_tm;
+       vcpu->arch.cr = vcpu->arch.cr_tm;
+       vcpu->arch.regs.xer = vcpu->arch.xer_tm;
+       vcpu->arch.vrsave = vcpu->arch.vrsave_tm;
+}
+
+static void kvmppc_emulate_treclaim(struct kvm_vcpu *vcpu, int ra_val)
+{
+       unsigned long guest_msr = kvmppc_get_msr(vcpu);
+       int fc_val = ra_val ? ra_val : 1;
+       uint64_t texasr;
+
+       /* CR0 = 0 | MSR[TS] | 0 */
+       vcpu->arch.cr = (vcpu->arch.cr & ~(CR0_MASK << CR0_SHIFT)) |
+               (((guest_msr & MSR_TS_MASK) >> (MSR_TS_S_LG - 1))
+                << CR0_SHIFT);
+
+       preempt_disable();
+       tm_enable();
+       texasr = mfspr(SPRN_TEXASR);
+       kvmppc_save_tm_pr(vcpu);
+       kvmppc_copyfrom_vcpu_tm(vcpu);
+
+       /* failure recording depends on Failure Summary bit */
+       if (!(texasr & TEXASR_FS)) {
+               texasr &= ~TEXASR_FC;
+               texasr |= ((u64)fc_val << TEXASR_FC_LG) | TEXASR_FS;
+
+               texasr &= ~(TEXASR_PR | TEXASR_HV);
+               if (kvmppc_get_msr(vcpu) & MSR_PR)
+                       texasr |= TEXASR_PR;
+
+               if (kvmppc_get_msr(vcpu) & MSR_HV)
+                       texasr |= TEXASR_HV;
+
+               vcpu->arch.texasr = texasr;
+               vcpu->arch.tfiar = kvmppc_get_pc(vcpu);
+               mtspr(SPRN_TEXASR, texasr);
+               mtspr(SPRN_TFIAR, vcpu->arch.tfiar);
+       }
+       tm_disable();
+       /*
+        * treclaim need quit to non-transactional state.
+        */
+       guest_msr &= ~(MSR_TS_MASK);
+       kvmppc_set_msr(vcpu, guest_msr);
+       preempt_enable();
+
+       if (vcpu->arch.shadow_fscr & FSCR_TAR)
+               mtspr(SPRN_TAR, vcpu->arch.tar);
+}
+
+static void kvmppc_emulate_trchkpt(struct kvm_vcpu *vcpu)
+{
+       unsigned long guest_msr = kvmppc_get_msr(vcpu);
+
+       preempt_disable();
+       /*
+        * need flush FP/VEC/VSX to vcpu save area before
+        * copy.
+        */
+       kvmppc_giveup_ext(vcpu, MSR_VSX);
+       kvmppc_giveup_fac(vcpu, FSCR_TAR_LG);
+       kvmppc_copyto_vcpu_tm(vcpu);
+       kvmppc_save_tm_sprs(vcpu);
+
+       /*
+        * as a result of trecheckpoint. set TS to suspended.
+        */
+       guest_msr &= ~(MSR_TS_MASK);
+       guest_msr |= MSR_TS_S;
+       kvmppc_set_msr(vcpu, guest_msr);
+       kvmppc_restore_tm_pr(vcpu);
+       preempt_enable();
+}
+
+/* emulate tabort. at guest privilege state */
+void kvmppc_emulate_tabort(struct kvm_vcpu *vcpu, int ra_val)
+{
+       /* currently we only emulate tabort. but no emulation of other
+        * tabort variants since there is no kernel usage of them at
+        * present.
+        */
+       unsigned long guest_msr = kvmppc_get_msr(vcpu);
+       uint64_t org_texasr;
+
+       preempt_disable();
+       tm_enable();
+       org_texasr = mfspr(SPRN_TEXASR);
+       tm_abort(ra_val);
+
+       /* CR0 = 0 | MSR[TS] | 0 */
+       vcpu->arch.cr = (vcpu->arch.cr & ~(CR0_MASK << CR0_SHIFT)) |
+               (((guest_msr & MSR_TS_MASK) >> (MSR_TS_S_LG - 1))
+                << CR0_SHIFT);
+
+       vcpu->arch.texasr = mfspr(SPRN_TEXASR);
+       /* failure recording depends on Failure Summary bit,
+        * and tabort will be treated as nops in non-transactional
+        * state.
+        */
+       if (!(org_texasr & TEXASR_FS) &&
+                       MSR_TM_ACTIVE(guest_msr)) {
+               vcpu->arch.texasr &= ~(TEXASR_PR | TEXASR_HV);
+               if (guest_msr & MSR_PR)
+                       vcpu->arch.texasr |= TEXASR_PR;
+
+               if (guest_msr & MSR_HV)
+                       vcpu->arch.texasr |= TEXASR_HV;
+
+               vcpu->arch.tfiar = kvmppc_get_pc(vcpu);
+       }
+       tm_disable();
+       preempt_enable();
+}
+
+#endif
+
 int kvmppc_core_emulate_op_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
                              unsigned int inst, int *advance)
 {
@@ -117,11 +276,28 @@ int kvmppc_core_emulate_op_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
        case 19:
                switch (get_xop(inst)) {
                case OP_19_XOP_RFID:
-               case OP_19_XOP_RFI:
+               case OP_19_XOP_RFI: {
+                       unsigned long srr1 = kvmppc_get_srr1(vcpu);
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+                       unsigned long cur_msr = kvmppc_get_msr(vcpu);
+
+                       /*
+                        * add rules to fit in ISA specification regarding TM
+                        * state transistion in TM disable/Suspended state,
+                        * and target TM state is TM inactive(00) state. (the
+                        * change should be suppressed).
+                        */
+                       if (((cur_msr & MSR_TM) == 0) &&
+                               ((srr1 & MSR_TM) == 0) &&
+                               MSR_TM_SUSPENDED(cur_msr) &&
+                               !MSR_TM_ACTIVE(srr1))
+                               srr1 |= MSR_TS_S;
+#endif
                        kvmppc_set_pc(vcpu, kvmppc_get_srr0(vcpu));
-                       kvmppc_set_msr(vcpu, kvmppc_get_srr1(vcpu));
+                       kvmppc_set_msr(vcpu, srr1);
                        *advance = 0;
                        break;
+               }
 
                default:
                        emulated = EMULATE_FAIL;
@@ -304,6 +480,140 @@ int kvmppc_core_emulate_op_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
 
                        break;
                }
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+               case OP_31_XOP_TBEGIN:
+               {
+                       if (!cpu_has_feature(CPU_FTR_TM))
+                               break;
+
+                       if (!(kvmppc_get_msr(vcpu) & MSR_TM)) {
+                               kvmppc_trigger_fac_interrupt(vcpu, FSCR_TM_LG);
+                               emulated = EMULATE_AGAIN;
+                               break;
+                       }
+
+                       if (!(kvmppc_get_msr(vcpu) & MSR_PR)) {
+                               preempt_disable();
+                               vcpu->arch.cr = (CR0_TBEGIN_FAILURE |
+                                 (vcpu->arch.cr & ~(CR0_MASK << CR0_SHIFT)));
+
+                               vcpu->arch.texasr = (TEXASR_FS | TEXASR_EXACT |
+                                       (((u64)(TM_CAUSE_EMULATE | TM_CAUSE_PERSISTENT))
+                                                << TEXASR_FC_LG));
+
+                               if ((inst >> 21) & 0x1)
+                                       vcpu->arch.texasr |= TEXASR_ROT;
+
+                               if (kvmppc_get_msr(vcpu) & MSR_HV)
+                                       vcpu->arch.texasr |= TEXASR_HV;
+
+                               vcpu->arch.tfhar = kvmppc_get_pc(vcpu) + 4;
+                               vcpu->arch.tfiar = kvmppc_get_pc(vcpu);
+
+                               kvmppc_restore_tm_sprs(vcpu);
+                               preempt_enable();
+                       } else
+                               emulated = EMULATE_FAIL;
+                       break;
+               }
+               case OP_31_XOP_TABORT:
+               {
+                       ulong guest_msr = kvmppc_get_msr(vcpu);
+                       unsigned long ra_val = 0;
+
+                       if (!cpu_has_feature(CPU_FTR_TM))
+                               break;
+
+                       if (!(kvmppc_get_msr(vcpu) & MSR_TM)) {
+                               kvmppc_trigger_fac_interrupt(vcpu, FSCR_TM_LG);
+                               emulated = EMULATE_AGAIN;
+                               break;
+                       }
+
+                       /* only emulate for privilege guest, since problem state
+                        * guest can run with TM enabled and we don't expect to
+                        * trap at here for that case.
+                        */
+                       WARN_ON(guest_msr & MSR_PR);
+
+                       if (ra)
+                               ra_val = kvmppc_get_gpr(vcpu, ra);
+
+                       kvmppc_emulate_tabort(vcpu, ra_val);
+                       break;
+               }
+               case OP_31_XOP_TRECLAIM:
+               {
+                       ulong guest_msr = kvmppc_get_msr(vcpu);
+                       unsigned long ra_val = 0;
+
+                       if (!cpu_has_feature(CPU_FTR_TM))
+                               break;
+
+                       if (!(kvmppc_get_msr(vcpu) & MSR_TM)) {
+                               kvmppc_trigger_fac_interrupt(vcpu, FSCR_TM_LG);
+                               emulated = EMULATE_AGAIN;
+                               break;
+                       }
+
+                       /* generate interrupts based on priorities */
+                       if (guest_msr & MSR_PR) {
+                               /* Privileged Instruction type Program Interrupt */
+                               kvmppc_core_queue_program(vcpu, SRR1_PROGPRIV);
+                               emulated = EMULATE_AGAIN;
+                               break;
+                       }
+
+                       if (!MSR_TM_ACTIVE(guest_msr)) {
+                               /* TM bad thing interrupt */
+                               kvmppc_core_queue_program(vcpu, SRR1_PROGTM);
+                               emulated = EMULATE_AGAIN;
+                               break;
+                       }
+
+                       if (ra)
+                               ra_val = kvmppc_get_gpr(vcpu, ra);
+                       kvmppc_emulate_treclaim(vcpu, ra_val);
+                       break;
+               }
+               case OP_31_XOP_TRCHKPT:
+               {
+                       ulong guest_msr = kvmppc_get_msr(vcpu);
+                       unsigned long texasr;
+
+                       if (!cpu_has_feature(CPU_FTR_TM))
+                               break;
+
+                       if (!(kvmppc_get_msr(vcpu) & MSR_TM)) {
+                               kvmppc_trigger_fac_interrupt(vcpu, FSCR_TM_LG);
+                               emulated = EMULATE_AGAIN;
+                               break;
+                       }
+
+                       /* generate interrupt based on priorities */
+                       if (guest_msr & MSR_PR) {
+                               /* Privileged Instruction type Program Intr */
+                               kvmppc_core_queue_program(vcpu, SRR1_PROGPRIV);
+                               emulated = EMULATE_AGAIN;
+                               break;
+                       }
+
+                       tm_enable();
+                       texasr = mfspr(SPRN_TEXASR);
+                       tm_disable();
+
+                       if (MSR_TM_ACTIVE(guest_msr) ||
+                               !(texasr & (TEXASR_FS))) {
+                               /* TM bad thing interrupt */
+                               kvmppc_core_queue_program(vcpu, SRR1_PROGTM);
+                               emulated = EMULATE_AGAIN;
+                               break;
+                       }
+
+                       kvmppc_emulate_trchkpt(vcpu);
+                       break;
+               }
+#endif
                default:
                        emulated = EMULATE_FAIL;
                }
@@ -465,13 +775,38 @@ int kvmppc_core_emulate_mtspr_pr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val)
                break;
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
        case SPRN_TFHAR:
-               vcpu->arch.tfhar = spr_val;
-               break;
        case SPRN_TEXASR:
-               vcpu->arch.texasr = spr_val;
-               break;
        case SPRN_TFIAR:
-               vcpu->arch.tfiar = spr_val;
+               if (!cpu_has_feature(CPU_FTR_TM))
+                       break;
+
+               if (!(kvmppc_get_msr(vcpu) & MSR_TM)) {
+                       kvmppc_trigger_fac_interrupt(vcpu, FSCR_TM_LG);
+                       emulated = EMULATE_AGAIN;
+                       break;
+               }
+
+               if (MSR_TM_ACTIVE(kvmppc_get_msr(vcpu)) &&
+                       !((MSR_TM_SUSPENDED(kvmppc_get_msr(vcpu))) &&
+                                       (sprn == SPRN_TFHAR))) {
+                       /* it is illegal to mtspr() TM regs in
+                        * other than non-transactional state, with
+                        * the exception of TFHAR in suspend state.
+                        */
+                       kvmppc_core_queue_program(vcpu, SRR1_PROGTM);
+                       emulated = EMULATE_AGAIN;
+                       break;
+               }
+
+               tm_enable();
+               if (sprn == SPRN_TFHAR)
+                       mtspr(SPRN_TFHAR, spr_val);
+               else if (sprn == SPRN_TEXASR)
+                       mtspr(SPRN_TEXASR, spr_val);
+               else
+                       mtspr(SPRN_TFIAR, spr_val);
+               tm_disable();
+
                break;
 #endif
 #endif
@@ -618,13 +953,25 @@ int kvmppc_core_emulate_mfspr_pr(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val
                break;
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
        case SPRN_TFHAR:
-               *spr_val = vcpu->arch.tfhar;
-               break;
        case SPRN_TEXASR:
-               *spr_val = vcpu->arch.texasr;
-               break;
        case SPRN_TFIAR:
-               *spr_val = vcpu->arch.tfiar;
+               if (!cpu_has_feature(CPU_FTR_TM))
+                       break;
+
+               if (!(kvmppc_get_msr(vcpu) & MSR_TM)) {
+                       kvmppc_trigger_fac_interrupt(vcpu, FSCR_TM_LG);
+                       emulated = EMULATE_AGAIN;
+                       break;
+               }
+
+               tm_enable();
+               if (sprn == SPRN_TFHAR)
+                       *spr_val = mfspr(SPRN_TFHAR);
+               else if (sprn == SPRN_TEXASR)
+                       *spr_val = mfspr(SPRN_TEXASR);
+               else if (sprn == SPRN_TFIAR)
+                       *spr_val = mfspr(SPRN_TFIAR);
+               tm_disable();
                break;
 #endif
 #endif
index 8858ab8b6ca42d79f8616b2d16d75e8561854ab7..de686b340f4aa4ccccaf47e3349eba94d6fddda2 100644 (file)
@@ -123,6 +123,32 @@ static bool no_mixing_hpt_and_radix;
 static void kvmppc_end_cede(struct kvm_vcpu *vcpu);
 static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu);
 
+/*
+ * RWMR values for POWER8.  These control the rate at which PURR
+ * and SPURR count and should be set according to the number of
+ * online threads in the vcore being run.
+ */
+#define RWMR_RPA_P8_1THREAD    0x164520C62609AECA
+#define RWMR_RPA_P8_2THREAD    0x7FFF2908450D8DA9
+#define RWMR_RPA_P8_3THREAD    0x164520C62609AECA
+#define RWMR_RPA_P8_4THREAD    0x199A421245058DA9
+#define RWMR_RPA_P8_5THREAD    0x164520C62609AECA
+#define RWMR_RPA_P8_6THREAD    0x164520C62609AECA
+#define RWMR_RPA_P8_7THREAD    0x164520C62609AECA
+#define RWMR_RPA_P8_8THREAD    0x164520C62609AECA
+
+static unsigned long p8_rwmr_values[MAX_SMT_THREADS + 1] = {
+       RWMR_RPA_P8_1THREAD,
+       RWMR_RPA_P8_1THREAD,
+       RWMR_RPA_P8_2THREAD,
+       RWMR_RPA_P8_3THREAD,
+       RWMR_RPA_P8_4THREAD,
+       RWMR_RPA_P8_5THREAD,
+       RWMR_RPA_P8_6THREAD,
+       RWMR_RPA_P8_7THREAD,
+       RWMR_RPA_P8_8THREAD,
+};
+
 static inline struct kvm_vcpu *next_runnable_thread(struct kvmppc_vcore *vc,
                int *ip)
 {
@@ -371,13 +397,13 @@ static void kvmppc_dump_regs(struct kvm_vcpu *vcpu)
 
        pr_err("vcpu %p (%d):\n", vcpu, vcpu->vcpu_id);
        pr_err("pc  = %.16lx  msr = %.16llx  trap = %x\n",
-              vcpu->arch.pc, vcpu->arch.shregs.msr, vcpu->arch.trap);
+              vcpu->arch.regs.nip, vcpu->arch.shregs.msr, vcpu->arch.trap);
        for (r = 0; r < 16; ++r)
                pr_err("r%2d = %.16lx  r%d = %.16lx\n",
                       r, kvmppc_get_gpr(vcpu, r),
                       r+16, kvmppc_get_gpr(vcpu, r+16));
        pr_err("ctr = %.16lx  lr  = %.16lx\n",
-              vcpu->arch.ctr, vcpu->arch.lr);
+              vcpu->arch.regs.ctr, vcpu->arch.regs.link);
        pr_err("srr0 = %.16llx srr1 = %.16llx\n",
               vcpu->arch.shregs.srr0, vcpu->arch.shregs.srr1);
        pr_err("sprg0 = %.16llx sprg1 = %.16llx\n",
@@ -385,7 +411,7 @@ static void kvmppc_dump_regs(struct kvm_vcpu *vcpu)
        pr_err("sprg2 = %.16llx sprg3 = %.16llx\n",
               vcpu->arch.shregs.sprg2, vcpu->arch.shregs.sprg3);
        pr_err("cr = %.8x  xer = %.16lx  dsisr = %.8x\n",
-              vcpu->arch.cr, vcpu->arch.xer, vcpu->arch.shregs.dsisr);
+              vcpu->arch.cr, vcpu->arch.regs.xer, vcpu->arch.shregs.dsisr);
        pr_err("dar = %.16llx\n", vcpu->arch.shregs.dar);
        pr_err("fault dar = %.16lx dsisr = %.8x\n",
               vcpu->arch.fault_dar, vcpu->arch.fault_dsisr);
@@ -1526,6 +1552,9 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
                *val = get_reg_val(id, vcpu->arch.dec_expires +
                                   vcpu->arch.vcore->tb_offset);
                break;
+       case KVM_REG_PPC_ONLINE:
+               *val = get_reg_val(id, vcpu->arch.online);
+               break;
        default:
                r = -EINVAL;
                break;
@@ -1757,6 +1786,14 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
                vcpu->arch.dec_expires = set_reg_val(id, *val) -
                        vcpu->arch.vcore->tb_offset;
                break;
+       case KVM_REG_PPC_ONLINE:
+               i = set_reg_val(id, *val);
+               if (i && !vcpu->arch.online)
+                       atomic_inc(&vcpu->arch.vcore->online_count);
+               else if (!i && vcpu->arch.online)
+                       atomic_dec(&vcpu->arch.vcore->online_count);
+               vcpu->arch.online = i;
+               break;
        default:
                r = -EINVAL;
                break;
@@ -2850,6 +2887,25 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
                }
        }
 
+       /*
+        * On POWER8, set RWMR register.
+        * Since it only affects PURR and SPURR, it doesn't affect
+        * the host, so we don't save/restore the host value.
+        */
+       if (is_power8) {
+               unsigned long rwmr_val = RWMR_RPA_P8_8THREAD;
+               int n_online = atomic_read(&vc->online_count);
+
+               /*
+                * Use the 8-thread value if we're doing split-core
+                * or if the vcore's online count looks bogus.
+                */
+               if (split == 1 && threads_per_subcore == MAX_SMT_THREADS &&
+                   n_online >= 1 && n_online <= MAX_SMT_THREADS)
+                       rwmr_val = p8_rwmr_values[n_online];
+               mtspr(SPRN_RWMR, rwmr_val);
+       }
+
        /* Start all the threads */
        active = 0;
        for (sub = 0; sub < core_info.n_subcores; ++sub) {
@@ -2902,6 +2958,32 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
        for (sub = 0; sub < core_info.n_subcores; ++sub)
                spin_unlock(&core_info.vc[sub]->lock);
 
+       if (kvm_is_radix(vc->kvm)) {
+               int tmp = pcpu;
+
+               /*
+                * Do we need to flush the process scoped TLB for the LPAR?
+                *
+                * On POWER9, individual threads can come in here, but the
+                * TLB is shared between the 4 threads in a core, hence
+                * invalidating on one thread invalidates for all.
+                * Thus we make all 4 threads use the same bit here.
+                *
+                * Hash must be flushed in realmode in order to use tlbiel.
+                */
+               mtspr(SPRN_LPID, vc->kvm->arch.lpid);
+               isync();
+
+               if (cpu_has_feature(CPU_FTR_ARCH_300))
+                       tmp &= ~0x3UL;
+
+               if (cpumask_test_cpu(tmp, &vc->kvm->arch.need_tlb_flush)) {
+                       radix__local_flush_tlb_lpid_guest(vc->kvm->arch.lpid);
+                       /* Clear the bit after the TLB flush */
+                       cpumask_clear_cpu(tmp, &vc->kvm->arch.need_tlb_flush);
+               }
+       }
+
        /*
         * Interrupts will be enabled once we get into the guest,
         * so tell lockdep that we're about to enable interrupts.
@@ -3356,6 +3438,15 @@ static int kvmppc_vcpu_run_hv(struct kvm_run *run, struct kvm_vcpu *vcpu)
        }
 #endif
 
+       /*
+        * Force online to 1 for the sake of old userspace which doesn't
+        * set it.
+        */
+       if (!vcpu->arch.online) {
+               atomic_inc(&vcpu->arch.vcore->online_count);
+               vcpu->arch.online = 1;
+       }
+
        kvmppc_core_prepare_to_enter(vcpu);
 
        /* No need to go into the guest when all we'll do is come back out */
index de18299f92b759288c13df1b3479cf6bc3403b08..d4a3f4da409bf2a39e2c0ed60b22760edf0975a0 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/cma.h>
 #include <linux/bitops.h>
 
+#include <asm/asm-prototypes.h>
 #include <asm/cputable.h>
 #include <asm/kvm_ppc.h>
 #include <asm/kvm_book3s.h>
@@ -211,9 +212,9 @@ long kvmppc_h_random(struct kvm_vcpu *vcpu)
 
        /* Only need to do the expensive mfmsr() on radix */
        if (kvm_is_radix(vcpu->kvm) && (mfmsr() & MSR_IR))
-               r = powernv_get_random_long(&vcpu->arch.gpr[4]);
+               r = powernv_get_random_long(&vcpu->arch.regs.gpr[4]);
        else
-               r = powernv_get_random_real_mode(&vcpu->arch.gpr[4]);
+               r = powernv_get_random_real_mode(&vcpu->arch.regs.gpr[4]);
        if (r)
                return H_SUCCESS;
 
@@ -562,7 +563,7 @@ unsigned long kvmppc_rm_h_xirr_x(struct kvm_vcpu *vcpu)
 {
        if (!kvmppc_xics_enabled(vcpu))
                return H_TOO_HARD;
-       vcpu->arch.gpr[5] = get_tb();
+       vcpu->arch.regs.gpr[5] = get_tb();
        if (xive_enabled()) {
                if (is_rm())
                        return xive_rm_h_xirr(vcpu);
@@ -633,7 +634,19 @@ int kvmppc_rm_h_eoi(struct kvm_vcpu *vcpu, unsigned long xirr)
 
 void kvmppc_bad_interrupt(struct pt_regs *regs)
 {
-       die("Bad interrupt in KVM entry/exit code", regs, SIGABRT);
+       /*
+        * 100 could happen at any time, 200 can happen due to invalid real
+        * address access for example (or any time due to a hardware problem).
+        */
+       if (TRAP(regs) == 0x100) {
+               get_paca()->in_nmi++;
+               system_reset_exception(regs);
+               get_paca()->in_nmi--;
+       } else if (TRAP(regs) == 0x200) {
+               machine_check_exception(regs);
+       } else {
+               die("Bad interrupt in KVM entry/exit code", regs, SIGABRT);
+       }
        panic("Bad KVM trap");
 }
 
index 0e84930332889507ce2461986c080aadd2bb14b2..82f2ff9410b6a3d398a290f2703a30b38b93ea10 100644 (file)
@@ -137,7 +137,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
 /*
  * We return here in virtual mode after the guest exits
  * with something that we can't handle in real mode.
- * Interrupts are enabled again at this point.
+ * Interrupts are still hard-disabled.
  */
 
        /*
index 78e6a392330f78b8407f8f7102762944c39c7d1f..1f22d9e977d4e8e031cf25436fad18a4904d4928 100644 (file)
@@ -418,7 +418,8 @@ long kvmppc_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
                    long pte_index, unsigned long pteh, unsigned long ptel)
 {
        return kvmppc_do_h_enter(vcpu->kvm, flags, pte_index, pteh, ptel,
-                                vcpu->arch.pgdir, true, &vcpu->arch.gpr[4]);
+                                vcpu->arch.pgdir, true,
+                                &vcpu->arch.regs.gpr[4]);
 }
 
 #ifdef __BIG_ENDIAN__
@@ -434,24 +435,6 @@ static inline int is_mmio_hpte(unsigned long v, unsigned long r)
                (HPTE_R_KEY_HI | HPTE_R_KEY_LO));
 }
 
-static inline int try_lock_tlbie(unsigned int *lock)
-{
-       unsigned int tmp, old;
-       unsigned int token = LOCK_TOKEN;
-
-       asm volatile("1:lwarx   %1,0,%2\n"
-                    "  cmpwi   cr0,%1,0\n"
-                    "  bne     2f\n"
-                    "  stwcx.  %3,0,%2\n"
-                    "  bne-    1b\n"
-                    "  isync\n"
-                    "2:"
-                    : "=&r" (tmp), "=&r" (old)
-                    : "r" (lock), "r" (token)
-                    : "cc", "memory");
-       return old == 0;
-}
-
 static void do_tlbies(struct kvm *kvm, unsigned long *rbvalues,
                      long npages, int global, bool need_sync)
 {
@@ -463,8 +446,6 @@ static void do_tlbies(struct kvm *kvm, unsigned long *rbvalues,
         * the RS field, this is backwards-compatible with P7 and P8.
         */
        if (global) {
-               while (!try_lock_tlbie(&kvm->arch.tlbie_lock))
-                       cpu_relax();
                if (need_sync)
                        asm volatile("ptesync" : : : "memory");
                for (i = 0; i < npages; ++i) {
@@ -483,7 +464,6 @@ static void do_tlbies(struct kvm *kvm, unsigned long *rbvalues,
                }
 
                asm volatile("eieio; tlbsync; ptesync" : : : "memory");
-               kvm->arch.tlbie_lock = 0;
        } else {
                if (need_sync)
                        asm volatile("ptesync" : : : "memory");
@@ -561,13 +541,13 @@ long kvmppc_h_remove(struct kvm_vcpu *vcpu, unsigned long flags,
                     unsigned long pte_index, unsigned long avpn)
 {
        return kvmppc_do_h_remove(vcpu->kvm, flags, pte_index, avpn,
-                                 &vcpu->arch.gpr[4]);
+                                 &vcpu->arch.regs.gpr[4]);
 }
 
 long kvmppc_h_bulk_remove(struct kvm_vcpu *vcpu)
 {
        struct kvm *kvm = vcpu->kvm;
-       unsigned long *args = &vcpu->arch.gpr[4];
+       unsigned long *args = &vcpu->arch.regs.gpr[4];
        __be64 *hp, *hptes[4];
        unsigned long tlbrb[4];
        long int i, j, k, n, found, indexes[4];
@@ -787,8 +767,8 @@ long kvmppc_h_read(struct kvm_vcpu *vcpu, unsigned long flags,
                        r = rev[i].guest_rpte | (r & (HPTE_R_R | HPTE_R_C));
                        r &= ~HPTE_GR_RESERVED;
                }
-               vcpu->arch.gpr[4 + i * 2] = v;
-               vcpu->arch.gpr[5 + i * 2] = r;
+               vcpu->arch.regs.gpr[4 + i * 2] = v;
+               vcpu->arch.regs.gpr[5 + i * 2] = r;
        }
        return H_SUCCESS;
 }
@@ -834,7 +814,7 @@ long kvmppc_h_clear_ref(struct kvm_vcpu *vcpu, unsigned long flags,
                        }
                }
        }
-       vcpu->arch.gpr[4] = gr;
+       vcpu->arch.regs.gpr[4] = gr;
        ret = H_SUCCESS;
  out:
        unlock_hpte(hpte, v & ~HPTE_V_HVLOCK);
@@ -881,7 +861,7 @@ long kvmppc_h_clear_mod(struct kvm_vcpu *vcpu, unsigned long flags,
                        kvmppc_set_dirty_from_hpte(kvm, v, gr);
                }
        }
-       vcpu->arch.gpr[4] = gr;
+       vcpu->arch.regs.gpr[4] = gr;
        ret = H_SUCCESS;
  out:
        unlock_hpte(hpte, v & ~HPTE_V_HVLOCK);
index 2a862618f072b63ee27915be5ab43468bcffbb2f..758d1d23215e94b2feb25cf9a53fd778a4785f44 100644 (file)
@@ -517,7 +517,7 @@ unsigned long xics_rm_h_xirr(struct kvm_vcpu *vcpu)
        } while (!icp_rm_try_update(icp, old_state, new_state));
 
        /* Return the result in GPR4 */
-       vcpu->arch.gpr[4] = xirr;
+       vcpu->arch.regs.gpr[4] = xirr;
 
        return check_too_hard(xics, icp);
 }
index b97d261d3b8998b67f4fc6cf7f022959ada9ad53..153988d878e8f1797ded66a265df97555194cb34 100644 (file)
@@ -39,8 +39,6 @@ BEGIN_FTR_SECTION;                            \
        extsw   reg, reg;                       \
 END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
 
-#define VCPU_GPRS_TM(reg) (((reg) * ULONG_SIZE) + VCPU_GPR_TM)
-
 /* Values in HSTATE_NAPPING(r13) */
 #define NAPPING_CEDE   1
 #define NAPPING_NOVCPU 2
@@ -639,6 +637,10 @@ kvmppc_hv_entry:
        /* Primary thread switches to guest partition. */
        cmpwi   r6,0
        bne     10f
+
+       /* Radix has already switched LPID and flushed core TLB */
+       bne     cr7, 22f
+
        lwz     r7,KVM_LPID(r9)
 BEGIN_FTR_SECTION
        ld      r6,KVM_SDR1(r9)
@@ -650,7 +652,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
        mtspr   SPRN_LPID,r7
        isync
 
-       /* See if we need to flush the TLB */
+       /* See if we need to flush the TLB. Hash has to be done in RM */
        lhz     r6,PACAPACAINDEX(r13)   /* test_bit(cpu, need_tlb_flush) */
 BEGIN_FTR_SECTION
        /*
@@ -677,15 +679,10 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
        li      r7,0x800                /* IS field = 0b10 */
        ptesync
        li      r0,0                    /* RS for P9 version of tlbiel */
-       bne     cr7, 29f
 28:    tlbiel  r7                      /* On P9, rs=0, RIC=0, PRS=0, R=0 */
        addi    r7,r7,0x1000
        bdnz    28b
-       b       30f
-29:    PPC_TLBIEL(7,0,2,1,1)           /* for radix, RIC=2, PRS=1, R=1 */
-       addi    r7,r7,0x1000
-       bdnz    29b
-30:    ptesync
+       ptesync
 23:    ldarx   r7,0,r6                 /* clear the bit after TLB flushed */
        andc    r7,r7,r8
        stdcx.  r7,0,r6
@@ -799,7 +796,10 @@ END_FTR_SECTION(CPU_FTR_TM | CPU_FTR_P9_TM_HV_ASSIST, 0)
        /*
         * NOTE THAT THIS TRASHES ALL NON-VOLATILE REGISTERS INCLUDING CR
         */
-       bl      kvmppc_restore_tm
+       mr      r3, r4
+       ld      r4, VCPU_MSR(r3)
+       bl      kvmppc_restore_tm_hv
+       ld      r4, HSTATE_KVM_VCPU(r13)
 91:
 #endif
 
@@ -1783,7 +1783,10 @@ END_FTR_SECTION(CPU_FTR_TM | CPU_FTR_P9_TM_HV_ASSIST, 0)
        /*
         * NOTE THAT THIS TRASHES ALL NON-VOLATILE REGISTERS INCLUDING CR
         */
-       bl      kvmppc_save_tm
+       mr      r3, r9
+       ld      r4, VCPU_MSR(r3)
+       bl      kvmppc_save_tm_hv
+       ld      r9, HSTATE_KVM_VCPU(r13)
 91:
 #endif
 
@@ -2686,8 +2689,9 @@ END_FTR_SECTION(CPU_FTR_TM | CPU_FTR_P9_TM_HV_ASSIST, 0)
        /*
         * NOTE THAT THIS TRASHES ALL NON-VOLATILE REGISTERS INCLUDING CR
         */
-       ld      r9, HSTATE_KVM_VCPU(r13)
-       bl      kvmppc_save_tm
+       ld      r3, HSTATE_KVM_VCPU(r13)
+       ld      r4, VCPU_MSR(r3)
+       bl      kvmppc_save_tm_hv
 91:
 #endif
 
@@ -2805,7 +2809,10 @@ END_FTR_SECTION(CPU_FTR_TM | CPU_FTR_P9_TM_HV_ASSIST, 0)
        /*
         * NOTE THAT THIS TRASHES ALL NON-VOLATILE REGISTERS INCLUDING CR
         */
-       bl      kvmppc_restore_tm
+       mr      r3, r4
+       ld      r4, VCPU_MSR(r3)
+       bl      kvmppc_restore_tm_hv
+       ld      r4, HSTATE_KVM_VCPU(r13)
 91:
 #endif
 
@@ -3126,11 +3133,22 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
 /*
  * Save transactional state and TM-related registers.
- * Called with r9 pointing to the vcpu struct.
+ * Called with r3 pointing to the vcpu struct and r4 containing
+ * the guest MSR value.
  * This can modify all checkpointed registers, but
- * restores r1, r2 and r9 (vcpu pointer) before exit.
+ * restores r1 and r2 before exit.
  */
-kvmppc_save_tm:
+kvmppc_save_tm_hv:
+       /* See if we need to handle fake suspend mode */
+BEGIN_FTR_SECTION
+       b       __kvmppc_save_tm
+END_FTR_SECTION_IFCLR(CPU_FTR_P9_TM_HV_ASSIST)
+
+       lbz     r0, HSTATE_FAKE_SUSPEND(r13) /* Were we fake suspended? */
+       cmpwi   r0, 0
+       beq     __kvmppc_save_tm
+
+       /* The following code handles the fake_suspend = 1 case */
        mflr    r0
        std     r0, PPC_LR_STKOFF(r1)
        stdu    r1, -PPC_MIN_STKFRM(r1)
@@ -3141,59 +3159,37 @@ kvmppc_save_tm:
        rldimi  r8, r0, MSR_TM_LG, 63-MSR_TM_LG
        mtmsrd  r8
 
-       ld      r5, VCPU_MSR(r9)
-       rldicl. r5, r5, 64 - MSR_TS_S_LG, 62
-       beq     1f      /* TM not active in guest. */
-
-       std     r1, HSTATE_HOST_R1(r13)
-       li      r3, TM_CAUSE_KVM_RESCHED
-
-BEGIN_FTR_SECTION
-       lbz     r0, HSTATE_FAKE_SUSPEND(r13) /* Were we fake suspended? */
-       cmpwi   r0, 0
-       beq     3f
        rldicl. r8, r8, 64 - MSR_TS_S_LG, 62 /* Did we actually hrfid? */
        beq     4f
-BEGIN_FTR_SECTION_NESTED(96)
+BEGIN_FTR_SECTION
        bl      pnv_power9_force_smt4_catch
-END_FTR_SECTION_NESTED(CPU_FTR_P9_TM_XER_SO_BUG, CPU_FTR_P9_TM_XER_SO_BUG, 96)
+END_FTR_SECTION_IFSET(CPU_FTR_P9_TM_XER_SO_BUG)
        nop
-       b       6f
-3:
-       /* Emulation of the treclaim instruction needs TEXASR before treclaim */
-       mfspr   r6, SPRN_TEXASR
-       std     r6, VCPU_ORIG_TEXASR(r9)
-6:
-END_FTR_SECTION_IFSET(CPU_FTR_P9_TM_HV_ASSIST)
 
-       /* Clear the MSR RI since r1, r13 are all going to be foobar. */
+       std     r1, HSTATE_HOST_R1(r13)
+
+       /* Clear the MSR RI since r1, r13 may be foobar. */
        li      r5, 0
        mtmsrd  r5, 1
 
-       /* All GPRs are volatile at this point. */
+       /* We have to treclaim here because that's the only way to do S->N */
+       li      r3, TM_CAUSE_KVM_RESCHED
        TRECLAIM(R3)
 
-       /* Temporarily store r13 and r9 so we have some regs to play with */
-       SET_SCRATCH0(r13)
-       GET_PACA(r13)
-       std     r9, PACATMSCRATCH(r13)
-
-       /* If doing TM emulation on POWER9 DD2.2, check for fake suspend mode */
-BEGIN_FTR_SECTION
-       lbz     r9, HSTATE_FAKE_SUSPEND(r13)
-       cmpwi   r9, 0
-       beq     2f
        /*
         * We were in fake suspend, so we are not going to save the
         * register state as the guest checkpointed state (since
         * we already have it), therefore we can now use any volatile GPR.
         */
-       /* Reload stack pointer and TOC. */
+       /* Reload PACA pointer, stack pointer and TOC. */
+       GET_PACA(r13)
        ld      r1, HSTATE_HOST_R1(r13)
        ld      r2, PACATOC(r13)
+
        /* Set MSR RI now we have r1 and r13 back. */
        li      r5, MSR_RI
        mtmsrd  r5, 1
+
        HMT_MEDIUM
        ld      r6, HSTATE_DSCR(r13)
        mtspr   SPRN_DSCR, r6
@@ -3208,85 +3204,9 @@ END_FTR_SECTION_NESTED(CPU_FTR_P9_TM_XER_SO_BUG, CPU_FTR_P9_TM_XER_SO_BUG, 96)
        li      r0, PSSCR_FAKE_SUSPEND
        andc    r3, r3, r0
        mtspr   SPRN_PSSCR, r3
-       ld      r9, HSTATE_KVM_VCPU(r13)
-       /* Don't save TEXASR, use value from last exit in real suspend state */
-       b       11f
-2:
-END_FTR_SECTION_IFSET(CPU_FTR_P9_TM_HV_ASSIST)
 
+       /* Don't save TEXASR, use value from last exit in real suspend state */
        ld      r9, HSTATE_KVM_VCPU(r13)
-
-       /* Get a few more GPRs free. */
-       std     r29, VCPU_GPRS_TM(29)(r9)
-       std     r30, VCPU_GPRS_TM(30)(r9)
-       std     r31, VCPU_GPRS_TM(31)(r9)
-
-       /* Save away PPR and DSCR soon so don't run with user values. */
-       mfspr   r31, SPRN_PPR
-       HMT_MEDIUM
-       mfspr   r30, SPRN_DSCR
-       ld      r29, HSTATE_DSCR(r13)
-       mtspr   SPRN_DSCR, r29
-
-       /* Save all but r9, r13 & r29-r31 */
-       reg = 0
-       .rept   29
-       .if (reg != 9) && (reg != 13)
-       std     reg, VCPU_GPRS_TM(reg)(r9)
-       .endif
-       reg = reg + 1
-       .endr
-       /* ... now save r13 */
-       GET_SCRATCH0(r4)
-       std     r4, VCPU_GPRS_TM(13)(r9)
-       /* ... and save r9 */
-       ld      r4, PACATMSCRATCH(r13)
-       std     r4, VCPU_GPRS_TM(9)(r9)
-
-       /* Reload stack pointer and TOC. */
-       ld      r1, HSTATE_HOST_R1(r13)
-       ld      r2, PACATOC(r13)
-
-       /* Set MSR RI now we have r1 and r13 back. */
-       li      r5, MSR_RI
-       mtmsrd  r5, 1
-
-       /* Save away checkpinted SPRs. */
-       std     r31, VCPU_PPR_TM(r9)
-       std     r30, VCPU_DSCR_TM(r9)
-       mflr    r5
-       mfcr    r6
-       mfctr   r7
-       mfspr   r8, SPRN_AMR
-       mfspr   r10, SPRN_TAR
-       mfxer   r11
-       std     r5, VCPU_LR_TM(r9)
-       stw     r6, VCPU_CR_TM(r9)
-       std     r7, VCPU_CTR_TM(r9)
-       std     r8, VCPU_AMR_TM(r9)
-       std     r10, VCPU_TAR_TM(r9)
-       std     r11, VCPU_XER_TM(r9)
-
-       /* Restore r12 as trap number. */
-       lwz     r12, VCPU_TRAP(r9)
-
-       /* Save FP/VSX. */
-       addi    r3, r9, VCPU_FPRS_TM
-       bl      store_fp_state
-       addi    r3, r9, VCPU_VRS_TM
-       bl      store_vr_state
-       mfspr   r6, SPRN_VRSAVE
-       stw     r6, VCPU_VRSAVE_TM(r9)
-1:
-       /*
-        * We need to save these SPRs after the treclaim so that the software
-        * error code is recorded correctly in the TEXASR.  Also the user may
-        * change these outside of a transaction, so they must always be
-        * context switched.
-        */
-       mfspr   r7, SPRN_TEXASR
-       std     r7, VCPU_TEXASR(r9)
-11:
        mfspr   r5, SPRN_TFHAR
        mfspr   r6, SPRN_TFIAR
        std     r5, VCPU_TFHAR(r9)
@@ -3299,149 +3219,63 @@ END_FTR_SECTION_IFSET(CPU_FTR_P9_TM_HV_ASSIST)
 
 /*
  * Restore transactional state and TM-related registers.
- * Called with r4 pointing to the vcpu struct.
+ * Called with r3 pointing to the vcpu struct
+ * and r4 containing the guest MSR value.
  * This potentially modifies all checkpointed registers.
- * It restores r1, r2, r4 from the PACA.
+ * It restores r1 and r2 from the PACA.
  */
-kvmppc_restore_tm:
+kvmppc_restore_tm_hv:
+       /*
+        * If we are doing TM emulation for the guest on a POWER9 DD2,
+        * then we don't actually do a trechkpt -- we either set up
+        * fake-suspend mode, or emulate a TM rollback.
+        */
+BEGIN_FTR_SECTION
+       b       __kvmppc_restore_tm
+END_FTR_SECTION_IFCLR(CPU_FTR_P9_TM_HV_ASSIST)
        mflr    r0
        std     r0, PPC_LR_STKOFF(r1)
 
-       /* Turn on TM/FP/VSX/VMX so we can restore them. */
+       li      r0, 0
+       stb     r0, HSTATE_FAKE_SUSPEND(r13)
+
+       /* Turn on TM so we can restore TM SPRs */
        mfmsr   r5
-       li      r6, MSR_TM >> 32
-       sldi    r6, r6, 32
-       or      r5, r5, r6
-       ori     r5, r5, MSR_FP
-       oris    r5, r5, (MSR_VEC | MSR_VSX)@h
+       li      r0, 1
+       rldimi  r5, r0, MSR_TM_LG, 63-MSR_TM_LG
        mtmsrd  r5
 
        /*
         * The user may change these outside of a transaction, so they must
         * always be context switched.
         */
-       ld      r5, VCPU_TFHAR(r4)
-       ld      r6, VCPU_TFIAR(r4)
-       ld      r7, VCPU_TEXASR(r4)
+       ld      r5, VCPU_TFHAR(r3)
+       ld      r6, VCPU_TFIAR(r3)
+       ld      r7, VCPU_TEXASR(r3)
        mtspr   SPRN_TFHAR, r5
        mtspr   SPRN_TFIAR, r6
        mtspr   SPRN_TEXASR, r7
 
-       li      r0, 0
-       stb     r0, HSTATE_FAKE_SUSPEND(r13)
-       ld      r5, VCPU_MSR(r4)
-       rldicl. r5, r5, 64 - MSR_TS_S_LG, 62
+       rldicl. r5, r4, 64 - MSR_TS_S_LG, 62
        beqlr           /* TM not active in guest */
-       std     r1, HSTATE_HOST_R1(r13)
 
-       /* Make sure the failure summary is set, otherwise we'll program check
-        * when we trechkpt.  It's possible that this might have been not set
-        * on a kvmppc_set_one_reg() call but we shouldn't let this crash the
-        * host.
-        */
+       /* Make sure the failure summary is set */
        oris    r7, r7, (TEXASR_FS)@h
        mtspr   SPRN_TEXASR, r7
 
-       /*
-        * If we are doing TM emulation for the guest on a POWER9 DD2,
-        * then we don't actually do a trechkpt -- we either set up
-        * fake-suspend mode, or emulate a TM rollback.
-        */
-BEGIN_FTR_SECTION
-       b       .Ldo_tm_fake_load
-END_FTR_SECTION_IFSET(CPU_FTR_P9_TM_HV_ASSIST)
-
-       /*
-        * We need to load up the checkpointed state for the guest.
-        * We need to do this early as it will blow away any GPRs, VSRs and
-        * some SPRs.
-        */
-
-       mr      r31, r4
-       addi    r3, r31, VCPU_FPRS_TM
-       bl      load_fp_state
-       addi    r3, r31, VCPU_VRS_TM
-       bl      load_vr_state
-       mr      r4, r31
-       lwz     r7, VCPU_VRSAVE_TM(r4)
-       mtspr   SPRN_VRSAVE, r7
-
-       ld      r5, VCPU_LR_TM(r4)
-       lwz     r6, VCPU_CR_TM(r4)
-       ld      r7, VCPU_CTR_TM(r4)
-       ld      r8, VCPU_AMR_TM(r4)
-       ld      r9, VCPU_TAR_TM(r4)
-       ld      r10, VCPU_XER_TM(r4)
-       mtlr    r5
-       mtcr    r6
-       mtctr   r7
-       mtspr   SPRN_AMR, r8
-       mtspr   SPRN_TAR, r9
-       mtxer   r10
-
-       /*
-        * Load up PPR and DSCR values but don't put them in the actual SPRs
-        * till the last moment to avoid running with userspace PPR and DSCR for
-        * too long.
-        */
-       ld      r29, VCPU_DSCR_TM(r4)
-       ld      r30, VCPU_PPR_TM(r4)
-
-       std     r2, PACATMSCRATCH(r13) /* Save TOC */
-
-       /* Clear the MSR RI since r1, r13 are all going to be foobar. */
-       li      r5, 0
-       mtmsrd  r5, 1
-
-       /* Load GPRs r0-r28 */
-       reg = 0
-       .rept   29
-       ld      reg, VCPU_GPRS_TM(reg)(r31)
-       reg = reg + 1
-       .endr
-
-       mtspr   SPRN_DSCR, r29
-       mtspr   SPRN_PPR, r30
-
-       /* Load final GPRs */
-       ld      29, VCPU_GPRS_TM(29)(r31)
-       ld      30, VCPU_GPRS_TM(30)(r31)
-       ld      31, VCPU_GPRS_TM(31)(r31)
-
-       /* TM checkpointed state is now setup.  All GPRs are now volatile. */
-       TRECHKPT
-
-       /* Now let's get back the state we need. */
-       HMT_MEDIUM
-       GET_PACA(r13)
-       ld      r29, HSTATE_DSCR(r13)
-       mtspr   SPRN_DSCR, r29
-       ld      r4, HSTATE_KVM_VCPU(r13)
-       ld      r1, HSTATE_HOST_R1(r13)
-       ld      r2, PACATMSCRATCH(r13)
-
-       /* Set the MSR RI since we have our registers back. */
-       li      r5, MSR_RI
-       mtmsrd  r5, 1
-9:
-       ld      r0, PPC_LR_STKOFF(r1)
-       mtlr    r0
-       blr
-
-.Ldo_tm_fake_load:
        cmpwi   r5, 1           /* check for suspended state */
        bgt     10f
        stb     r5, HSTATE_FAKE_SUSPEND(r13)
-       b       9b              /* and return */
+       b       9f              /* and return */
 10:    stdu    r1, -PPC_MIN_STKFRM(r1)
        /* guest is in transactional state, so simulate rollback */
-       mr      r3, r4
        bl      kvmhv_emulate_tm_rollback
        nop
-       ld      r4, HSTATE_KVM_VCPU(r13) /* our vcpu pointer has been trashed */
        addi    r1, r1, PPC_MIN_STKFRM
-       b       9b
-#endif
+9:     ld      r0, PPC_LR_STKOFF(r1)
+       mtlr    r0
+       blr
+#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
 
 /*
  * We come here if we get any exception or interrupt while we are
@@ -3572,6 +3406,8 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_RADIX)
        bcl     20, 31, .+4
 5:     mflr    r3
        addi    r3, r3, 9f - 5b
+       li      r4, -1
+       rldimi  r3, r4, 62, 0   /* ensure 0xc000000000000000 bits are set */
        ld      r4, PACAKMSR(r13)
        mtspr   SPRN_SRR0, r3
        mtspr   SPRN_SRR1, r4
index bf710ad3a6d71449bce9ba6a05fe9de577853280..008285058f9b554616cb52fdc53a85843826ae23 100644 (file)
@@ -19,7 +19,7 @@ static void emulate_tx_failure(struct kvm_vcpu *vcpu, u64 failure_cause)
        u64 texasr, tfiar;
        u64 msr = vcpu->arch.shregs.msr;
 
-       tfiar = vcpu->arch.pc & ~0x3ull;
+       tfiar = vcpu->arch.regs.nip & ~0x3ull;
        texasr = (failure_cause << 56) | TEXASR_ABORT | TEXASR_FS | TEXASR_EXACT;
        if (MSR_TM_SUSPENDED(vcpu->arch.shregs.msr))
                texasr |= TEXASR_SUSP;
@@ -57,8 +57,8 @@ int kvmhv_p9_tm_emulation(struct kvm_vcpu *vcpu)
                               (newmsr & MSR_TM)));
                newmsr = sanitize_msr(newmsr);
                vcpu->arch.shregs.msr = newmsr;
-               vcpu->arch.cfar = vcpu->arch.pc - 4;
-               vcpu->arch.pc = vcpu->arch.shregs.srr0;
+               vcpu->arch.cfar = vcpu->arch.regs.nip - 4;
+               vcpu->arch.regs.nip = vcpu->arch.shregs.srr0;
                return RESUME_GUEST;
 
        case PPC_INST_RFEBB:
@@ -90,8 +90,8 @@ int kvmhv_p9_tm_emulation(struct kvm_vcpu *vcpu)
                vcpu->arch.bescr = bescr;
                msr = (msr & ~MSR_TS_MASK) | MSR_TS_T;
                vcpu->arch.shregs.msr = msr;
-               vcpu->arch.cfar = vcpu->arch.pc - 4;
-               vcpu->arch.pc = vcpu->arch.ebbrr;
+               vcpu->arch.cfar = vcpu->arch.regs.nip - 4;
+               vcpu->arch.regs.nip = vcpu->arch.ebbrr;
                return RESUME_GUEST;
 
        case PPC_INST_MTMSRD:
index d98ccfd2b88cd5379c3aefe086347466135d38a4..b2c7c6fca4f96e5a315371e39ec9d25dc220da8d 100644 (file)
@@ -35,8 +35,8 @@ int kvmhv_p9_tm_emulation_early(struct kvm_vcpu *vcpu)
                        return 0;
                newmsr = sanitize_msr(newmsr);
                vcpu->arch.shregs.msr = newmsr;
-               vcpu->arch.cfar = vcpu->arch.pc - 4;
-               vcpu->arch.pc = vcpu->arch.shregs.srr0;
+               vcpu->arch.cfar = vcpu->arch.regs.nip - 4;
+               vcpu->arch.regs.nip = vcpu->arch.shregs.srr0;
                return 1;
 
        case PPC_INST_RFEBB:
@@ -58,8 +58,8 @@ int kvmhv_p9_tm_emulation_early(struct kvm_vcpu *vcpu)
                mtspr(SPRN_BESCR, bescr);
                msr = (msr & ~MSR_TS_MASK) | MSR_TS_T;
                vcpu->arch.shregs.msr = msr;
-               vcpu->arch.cfar = vcpu->arch.pc - 4;
-               vcpu->arch.pc = mfspr(SPRN_EBBRR);
+               vcpu->arch.cfar = vcpu->arch.regs.nip - 4;
+               vcpu->arch.regs.nip = mfspr(SPRN_EBBRR);
                return 1;
 
        case PPC_INST_MTMSRD:
@@ -103,7 +103,7 @@ int kvmhv_p9_tm_emulation_early(struct kvm_vcpu *vcpu)
 void kvmhv_emulate_tm_rollback(struct kvm_vcpu *vcpu)
 {
        vcpu->arch.shregs.msr &= ~MSR_TS_MASK;  /* go to N state */
-       vcpu->arch.pc = vcpu->arch.tfhar;
+       vcpu->arch.regs.nip = vcpu->arch.tfhar;
        copy_from_checkpoint(vcpu);
        vcpu->arch.cr = (vcpu->arch.cr & 0x0fffffff) | 0xa0000000;
 }
index d3f304d06adfcb27dfd87b890b2fde37152d877d..c3b8006f0eac14a5d1f35a7b9b31f5fe106b98b8 100644 (file)
@@ -42,6 +42,8 @@
 #include <linux/highmem.h>
 #include <linux/module.h>
 #include <linux/miscdevice.h>
+#include <asm/asm-prototypes.h>
+#include <asm/tm.h>
 
 #include "book3s.h"
 
@@ -53,7 +55,9 @@
 
 static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr,
                             ulong msr);
-static void kvmppc_giveup_fac(struct kvm_vcpu *vcpu, ulong fac);
+#ifdef CONFIG_PPC_BOOK3S_64
+static int kvmppc_handle_fac(struct kvm_vcpu *vcpu, ulong fac);
+#endif
 
 /* Some compatibility defines */
 #ifdef CONFIG_PPC_BOOK3S_32
@@ -114,6 +118,8 @@ static void kvmppc_core_vcpu_load_pr(struct kvm_vcpu *vcpu, int cpu)
 
        if (kvmppc_is_split_real(vcpu))
                kvmppc_fixup_split_real(vcpu);
+
+       kvmppc_restore_tm_pr(vcpu);
 }
 
 static void kvmppc_core_vcpu_put_pr(struct kvm_vcpu *vcpu)
@@ -133,6 +139,7 @@ static void kvmppc_core_vcpu_put_pr(struct kvm_vcpu *vcpu)
 
        kvmppc_giveup_ext(vcpu, MSR_FP | MSR_VEC | MSR_VSX);
        kvmppc_giveup_fac(vcpu, FSCR_TAR_LG);
+       kvmppc_save_tm_pr(vcpu);
 
        /* Enable AIL if supported */
        if (cpu_has_feature(CPU_FTR_HVMODE) &&
@@ -147,25 +154,25 @@ void kvmppc_copy_to_svcpu(struct kvm_vcpu *vcpu)
 {
        struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
 
-       svcpu->gpr[0] = vcpu->arch.gpr[0];
-       svcpu->gpr[1] = vcpu->arch.gpr[1];
-       svcpu->gpr[2] = vcpu->arch.gpr[2];
-       svcpu->gpr[3] = vcpu->arch.gpr[3];
-       svcpu->gpr[4] = vcpu->arch.gpr[4];
-       svcpu->gpr[5] = vcpu->arch.gpr[5];
-       svcpu->gpr[6] = vcpu->arch.gpr[6];
-       svcpu->gpr[7] = vcpu->arch.gpr[7];
-       svcpu->gpr[8] = vcpu->arch.gpr[8];
-       svcpu->gpr[9] = vcpu->arch.gpr[9];
-       svcpu->gpr[10] = vcpu->arch.gpr[10];
-       svcpu->gpr[11] = vcpu->arch.gpr[11];
-       svcpu->gpr[12] = vcpu->arch.gpr[12];
-       svcpu->gpr[13] = vcpu->arch.gpr[13];
+       svcpu->gpr[0] = vcpu->arch.regs.gpr[0];
+       svcpu->gpr[1] = vcpu->arch.regs.gpr[1];
+       svcpu->gpr[2] = vcpu->arch.regs.gpr[2];
+       svcpu->gpr[3] = vcpu->arch.regs.gpr[3];
+       svcpu->gpr[4] = vcpu->arch.regs.gpr[4];
+       svcpu->gpr[5] = vcpu->arch.regs.gpr[5];
+       svcpu->gpr[6] = vcpu->arch.regs.gpr[6];
+       svcpu->gpr[7] = vcpu->arch.regs.gpr[7];
+       svcpu->gpr[8] = vcpu->arch.regs.gpr[8];
+       svcpu->gpr[9] = vcpu->arch.regs.gpr[9];
+       svcpu->gpr[10] = vcpu->arch.regs.gpr[10];
+       svcpu->gpr[11] = vcpu->arch.regs.gpr[11];
+       svcpu->gpr[12] = vcpu->arch.regs.gpr[12];
+       svcpu->gpr[13] = vcpu->arch.regs.gpr[13];
        svcpu->cr  = vcpu->arch.cr;
-       svcpu->xer = vcpu->arch.xer;
-       svcpu->ctr = vcpu->arch.ctr;
-       svcpu->lr  = vcpu->arch.lr;
-       svcpu->pc  = vcpu->arch.pc;
+       svcpu->xer = vcpu->arch.regs.xer;
+       svcpu->ctr = vcpu->arch.regs.ctr;
+       svcpu->lr  = vcpu->arch.regs.link;
+       svcpu->pc  = vcpu->arch.regs.nip;
 #ifdef CONFIG_PPC_BOOK3S_64
        svcpu->shadow_fscr = vcpu->arch.shadow_fscr;
 #endif
@@ -182,10 +189,45 @@ void kvmppc_copy_to_svcpu(struct kvm_vcpu *vcpu)
        svcpu_put(svcpu);
 }
 
+static void kvmppc_recalc_shadow_msr(struct kvm_vcpu *vcpu)
+{
+       ulong guest_msr = kvmppc_get_msr(vcpu);
+       ulong smsr = guest_msr;
+
+       /* Guest MSR values */
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       smsr &= MSR_FE0 | MSR_FE1 | MSR_SF | MSR_SE | MSR_BE | MSR_LE |
+               MSR_TM | MSR_TS_MASK;
+#else
+       smsr &= MSR_FE0 | MSR_FE1 | MSR_SF | MSR_SE | MSR_BE | MSR_LE;
+#endif
+       /* Process MSR values */
+       smsr |= MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_PR | MSR_EE;
+       /* External providers the guest reserved */
+       smsr |= (guest_msr & vcpu->arch.guest_owned_ext);
+       /* 64-bit Process MSR values */
+#ifdef CONFIG_PPC_BOOK3S_64
+       smsr |= MSR_ISF | MSR_HV;
+#endif
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       /*
+        * in guest privileged state, we want to fail all TM transactions.
+        * So disable MSR TM bit so that all tbegin. will be able to be
+        * trapped into host.
+        */
+       if (!(guest_msr & MSR_PR))
+               smsr &= ~MSR_TM;
+#endif
+       vcpu->arch.shadow_msr = smsr;
+}
+
 /* Copy data touched by real-mode code from shadow vcpu back to vcpu */
 void kvmppc_copy_from_svcpu(struct kvm_vcpu *vcpu)
 {
        struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       ulong old_msr;
+#endif
 
        /*
         * Maybe we were already preempted and synced the svcpu from
@@ -194,25 +236,25 @@ void kvmppc_copy_from_svcpu(struct kvm_vcpu *vcpu)
        if (!svcpu->in_use)
                goto out;
 
-       vcpu->arch.gpr[0] = svcpu->gpr[0];
-       vcpu->arch.gpr[1] = svcpu->gpr[1];
-       vcpu->arch.gpr[2] = svcpu->gpr[2];
-       vcpu->arch.gpr[3] = svcpu->gpr[3];
-       vcpu->arch.gpr[4] = svcpu->gpr[4];
-       vcpu->arch.gpr[5] = svcpu->gpr[5];
-       vcpu->arch.gpr[6] = svcpu->gpr[6];
-       vcpu->arch.gpr[7] = svcpu->gpr[7];
-       vcpu->arch.gpr[8] = svcpu->gpr[8];
-       vcpu->arch.gpr[9] = svcpu->gpr[9];
-       vcpu->arch.gpr[10] = svcpu->gpr[10];
-       vcpu->arch.gpr[11] = svcpu->gpr[11];
-       vcpu->arch.gpr[12] = svcpu->gpr[12];
-       vcpu->arch.gpr[13] = svcpu->gpr[13];
+       vcpu->arch.regs.gpr[0] = svcpu->gpr[0];
+       vcpu->arch.regs.gpr[1] = svcpu->gpr[1];
+       vcpu->arch.regs.gpr[2] = svcpu->gpr[2];
+       vcpu->arch.regs.gpr[3] = svcpu->gpr[3];
+       vcpu->arch.regs.gpr[4] = svcpu->gpr[4];
+       vcpu->arch.regs.gpr[5] = svcpu->gpr[5];
+       vcpu->arch.regs.gpr[6] = svcpu->gpr[6];
+       vcpu->arch.regs.gpr[7] = svcpu->gpr[7];
+       vcpu->arch.regs.gpr[8] = svcpu->gpr[8];
+       vcpu->arch.regs.gpr[9] = svcpu->gpr[9];
+       vcpu->arch.regs.gpr[10] = svcpu->gpr[10];
+       vcpu->arch.regs.gpr[11] = svcpu->gpr[11];
+       vcpu->arch.regs.gpr[12] = svcpu->gpr[12];
+       vcpu->arch.regs.gpr[13] = svcpu->gpr[13];
        vcpu->arch.cr  = svcpu->cr;
-       vcpu->arch.xer = svcpu->xer;
-       vcpu->arch.ctr = svcpu->ctr;
-       vcpu->arch.lr  = svcpu->lr;
-       vcpu->arch.pc  = svcpu->pc;
+       vcpu->arch.regs.xer = svcpu->xer;
+       vcpu->arch.regs.ctr = svcpu->ctr;
+       vcpu->arch.regs.link  = svcpu->lr;
+       vcpu->arch.regs.nip  = svcpu->pc;
        vcpu->arch.shadow_srr1 = svcpu->shadow_srr1;
        vcpu->arch.fault_dar   = svcpu->fault_dar;
        vcpu->arch.fault_dsisr = svcpu->fault_dsisr;
@@ -228,12 +270,116 @@ void kvmppc_copy_from_svcpu(struct kvm_vcpu *vcpu)
        to_book3s(vcpu)->vtb += get_vtb() - vcpu->arch.entry_vtb;
        if (cpu_has_feature(CPU_FTR_ARCH_207S))
                vcpu->arch.ic += mfspr(SPRN_IC) - vcpu->arch.entry_ic;
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       /*
+        * Unlike other MSR bits, MSR[TS]bits can be changed at guest without
+        * notifying host:
+        *  modified by unprivileged instructions like "tbegin"/"tend"/
+        * "tresume"/"tsuspend" in PR KVM guest.
+        *
+        * It is necessary to sync here to calculate a correct shadow_msr.
+        *
+        * privileged guest's tbegin will be failed at present. So we
+        * only take care of problem state guest.
+        */
+       old_msr = kvmppc_get_msr(vcpu);
+       if (unlikely((old_msr & MSR_PR) &&
+               (vcpu->arch.shadow_srr1 & (MSR_TS_MASK)) !=
+                               (old_msr & (MSR_TS_MASK)))) {
+               old_msr &= ~(MSR_TS_MASK);
+               old_msr |= (vcpu->arch.shadow_srr1 & (MSR_TS_MASK));
+               kvmppc_set_msr_fast(vcpu, old_msr);
+               kvmppc_recalc_shadow_msr(vcpu);
+       }
+#endif
+
        svcpu->in_use = false;
 
 out:
        svcpu_put(svcpu);
 }
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+void kvmppc_save_tm_sprs(struct kvm_vcpu *vcpu)
+{
+       tm_enable();
+       vcpu->arch.tfhar = mfspr(SPRN_TFHAR);
+       vcpu->arch.texasr = mfspr(SPRN_TEXASR);
+       vcpu->arch.tfiar = mfspr(SPRN_TFIAR);
+       tm_disable();
+}
+
+void kvmppc_restore_tm_sprs(struct kvm_vcpu *vcpu)
+{
+       tm_enable();
+       mtspr(SPRN_TFHAR, vcpu->arch.tfhar);
+       mtspr(SPRN_TEXASR, vcpu->arch.texasr);
+       mtspr(SPRN_TFIAR, vcpu->arch.tfiar);
+       tm_disable();
+}
+
+/* loadup math bits which is enabled at kvmppc_get_msr() but not enabled at
+ * hardware.
+ */
+static void kvmppc_handle_lost_math_exts(struct kvm_vcpu *vcpu)
+{
+       ulong exit_nr;
+       ulong ext_diff = (kvmppc_get_msr(vcpu) & ~vcpu->arch.guest_owned_ext) &
+               (MSR_FP | MSR_VEC | MSR_VSX);
+
+       if (!ext_diff)
+               return;
+
+       if (ext_diff == MSR_FP)
+               exit_nr = BOOK3S_INTERRUPT_FP_UNAVAIL;
+       else if (ext_diff == MSR_VEC)
+               exit_nr = BOOK3S_INTERRUPT_ALTIVEC;
+       else
+               exit_nr = BOOK3S_INTERRUPT_VSX;
+
+       kvmppc_handle_ext(vcpu, exit_nr, ext_diff);
+}
+
+void kvmppc_save_tm_pr(struct kvm_vcpu *vcpu)
+{
+       if (!(MSR_TM_ACTIVE(kvmppc_get_msr(vcpu)))) {
+               kvmppc_save_tm_sprs(vcpu);
+               return;
+       }
+
+       kvmppc_giveup_fac(vcpu, FSCR_TAR_LG);
+       kvmppc_giveup_ext(vcpu, MSR_VSX);
+
+       preempt_disable();
+       _kvmppc_save_tm_pr(vcpu, mfmsr());
+       preempt_enable();
+}
+
+void kvmppc_restore_tm_pr(struct kvm_vcpu *vcpu)
+{
+       if (!MSR_TM_ACTIVE(kvmppc_get_msr(vcpu))) {
+               kvmppc_restore_tm_sprs(vcpu);
+               if (kvmppc_get_msr(vcpu) & MSR_TM) {
+                       kvmppc_handle_lost_math_exts(vcpu);
+                       if (vcpu->arch.fscr & FSCR_TAR)
+                               kvmppc_handle_fac(vcpu, FSCR_TAR_LG);
+               }
+               return;
+       }
+
+       preempt_disable();
+       _kvmppc_restore_tm_pr(vcpu, kvmppc_get_msr(vcpu));
+       preempt_enable();
+
+       if (kvmppc_get_msr(vcpu) & MSR_TM) {
+               kvmppc_handle_lost_math_exts(vcpu);
+               if (vcpu->arch.fscr & FSCR_TAR)
+                       kvmppc_handle_fac(vcpu, FSCR_TAR_LG);
+       }
+}
+#endif
+
 static int kvmppc_core_check_requests_pr(struct kvm_vcpu *vcpu)
 {
        int r = 1; /* Indicate we want to get back into the guest */
@@ -306,32 +452,29 @@ static void kvm_set_spte_hva_pr(struct kvm *kvm, unsigned long hva, pte_t pte)
 
 /*****************************************/
 
-static void kvmppc_recalc_shadow_msr(struct kvm_vcpu *vcpu)
-{
-       ulong guest_msr = kvmppc_get_msr(vcpu);
-       ulong smsr = guest_msr;
-
-       /* Guest MSR values */
-       smsr &= MSR_FE0 | MSR_FE1 | MSR_SF | MSR_SE | MSR_BE | MSR_LE;
-       /* Process MSR values */
-       smsr |= MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_PR | MSR_EE;
-       /* External providers the guest reserved */
-       smsr |= (guest_msr & vcpu->arch.guest_owned_ext);
-       /* 64-bit Process MSR values */
-#ifdef CONFIG_PPC_BOOK3S_64
-       smsr |= MSR_ISF | MSR_HV;
-#endif
-       vcpu->arch.shadow_msr = smsr;
-}
-
 static void kvmppc_set_msr_pr(struct kvm_vcpu *vcpu, u64 msr)
 {
-       ulong old_msr = kvmppc_get_msr(vcpu);
+       ulong old_msr;
+
+       /* For PAPR guest, make sure MSR reflects guest mode */
+       if (vcpu->arch.papr_enabled)
+               msr = (msr & ~MSR_HV) | MSR_ME;
 
 #ifdef EXIT_DEBUG
        printk(KERN_INFO "KVM: Set MSR to 0x%llx\n", msr);
 #endif
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       /* We should never target guest MSR to TS=10 && PR=0,
+        * since we always fail transaction for guest privilege
+        * state.
+        */
+       if (!(msr & MSR_PR) && MSR_TM_TRANSACTIONAL(msr))
+               kvmppc_emulate_tabort(vcpu,
+                       TM_CAUSE_KVM_FAC_UNAV | TM_CAUSE_PERSISTENT);
+#endif
+
+       old_msr = kvmppc_get_msr(vcpu);
        msr &= to_book3s(vcpu)->msr_mask;
        kvmppc_set_msr_fast(vcpu, msr);
        kvmppc_recalc_shadow_msr(vcpu);
@@ -387,6 +530,11 @@ static void kvmppc_set_msr_pr(struct kvm_vcpu *vcpu, u64 msr)
        /* Preload FPU if it's enabled */
        if (kvmppc_get_msr(vcpu) & MSR_FP)
                kvmppc_handle_ext(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, MSR_FP);
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       if (kvmppc_get_msr(vcpu) & MSR_TM)
+               kvmppc_handle_lost_math_exts(vcpu);
+#endif
 }
 
 void kvmppc_set_pvr_pr(struct kvm_vcpu *vcpu, u32 pvr)
@@ -584,24 +732,20 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
                pte.may_execute = !data;
        }
 
-       if (page_found == -ENOENT) {
-               /* Page not found in guest PTE entries */
-               u64 ssrr1 = vcpu->arch.shadow_srr1;
-               u64 msr = kvmppc_get_msr(vcpu);
-               kvmppc_set_dar(vcpu, kvmppc_get_fault_dar(vcpu));
-               kvmppc_set_dsisr(vcpu, vcpu->arch.fault_dsisr);
-               kvmppc_set_msr_fast(vcpu, msr | (ssrr1 & 0xf8000000ULL));
-               kvmppc_book3s_queue_irqprio(vcpu, vec);
-       } else if (page_found == -EPERM) {
-               /* Storage protection */
-               u32 dsisr = vcpu->arch.fault_dsisr;
-               u64 ssrr1 = vcpu->arch.shadow_srr1;
-               u64 msr = kvmppc_get_msr(vcpu);
-               kvmppc_set_dar(vcpu, kvmppc_get_fault_dar(vcpu));
-               dsisr = (dsisr & ~DSISR_NOHPTE) | DSISR_PROTFAULT;
-               kvmppc_set_dsisr(vcpu, dsisr);
-               kvmppc_set_msr_fast(vcpu, msr | (ssrr1 & 0xf8000000ULL));
-               kvmppc_book3s_queue_irqprio(vcpu, vec);
+       if (page_found == -ENOENT || page_found == -EPERM) {
+               /* Page not found in guest PTE entries, or protection fault */
+               u64 flags;
+
+               if (page_found == -EPERM)
+                       flags = DSISR_PROTFAULT;
+               else
+                       flags = DSISR_NOHPTE;
+               if (data) {
+                       flags |= vcpu->arch.fault_dsisr & DSISR_ISSTORE;
+                       kvmppc_core_queue_data_storage(vcpu, eaddr, flags);
+               } else {
+                       kvmppc_core_queue_inst_storage(vcpu, flags);
+               }
        } else if (page_found == -EINVAL) {
                /* Page not found in guest SLB */
                kvmppc_set_dar(vcpu, kvmppc_get_fault_dar(vcpu));
@@ -683,7 +827,7 @@ void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr)
 }
 
 /* Give up facility (TAR / EBB / DSCR) */
-static void kvmppc_giveup_fac(struct kvm_vcpu *vcpu, ulong fac)
+void kvmppc_giveup_fac(struct kvm_vcpu *vcpu, ulong fac)
 {
 #ifdef CONFIG_PPC_BOOK3S_64
        if (!(vcpu->arch.shadow_fscr & (1ULL << fac))) {
@@ -802,7 +946,7 @@ static void kvmppc_handle_lost_ext(struct kvm_vcpu *vcpu)
 
 #ifdef CONFIG_PPC_BOOK3S_64
 
-static void kvmppc_trigger_fac_interrupt(struct kvm_vcpu *vcpu, ulong fac)
+void kvmppc_trigger_fac_interrupt(struct kvm_vcpu *vcpu, ulong fac)
 {
        /* Inject the Interrupt Cause field and trigger a guest interrupt */
        vcpu->arch.fscr &= ~(0xffULL << 56);
@@ -864,6 +1008,18 @@ static int kvmppc_handle_fac(struct kvm_vcpu *vcpu, ulong fac)
                break;
        }
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       /* Since we disabled MSR_TM at privilege state, the mfspr instruction
+        * for TM spr can trigger TM fac unavailable. In this case, the
+        * emulation is handled by kvmppc_emulate_fac(), which invokes
+        * kvmppc_emulate_mfspr() finally. But note the mfspr can include
+        * RT for NV registers. So it need to restore those NV reg to reflect
+        * the update.
+        */
+       if ((fac == FSCR_TM_LG) && !(kvmppc_get_msr(vcpu) & MSR_PR))
+               return RESUME_GUEST_NV;
+#endif
+
        return RESUME_GUEST;
 }
 
@@ -872,7 +1028,12 @@ void kvmppc_set_fscr(struct kvm_vcpu *vcpu, u64 fscr)
        if ((vcpu->arch.fscr & FSCR_TAR) && !(fscr & FSCR_TAR)) {
                /* TAR got dropped, drop it in shadow too */
                kvmppc_giveup_fac(vcpu, FSCR_TAR_LG);
+       } else if (!(vcpu->arch.fscr & FSCR_TAR) && (fscr & FSCR_TAR)) {
+               vcpu->arch.fscr = fscr;
+               kvmppc_handle_fac(vcpu, FSCR_TAR_LG);
+               return;
        }
+
        vcpu->arch.fscr = fscr;
 }
 #endif
@@ -1017,10 +1178,8 @@ int kvmppc_handle_exit_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
                        kvmppc_mmu_pte_flush(vcpu, kvmppc_get_pc(vcpu), ~0xFFFUL);
                        r = RESUME_GUEST;
                } else {
-                       u64 msr = kvmppc_get_msr(vcpu);
-                       msr |= shadow_srr1 & 0x58000000;
-                       kvmppc_set_msr_fast(vcpu, msr);
-                       kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
+                       kvmppc_core_queue_inst_storage(vcpu,
+                                               shadow_srr1 & 0x58000000);
                        r = RESUME_GUEST;
                }
                break;
@@ -1059,9 +1218,7 @@ int kvmppc_handle_exit_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
                        r = kvmppc_handle_pagefault(run, vcpu, dar, exit_nr);
                        srcu_read_unlock(&vcpu->kvm->srcu, idx);
                } else {
-                       kvmppc_set_dar(vcpu, dar);
-                       kvmppc_set_dsisr(vcpu, fault_dsisr);
-                       kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
+                       kvmppc_core_queue_data_storage(vcpu, dar, fault_dsisr);
                        r = RESUME_GUEST;
                }
                break;
@@ -1092,10 +1249,13 @@ int kvmppc_handle_exit_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
        case BOOK3S_INTERRUPT_EXTERNAL:
        case BOOK3S_INTERRUPT_EXTERNAL_LEVEL:
        case BOOK3S_INTERRUPT_EXTERNAL_HV:
+       case BOOK3S_INTERRUPT_H_VIRT:
                vcpu->stat.ext_intr_exits++;
                r = RESUME_GUEST;
                break;
+       case BOOK3S_INTERRUPT_HMI:
        case BOOK3S_INTERRUPT_PERFMON:
+       case BOOK3S_INTERRUPT_SYSTEM_RESET:
                r = RESUME_GUEST;
                break;
        case BOOK3S_INTERRUPT_PROGRAM:
@@ -1225,8 +1385,7 @@ int kvmppc_handle_exit_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
        }
 #ifdef CONFIG_PPC_BOOK3S_64
        case BOOK3S_INTERRUPT_FAC_UNAVAIL:
-               kvmppc_handle_fac(vcpu, vcpu->arch.shadow_fscr >> 56);
-               r = RESUME_GUEST;
+               r = kvmppc_handle_fac(vcpu, vcpu->arch.shadow_fscr >> 56);
                break;
 #endif
        case BOOK3S_INTERRUPT_MACHINE_CHECK:
@@ -1379,6 +1538,73 @@ static int kvmppc_get_one_reg_pr(struct kvm_vcpu *vcpu, u64 id,
                else
                        *val = get_reg_val(id, 0);
                break;
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       case KVM_REG_PPC_TFHAR:
+               *val = get_reg_val(id, vcpu->arch.tfhar);
+               break;
+       case KVM_REG_PPC_TFIAR:
+               *val = get_reg_val(id, vcpu->arch.tfiar);
+               break;
+       case KVM_REG_PPC_TEXASR:
+               *val = get_reg_val(id, vcpu->arch.texasr);
+               break;
+       case KVM_REG_PPC_TM_GPR0 ... KVM_REG_PPC_TM_GPR31:
+               *val = get_reg_val(id,
+                               vcpu->arch.gpr_tm[id-KVM_REG_PPC_TM_GPR0]);
+               break;
+       case KVM_REG_PPC_TM_VSR0 ... KVM_REG_PPC_TM_VSR63:
+       {
+               int i, j;
+
+               i = id - KVM_REG_PPC_TM_VSR0;
+               if (i < 32)
+                       for (j = 0; j < TS_FPRWIDTH; j++)
+                               val->vsxval[j] = vcpu->arch.fp_tm.fpr[i][j];
+               else {
+                       if (cpu_has_feature(CPU_FTR_ALTIVEC))
+                               val->vval = vcpu->arch.vr_tm.vr[i-32];
+                       else
+                               r = -ENXIO;
+               }
+               break;
+       }
+       case KVM_REG_PPC_TM_CR:
+               *val = get_reg_val(id, vcpu->arch.cr_tm);
+               break;
+       case KVM_REG_PPC_TM_XER:
+               *val = get_reg_val(id, vcpu->arch.xer_tm);
+               break;
+       case KVM_REG_PPC_TM_LR:
+               *val = get_reg_val(id, vcpu->arch.lr_tm);
+               break;
+       case KVM_REG_PPC_TM_CTR:
+               *val = get_reg_val(id, vcpu->arch.ctr_tm);
+               break;
+       case KVM_REG_PPC_TM_FPSCR:
+               *val = get_reg_val(id, vcpu->arch.fp_tm.fpscr);
+               break;
+       case KVM_REG_PPC_TM_AMR:
+               *val = get_reg_val(id, vcpu->arch.amr_tm);
+               break;
+       case KVM_REG_PPC_TM_PPR:
+               *val = get_reg_val(id, vcpu->arch.ppr_tm);
+               break;
+       case KVM_REG_PPC_TM_VRSAVE:
+               *val = get_reg_val(id, vcpu->arch.vrsave_tm);
+               break;
+       case KVM_REG_PPC_TM_VSCR:
+               if (cpu_has_feature(CPU_FTR_ALTIVEC))
+                       *val = get_reg_val(id, vcpu->arch.vr_tm.vscr.u[3]);
+               else
+                       r = -ENXIO;
+               break;
+       case KVM_REG_PPC_TM_DSCR:
+               *val = get_reg_val(id, vcpu->arch.dscr_tm);
+               break;
+       case KVM_REG_PPC_TM_TAR:
+               *val = get_reg_val(id, vcpu->arch.tar_tm);
+               break;
+#endif
        default:
                r = -EINVAL;
                break;
@@ -1412,6 +1638,72 @@ static int kvmppc_set_one_reg_pr(struct kvm_vcpu *vcpu, u64 id,
        case KVM_REG_PPC_LPCR_64:
                kvmppc_set_lpcr_pr(vcpu, set_reg_val(id, *val));
                break;
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       case KVM_REG_PPC_TFHAR:
+               vcpu->arch.tfhar = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_TFIAR:
+               vcpu->arch.tfiar = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_TEXASR:
+               vcpu->arch.texasr = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_TM_GPR0 ... KVM_REG_PPC_TM_GPR31:
+               vcpu->arch.gpr_tm[id - KVM_REG_PPC_TM_GPR0] =
+                       set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_TM_VSR0 ... KVM_REG_PPC_TM_VSR63:
+       {
+               int i, j;
+
+               i = id - KVM_REG_PPC_TM_VSR0;
+               if (i < 32)
+                       for (j = 0; j < TS_FPRWIDTH; j++)
+                               vcpu->arch.fp_tm.fpr[i][j] = val->vsxval[j];
+               else
+                       if (cpu_has_feature(CPU_FTR_ALTIVEC))
+                               vcpu->arch.vr_tm.vr[i-32] = val->vval;
+                       else
+                               r = -ENXIO;
+               break;
+       }
+       case KVM_REG_PPC_TM_CR:
+               vcpu->arch.cr_tm = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_TM_XER:
+               vcpu->arch.xer_tm = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_TM_LR:
+               vcpu->arch.lr_tm = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_TM_CTR:
+               vcpu->arch.ctr_tm = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_TM_FPSCR:
+               vcpu->arch.fp_tm.fpscr = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_TM_AMR:
+               vcpu->arch.amr_tm = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_TM_PPR:
+               vcpu->arch.ppr_tm = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_TM_VRSAVE:
+               vcpu->arch.vrsave_tm = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_TM_VSCR:
+               if (cpu_has_feature(CPU_FTR_ALTIVEC))
+                       vcpu->arch.vr.vscr.u[3] = set_reg_val(id, *val);
+               else
+                       r = -ENXIO;
+               break;
+       case KVM_REG_PPC_TM_DSCR:
+               vcpu->arch.dscr_tm = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_TM_TAR:
+               vcpu->arch.tar_tm = set_reg_val(id, *val);
+               break;
+#endif
        default:
                r = -EINVAL;
                break;
@@ -1687,6 +1979,17 @@ static int kvm_vm_ioctl_get_smmu_info_pr(struct kvm *kvm,
 
        return 0;
 }
+
+static int kvm_configure_mmu_pr(struct kvm *kvm, struct kvm_ppc_mmuv3_cfg *cfg)
+{
+       if (!cpu_has_feature(CPU_FTR_ARCH_300))
+               return -ENODEV;
+       /* Require flags and process table base and size to all be zero. */
+       if (cfg->flags || cfg->process_table)
+               return -EINVAL;
+       return 0;
+}
+
 #else
 static int kvm_vm_ioctl_get_smmu_info_pr(struct kvm *kvm,
                                         struct kvm_ppc_smmu_info *info)
@@ -1735,9 +2038,12 @@ static void kvmppc_core_destroy_vm_pr(struct kvm *kvm)
 static int kvmppc_core_check_processor_compat_pr(void)
 {
        /*
-        * Disable KVM for Power9 untill the required bits merged.
+        * PR KVM can work on POWER9 inside a guest partition
+        * running in HPT mode.  It can't work if we are using
+        * radix translation (because radix provides no way for
+        * a process to have unique translations in quadrant 3).
         */
-       if (cpu_has_feature(CPU_FTR_ARCH_300))
+       if (cpu_has_feature(CPU_FTR_ARCH_300) && radix_enabled())
                return -EIO;
        return 0;
 }
@@ -1781,7 +2087,9 @@ static struct kvmppc_ops kvm_ops_pr = {
        .arch_vm_ioctl  = kvm_arch_vm_ioctl_pr,
 #ifdef CONFIG_PPC_BOOK3S_64
        .hcall_implemented = kvmppc_hcall_impl_pr,
+       .configure_mmu = kvm_configure_mmu_pr,
 #endif
+       .giveup_ext = kvmppc_giveup_ext,
 };
 
 
index 93a180ceefad03343d1f9064420ee00ca54973d7..98ccc7ec5d488c18c99f452d32ca22770ebf6b8d 100644 (file)
@@ -383,6 +383,19 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
         */
 
        PPC_LL  r6, HSTATE_HOST_MSR(r13)
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       /*
+        * We don't want to change MSR[TS] bits via rfi here.
+        * The actual TM handling logic will be in host with
+        * recovered DR/IR bits after HSTATE_VMHANDLER.
+        * And MSR_TM can be enabled in HOST_MSR so rfid may
+        * not suppress this change and can lead to exception.
+        * Manually set MSR to prevent TS state change here.
+        */
+       mfmsr   r7
+       rldicl  r7, r7, 64 - MSR_TS_S_LG, 62
+       rldimi  r6, r7, MSR_TS_S_LG, 63 - MSR_TS_T_LG
+#endif
        PPC_LL  r8, HSTATE_VMHANDLER(r13)
 
 #ifdef CONFIG_PPC64
index 99c3620b40d95b91481a5485ab6e2649ea40c37c..6e41ba7ec8f45b8c7861f038820e18b5d9cbb507 100644 (file)
@@ -334,7 +334,7 @@ X_STATIC unsigned long GLUE(X_PFX,h_xirr)(struct kvm_vcpu *vcpu)
         */
 
        /* Return interrupt and old CPPR in GPR4 */
-       vcpu->arch.gpr[4] = hirq | (old_cppr << 24);
+       vcpu->arch.regs.gpr[4] = hirq | (old_cppr << 24);
 
        return H_SUCCESS;
 }
@@ -369,7 +369,7 @@ X_STATIC unsigned long GLUE(X_PFX,h_ipoll)(struct kvm_vcpu *vcpu, unsigned long
        hirq = GLUE(X_PFX,scan_interrupts)(xc, pending, scan_poll);
 
        /* Return interrupt and old CPPR in GPR4 */
-       vcpu->arch.gpr[4] = hirq | (xc->cppr << 24);
+       vcpu->arch.regs.gpr[4] = hirq | (xc->cppr << 24);
 
        return H_SUCCESS;
 }
index 876d4f294fdd89fc160439073a3c04c9c8e81174..a9ca016da67021691de512d0a8a2f9f0039d56e5 100644 (file)
@@ -77,8 +77,10 @@ void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu)
 {
        int i;
 
-       printk("pc:   %08lx msr:  %08llx\n", vcpu->arch.pc, vcpu->arch.shared->msr);
-       printk("lr:   %08lx ctr:  %08lx\n", vcpu->arch.lr, vcpu->arch.ctr);
+       printk("pc:   %08lx msr:  %08llx\n", vcpu->arch.regs.nip,
+                       vcpu->arch.shared->msr);
+       printk("lr:   %08lx ctr:  %08lx\n", vcpu->arch.regs.link,
+                       vcpu->arch.regs.ctr);
        printk("srr0: %08llx srr1: %08llx\n", vcpu->arch.shared->srr0,
                                            vcpu->arch.shared->srr1);
 
@@ -491,24 +493,25 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
        if (allowed) {
                switch (int_class) {
                case INT_CLASS_NONCRIT:
-                       set_guest_srr(vcpu, vcpu->arch.pc,
+                       set_guest_srr(vcpu, vcpu->arch.regs.nip,
                                      vcpu->arch.shared->msr);
                        break;
                case INT_CLASS_CRIT:
-                       set_guest_csrr(vcpu, vcpu->arch.pc,
+                       set_guest_csrr(vcpu, vcpu->arch.regs.nip,
                                       vcpu->arch.shared->msr);
                        break;
                case INT_CLASS_DBG:
-                       set_guest_dsrr(vcpu, vcpu->arch.pc,
+                       set_guest_dsrr(vcpu, vcpu->arch.regs.nip,
                                       vcpu->arch.shared->msr);
                        break;
                case INT_CLASS_MC:
-                       set_guest_mcsrr(vcpu, vcpu->arch.pc,
+                       set_guest_mcsrr(vcpu, vcpu->arch.regs.nip,
                                        vcpu->arch.shared->msr);
                        break;
                }
 
-               vcpu->arch.pc = vcpu->arch.ivpr | vcpu->arch.ivor[priority];
+               vcpu->arch.regs.nip = vcpu->arch.ivpr |
+                                       vcpu->arch.ivor[priority];
                if (update_esr == true)
                        kvmppc_set_esr(vcpu, vcpu->arch.queued_esr);
                if (update_dear == true)
@@ -826,7 +829,7 @@ static int emulation_exit(struct kvm_run *run, struct kvm_vcpu *vcpu)
 
        case EMULATE_FAIL:
                printk(KERN_CRIT "%s: emulation at %lx failed (%08x)\n",
-                      __func__, vcpu->arch.pc, vcpu->arch.last_inst);
+                      __func__, vcpu->arch.regs.nip, vcpu->arch.last_inst);
                /* For debugging, encode the failing instruction and
                 * report it to userspace. */
                run->hw.hardware_exit_reason = ~0ULL << 32;
@@ -875,7 +878,7 @@ static int kvmppc_handle_debug(struct kvm_run *run, struct kvm_vcpu *vcpu)
         */
        vcpu->arch.dbsr = 0;
        run->debug.arch.status = 0;
-       run->debug.arch.address = vcpu->arch.pc;
+       run->debug.arch.address = vcpu->arch.regs.nip;
 
        if (dbsr & (DBSR_IAC1 | DBSR_IAC2 | DBSR_IAC3 | DBSR_IAC4)) {
                run->debug.arch.status |= KVMPPC_DEBUG_BREAKPOINT;
@@ -971,7 +974,7 @@ static int kvmppc_resume_inst_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
 
        case EMULATE_FAIL:
                pr_debug("%s: load instruction from guest address %lx failed\n",
-                      __func__, vcpu->arch.pc);
+                      __func__, vcpu->arch.regs.nip);
                /* For debugging, encode the failing instruction and
                 * report it to userspace. */
                run->hw.hardware_exit_reason = ~0ULL << 32;
@@ -1169,7 +1172,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
        case BOOKE_INTERRUPT_SPE_FP_DATA:
        case BOOKE_INTERRUPT_SPE_FP_ROUND:
                printk(KERN_CRIT "%s: unexpected SPE interrupt %u at %08lx\n",
-                      __func__, exit_nr, vcpu->arch.pc);
+                      __func__, exit_nr, vcpu->arch.regs.nip);
                run->hw.hardware_exit_reason = exit_nr;
                r = RESUME_HOST;
                break;
@@ -1299,7 +1302,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
        }
 
        case BOOKE_INTERRUPT_ITLB_MISS: {
-               unsigned long eaddr = vcpu->arch.pc;
+               unsigned long eaddr = vcpu->arch.regs.nip;
                gpa_t gpaddr;
                gfn_t gfn;
                int gtlb_index;
@@ -1391,7 +1394,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
        int i;
        int r;
 
-       vcpu->arch.pc = 0;
+       vcpu->arch.regs.nip = 0;
        vcpu->arch.shared->pir = vcpu->vcpu_id;
        kvmppc_set_gpr(vcpu, 1, (16<<20) - 8); /* -8 for the callee-save LR slot */
        kvmppc_set_msr(vcpu, 0);
@@ -1440,10 +1443,10 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 
        vcpu_load(vcpu);
 
-       regs->pc = vcpu->arch.pc;
+       regs->pc = vcpu->arch.regs.nip;
        regs->cr = kvmppc_get_cr(vcpu);
-       regs->ctr = vcpu->arch.ctr;
-       regs->lr = vcpu->arch.lr;
+       regs->ctr = vcpu->arch.regs.ctr;
+       regs->lr = vcpu->arch.regs.link;
        regs->xer = kvmppc_get_xer(vcpu);
        regs->msr = vcpu->arch.shared->msr;
        regs->srr0 = kvmppc_get_srr0(vcpu);
@@ -1471,10 +1474,10 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 
        vcpu_load(vcpu);
 
-       vcpu->arch.pc = regs->pc;
+       vcpu->arch.regs.nip = regs->pc;
        kvmppc_set_cr(vcpu, regs->cr);
-       vcpu->arch.ctr = regs->ctr;
-       vcpu->arch.lr = regs->lr;
+       vcpu->arch.regs.ctr = regs->ctr;
+       vcpu->arch.regs.link = regs->lr;
        kvmppc_set_xer(vcpu, regs->xer);
        kvmppc_set_msr(vcpu, regs->msr);
        kvmppc_set_srr0(vcpu, regs->srr0);
index a82f64502de124c6df3a899cac632548353048d5..d23e582f0feec3328635234bfdd62ef5f260f92c 100644 (file)
 
 static void kvmppc_emul_rfi(struct kvm_vcpu *vcpu)
 {
-       vcpu->arch.pc = vcpu->arch.shared->srr0;
+       vcpu->arch.regs.nip = vcpu->arch.shared->srr0;
        kvmppc_set_msr(vcpu, vcpu->arch.shared->srr1);
 }
 
 static void kvmppc_emul_rfdi(struct kvm_vcpu *vcpu)
 {
-       vcpu->arch.pc = vcpu->arch.dsrr0;
+       vcpu->arch.regs.nip = vcpu->arch.dsrr0;
        kvmppc_set_msr(vcpu, vcpu->arch.dsrr1);
 }
 
 static void kvmppc_emul_rfci(struct kvm_vcpu *vcpu)
 {
-       vcpu->arch.pc = vcpu->arch.csrr0;
+       vcpu->arch.regs.nip = vcpu->arch.csrr0;
        kvmppc_set_msr(vcpu, vcpu->arch.csrr1);
 }
 
index 990db69a1d0b0f9a76d31ae1323fb6e23cb39a82..3f8189eb56ed038f2be56f478f8c6e6925c11f27 100644 (file)
@@ -53,7 +53,7 @@ static int dbell2prio(ulong param)
 
 static int kvmppc_e500_emul_msgclr(struct kvm_vcpu *vcpu, int rb)
 {
-       ulong param = vcpu->arch.gpr[rb];
+       ulong param = vcpu->arch.regs.gpr[rb];
        int prio = dbell2prio(param);
 
        if (prio < 0)
@@ -65,7 +65,7 @@ static int kvmppc_e500_emul_msgclr(struct kvm_vcpu *vcpu, int rb)
 
 static int kvmppc_e500_emul_msgsnd(struct kvm_vcpu *vcpu, int rb)
 {
-       ulong param = vcpu->arch.gpr[rb];
+       ulong param = vcpu->arch.regs.gpr[rb];
        int prio = dbell2prio(rb);
        int pir = param & PPC_DBELL_PIR_MASK;
        int i;
@@ -94,7 +94,7 @@ static int kvmppc_e500_emul_ehpriv(struct kvm_run *run, struct kvm_vcpu *vcpu,
        switch (get_oc(inst)) {
        case EHPRIV_OC_DEBUG:
                run->exit_reason = KVM_EXIT_DEBUG;
-               run->debug.arch.address = vcpu->arch.pc;
+               run->debug.arch.address = vcpu->arch.regs.nip;
                run->debug.arch.status = 0;
                kvmppc_account_exit(vcpu, DEBUG_EXITS);
                emulated = EMULATE_EXIT_USER;
index ddbf8f0284c0e1f8590c05151aa1f5c978ea325e..24296f4cadc6c43c529c9d7e9eb81823c8ff963d 100644 (file)
@@ -513,7 +513,7 @@ void kvmppc_mmu_itlb_miss(struct kvm_vcpu *vcpu)
 {
        unsigned int as = !!(vcpu->arch.shared->msr & MSR_IS);
 
-       kvmppc_e500_deliver_tlb_miss(vcpu, vcpu->arch.pc, as);
+       kvmppc_e500_deliver_tlb_miss(vcpu, vcpu->arch.regs.nip, as);
 }
 
 void kvmppc_mmu_dtlb_miss(struct kvm_vcpu *vcpu)
index c878b4ffb86fe6c284aa3f6b4cb8f8de630eb72a..8f2985e46f6f193d975e2d26ca92c2df60742649 100644 (file)
@@ -625,8 +625,8 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr,
 }
 
 #ifdef CONFIG_KVM_BOOKE_HV
-int kvmppc_load_last_inst(struct kvm_vcpu *vcpu, enum instruction_type type,
-                         u32 *instr)
+int kvmppc_load_last_inst(struct kvm_vcpu *vcpu,
+               enum instruction_fetch_type type, u32 *instr)
 {
        gva_t geaddr;
        hpa_t addr;
@@ -715,8 +715,8 @@ int kvmppc_load_last_inst(struct kvm_vcpu *vcpu, enum instruction_type type,
        return EMULATE_DONE;
 }
 #else
-int kvmppc_load_last_inst(struct kvm_vcpu *vcpu, enum instruction_type type,
-                         u32 *instr)
+int kvmppc_load_last_inst(struct kvm_vcpu *vcpu,
+               enum instruction_fetch_type type, u32 *instr)
 {
        return EMULATE_AGAIN;
 }
index a382e15135e6d3e2358d19745d02b1385ed56312..afde788be14148bf1386b4442e103789dcb181ad 100644 (file)
@@ -31,6 +31,7 @@
 #include <asm/kvm_ppc.h>
 #include <asm/disassemble.h>
 #include <asm/ppc-opcode.h>
+#include <asm/sstep.h>
 #include "timing.h"
 #include "trace.h"
 
@@ -84,8 +85,9 @@ int kvmppc_emulate_loadstore(struct kvm_vcpu *vcpu)
        struct kvm_run *run = vcpu->run;
        u32 inst;
        int ra, rs, rt;
-       enum emulation_result emulated;
+       enum emulation_result emulated = EMULATE_FAIL;
        int advance = 1;
+       struct instruction_op op;
 
        /* this default type might be overwritten by subcategories */
        kvmppc_set_exit_type(vcpu, EMULATED_INST_EXITS);
@@ -107,580 +109,276 @@ int kvmppc_emulate_loadstore(struct kvm_vcpu *vcpu)
        vcpu->arch.mmio_vsx_tx_sx_enabled = get_tx_or_sx(inst);
        vcpu->arch.mmio_vsx_copy_nums = 0;
        vcpu->arch.mmio_vsx_offset = 0;
-       vcpu->arch.mmio_vsx_copy_type = KVMPPC_VSX_COPY_NONE;
+       vcpu->arch.mmio_copy_type = KVMPPC_VSX_COPY_NONE;
        vcpu->arch.mmio_sp64_extend = 0;
        vcpu->arch.mmio_sign_extend = 0;
        vcpu->arch.mmio_vmx_copy_nums = 0;
+       vcpu->arch.mmio_vmx_offset = 0;
+       vcpu->arch.mmio_host_swabbed = 0;
 
-       switch (get_op(inst)) {
-       case 31:
-               switch (get_xop(inst)) {
-               case OP_31_XOP_LWZX:
-                       emulated = kvmppc_handle_load(run, vcpu, rt, 4, 1);
-                       break;
-
-               case OP_31_XOP_LWZUX:
-                       emulated = kvmppc_handle_load(run, vcpu, rt, 4, 1);
-                       kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-                       break;
+       emulated = EMULATE_FAIL;
+       vcpu->arch.regs.msr = vcpu->arch.shared->msr;
+       vcpu->arch.regs.ccr = vcpu->arch.cr;
+       if (analyse_instr(&op, &vcpu->arch.regs, inst) == 0) {
+               int type = op.type & INSTR_TYPE_MASK;
+               int size = GETSIZE(op.type);
 
-               case OP_31_XOP_LBZX:
-                       emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1);
-                       break;
-
-               case OP_31_XOP_LBZUX:
-                       emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1);
-                       kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-                       break;
+               switch (type) {
+               case LOAD:  {
+                       int instr_byte_swap = op.type & BYTEREV;
 
-               case OP_31_XOP_STDX:
-                       emulated = kvmppc_handle_store(run, vcpu,
-                                       kvmppc_get_gpr(vcpu, rs), 8, 1);
-                       break;
+                       if (op.type & SIGNEXT)
+                               emulated = kvmppc_handle_loads(run, vcpu,
+                                               op.reg, size, !instr_byte_swap);
+                       else
+                               emulated = kvmppc_handle_load(run, vcpu,
+                                               op.reg, size, !instr_byte_swap);
 
-               case OP_31_XOP_STDUX:
-                       emulated = kvmppc_handle_store(run, vcpu,
-                                       kvmppc_get_gpr(vcpu, rs), 8, 1);
-                       kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-                       break;
+                       if ((op.type & UPDATE) && (emulated != EMULATE_FAIL))
+                               kvmppc_set_gpr(vcpu, op.update_reg, op.ea);
 
-               case OP_31_XOP_STWX:
-                       emulated = kvmppc_handle_store(run, vcpu,
-                                       kvmppc_get_gpr(vcpu, rs), 4, 1);
-                       break;
-
-               case OP_31_XOP_STWUX:
-                       emulated = kvmppc_handle_store(run, vcpu,
-                                       kvmppc_get_gpr(vcpu, rs), 4, 1);
-                       kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-                       break;
-
-               case OP_31_XOP_STBX:
-                       emulated = kvmppc_handle_store(run, vcpu,
-                                       kvmppc_get_gpr(vcpu, rs), 1, 1);
-                       break;
-
-               case OP_31_XOP_STBUX:
-                       emulated = kvmppc_handle_store(run, vcpu,
-                                       kvmppc_get_gpr(vcpu, rs), 1, 1);
-                       kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-                       break;
-
-               case OP_31_XOP_LHAX:
-                       emulated = kvmppc_handle_loads(run, vcpu, rt, 2, 1);
-                       break;
-
-               case OP_31_XOP_LHAUX:
-                       emulated = kvmppc_handle_loads(run, vcpu, rt, 2, 1);
-                       kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-                       break;
-
-               case OP_31_XOP_LHZX:
-                       emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1);
-                       break;
-
-               case OP_31_XOP_LHZUX:
-                       emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1);
-                       kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-                       break;
-
-               case OP_31_XOP_STHX:
-                       emulated = kvmppc_handle_store(run, vcpu,
-                                       kvmppc_get_gpr(vcpu, rs), 2, 1);
-                       break;
-
-               case OP_31_XOP_STHUX:
-                       emulated = kvmppc_handle_store(run, vcpu,
-                                       kvmppc_get_gpr(vcpu, rs), 2, 1);
-                       kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-                       break;
-
-               case OP_31_XOP_DCBST:
-               case OP_31_XOP_DCBF:
-               case OP_31_XOP_DCBI:
-                       /* Do nothing. The guest is performing dcbi because
-                        * hardware DMA is not snooped by the dcache, but
-                        * emulated DMA either goes through the dcache as
-                        * normal writes, or the host kernel has handled dcache
-                        * coherence. */
-                       break;
-
-               case OP_31_XOP_LWBRX:
-                       emulated = kvmppc_handle_load(run, vcpu, rt, 4, 0);
-                       break;
-
-               case OP_31_XOP_STWBRX:
-                       emulated = kvmppc_handle_store(run, vcpu,
-                                       kvmppc_get_gpr(vcpu, rs), 4, 0);
                        break;
-
-               case OP_31_XOP_LHBRX:
-                       emulated = kvmppc_handle_load(run, vcpu, rt, 2, 0);
-                       break;
-
-               case OP_31_XOP_STHBRX:
-                       emulated = kvmppc_handle_store(run, vcpu,
-                                       kvmppc_get_gpr(vcpu, rs), 2, 0);
-                       break;
-
-               case OP_31_XOP_LDBRX:
-                       emulated = kvmppc_handle_load(run, vcpu, rt, 8, 0);
-                       break;
-
-               case OP_31_XOP_STDBRX:
-                       emulated = kvmppc_handle_store(run, vcpu,
-                                       kvmppc_get_gpr(vcpu, rs), 8, 0);
-                       break;
-
-               case OP_31_XOP_LDX:
-                       emulated = kvmppc_handle_load(run, vcpu, rt, 8, 1);
-                       break;
-
-               case OP_31_XOP_LDUX:
-                       emulated = kvmppc_handle_load(run, vcpu, rt, 8, 1);
-                       kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-                       break;
-
-               case OP_31_XOP_LWAX:
-                       emulated = kvmppc_handle_loads(run, vcpu, rt, 4, 1);
-                       break;
-
-               case OP_31_XOP_LWAUX:
-                       emulated = kvmppc_handle_loads(run, vcpu, rt, 4, 1);
-                       kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-                       break;
-
+               }
 #ifdef CONFIG_PPC_FPU
-               case OP_31_XOP_LFSX:
-                       if (kvmppc_check_fp_disabled(vcpu))
-                               return EMULATE_DONE;
-                       vcpu->arch.mmio_sp64_extend = 1;
-                       emulated = kvmppc_handle_load(run, vcpu,
-                               KVM_MMIO_REG_FPR|rt, 4, 1);
-                       break;
-
-               case OP_31_XOP_LFSUX:
+               case LOAD_FP:
                        if (kvmppc_check_fp_disabled(vcpu))
                                return EMULATE_DONE;
-                       vcpu->arch.mmio_sp64_extend = 1;
-                       emulated = kvmppc_handle_load(run, vcpu,
-                               KVM_MMIO_REG_FPR|rt, 4, 1);
-                       kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-                       break;
 
-               case OP_31_XOP_LFDX:
-                       if (kvmppc_check_fp_disabled(vcpu))
-                               return EMULATE_DONE;
-                       emulated = kvmppc_handle_load(run, vcpu,
-                               KVM_MMIO_REG_FPR|rt, 8, 1);
-                       break;
+                       if (op.type & FPCONV)
+                               vcpu->arch.mmio_sp64_extend = 1;
 
-               case OP_31_XOP_LFDUX:
-                       if (kvmppc_check_fp_disabled(vcpu))
-                               return EMULATE_DONE;
-                       emulated = kvmppc_handle_load(run, vcpu,
-                               KVM_MMIO_REG_FPR|rt, 8, 1);
-                       kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-                       break;
-
-               case OP_31_XOP_LFIWAX:
-                       if (kvmppc_check_fp_disabled(vcpu))
-                               return EMULATE_DONE;
-                       emulated = kvmppc_handle_loads(run, vcpu,
-                               KVM_MMIO_REG_FPR|rt, 4, 1);
-                       break;
+                       if (op.type & SIGNEXT)
+                               emulated = kvmppc_handle_loads(run, vcpu,
+                                            KVM_MMIO_REG_FPR|op.reg, size, 1);
+                       else
+                               emulated = kvmppc_handle_load(run, vcpu,
+                                            KVM_MMIO_REG_FPR|op.reg, size, 1);
 
-               case OP_31_XOP_LFIWZX:
-                       if (kvmppc_check_fp_disabled(vcpu))
-                               return EMULATE_DONE;
-                       emulated = kvmppc_handle_load(run, vcpu,
-                               KVM_MMIO_REG_FPR|rt, 4, 1);
-                       break;
+                       if ((op.type & UPDATE) && (emulated != EMULATE_FAIL))
+                               kvmppc_set_gpr(vcpu, op.update_reg, op.ea);
 
-               case OP_31_XOP_STFSX:
-                       if (kvmppc_check_fp_disabled(vcpu))
-                               return EMULATE_DONE;
-                       vcpu->arch.mmio_sp64_extend = 1;
-                       emulated = kvmppc_handle_store(run, vcpu,
-                               VCPU_FPR(vcpu, rs), 4, 1);
                        break;
-
-               case OP_31_XOP_STFSUX:
-                       if (kvmppc_check_fp_disabled(vcpu))
-                               return EMULATE_DONE;
-                       vcpu->arch.mmio_sp64_extend = 1;
-                       emulated = kvmppc_handle_store(run, vcpu,
-                               VCPU_FPR(vcpu, rs), 4, 1);
-                       kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-                       break;
-
-               case OP_31_XOP_STFDX:
-                       if (kvmppc_check_fp_disabled(vcpu))
-                               return EMULATE_DONE;
-                       emulated = kvmppc_handle_store(run, vcpu,
-                               VCPU_FPR(vcpu, rs), 8, 1);
-                       break;
-
-               case OP_31_XOP_STFDUX:
-                       if (kvmppc_check_fp_disabled(vcpu))
+#endif
+#ifdef CONFIG_ALTIVEC
+               case LOAD_VMX:
+                       if (kvmppc_check_altivec_disabled(vcpu))
                                return EMULATE_DONE;
-                       emulated = kvmppc_handle_store(run, vcpu,
-                               VCPU_FPR(vcpu, rs), 8, 1);
-                       kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-                       break;
 
-               case OP_31_XOP_STFIWX:
-                       if (kvmppc_check_fp_disabled(vcpu))
-                               return EMULATE_DONE;
-                       emulated = kvmppc_handle_store(run, vcpu,
-                               VCPU_FPR(vcpu, rs), 4, 1);
+                       /* Hardware enforces alignment of VMX accesses */
+                       vcpu->arch.vaddr_accessed &= ~((unsigned long)size - 1);
+                       vcpu->arch.paddr_accessed &= ~((unsigned long)size - 1);
+
+                       if (size == 16) { /* lvx */
+                               vcpu->arch.mmio_copy_type =
+                                               KVMPPC_VMX_COPY_DWORD;
+                       } else if (size == 4) { /* lvewx  */
+                               vcpu->arch.mmio_copy_type =
+                                               KVMPPC_VMX_COPY_WORD;
+                       } else if (size == 2) { /* lvehx  */
+                               vcpu->arch.mmio_copy_type =
+                                               KVMPPC_VMX_COPY_HWORD;
+                       } else if (size == 1) { /* lvebx  */
+                               vcpu->arch.mmio_copy_type =
+                                               KVMPPC_VMX_COPY_BYTE;
+                       } else
+                               break;
+
+                       vcpu->arch.mmio_vmx_offset =
+                               (vcpu->arch.vaddr_accessed & 0xf)/size;
+
+                       if (size == 16) {
+                               vcpu->arch.mmio_vmx_copy_nums = 2;
+                               emulated = kvmppc_handle_vmx_load(run,
+                                               vcpu, KVM_MMIO_REG_VMX|op.reg,
+                                               8, 1);
+                       } else {
+                               vcpu->arch.mmio_vmx_copy_nums = 1;
+                               emulated = kvmppc_handle_vmx_load(run, vcpu,
+                                               KVM_MMIO_REG_VMX|op.reg,
+                                               size, 1);
+                       }
                        break;
 #endif
-
 #ifdef CONFIG_VSX
-               case OP_31_XOP_LXSDX:
-                       if (kvmppc_check_vsx_disabled(vcpu))
-                               return EMULATE_DONE;
-                       vcpu->arch.mmio_vsx_copy_nums = 1;
-                       vcpu->arch.mmio_vsx_copy_type = KVMPPC_VSX_COPY_DWORD;
-                       emulated = kvmppc_handle_vsx_load(run, vcpu,
-                               KVM_MMIO_REG_VSX|rt, 8, 1, 0);
-                       break;
-
-               case OP_31_XOP_LXSSPX:
-                       if (kvmppc_check_vsx_disabled(vcpu))
-                               return EMULATE_DONE;
-                       vcpu->arch.mmio_vsx_copy_nums = 1;
-                       vcpu->arch.mmio_vsx_copy_type = KVMPPC_VSX_COPY_DWORD;
-                       vcpu->arch.mmio_sp64_extend = 1;
-                       emulated = kvmppc_handle_vsx_load(run, vcpu,
-                               KVM_MMIO_REG_VSX|rt, 4, 1, 0);
-                       break;
+               case LOAD_VSX: {
+                       int io_size_each;
+
+                       if (op.vsx_flags & VSX_CHECK_VEC) {
+                               if (kvmppc_check_altivec_disabled(vcpu))
+                                       return EMULATE_DONE;
+                       } else {
+                               if (kvmppc_check_vsx_disabled(vcpu))
+                                       return EMULATE_DONE;
+                       }
+
+                       if (op.vsx_flags & VSX_FPCONV)
+                               vcpu->arch.mmio_sp64_extend = 1;
+
+                       if (op.element_size == 8)  {
+                               if (op.vsx_flags & VSX_SPLAT)
+                                       vcpu->arch.mmio_copy_type =
+                                               KVMPPC_VSX_COPY_DWORD_LOAD_DUMP;
+                               else
+                                       vcpu->arch.mmio_copy_type =
+                                               KVMPPC_VSX_COPY_DWORD;
+                       } else if (op.element_size == 4) {
+                               if (op.vsx_flags & VSX_SPLAT)
+                                       vcpu->arch.mmio_copy_type =
+                                               KVMPPC_VSX_COPY_WORD_LOAD_DUMP;
+                               else
+                                       vcpu->arch.mmio_copy_type =
+                                               KVMPPC_VSX_COPY_WORD;
+                       } else
+                               break;
+
+                       if (size < op.element_size) {
+                               /* precision convert case: lxsspx, etc */
+                               vcpu->arch.mmio_vsx_copy_nums = 1;
+                               io_size_each = size;
+                       } else { /* lxvw4x, lxvd2x, etc */
+                               vcpu->arch.mmio_vsx_copy_nums =
+                                       size/op.element_size;
+                               io_size_each = op.element_size;
+                       }
 
-               case OP_31_XOP_LXSIWAX:
-                       if (kvmppc_check_vsx_disabled(vcpu))
-                               return EMULATE_DONE;
-                       vcpu->arch.mmio_vsx_copy_nums = 1;
-                       vcpu->arch.mmio_vsx_copy_type = KVMPPC_VSX_COPY_DWORD;
                        emulated = kvmppc_handle_vsx_load(run, vcpu,
-                               KVM_MMIO_REG_VSX|rt, 4, 1, 1);
-                       break;
-
-               case OP_31_XOP_LXSIWZX:
-                       if (kvmppc_check_vsx_disabled(vcpu))
-                               return EMULATE_DONE;
-                       vcpu->arch.mmio_vsx_copy_nums = 1;
-                       vcpu->arch.mmio_vsx_copy_type = KVMPPC_VSX_COPY_DWORD;
-                       emulated = kvmppc_handle_vsx_load(run, vcpu,
-                               KVM_MMIO_REG_VSX|rt, 4, 1, 0);
+                                       KVM_MMIO_REG_VSX | (op.reg & 0x1f),
+                                       io_size_each, 1, op.type & SIGNEXT);
                        break;
+               }
+#endif
+               case STORE:
+                       /* if need byte reverse, op.val has been reversed by
+                        * analyse_instr().
+                        */
+                       emulated = kvmppc_handle_store(run, vcpu, op.val,
+                                       size, 1);
 
-               case OP_31_XOP_LXVD2X:
-               /*
-                * In this case, the official load/store process is like this:
-                * Step1, exit from vm by page fault isr, then kvm save vsr.
-                * Please see guest_exit_cont->store_fp_state->SAVE_32VSRS
-                * as reference.
-                *
-                * Step2, copy data between memory and VCPU
-                * Notice: for LXVD2X/STXVD2X/LXVW4X/STXVW4X, we use
-                * 2copies*8bytes or 4copies*4bytes
-                * to simulate one copy of 16bytes.
-                * Also there is an endian issue here, we should notice the
-                * layout of memory.
-                * Please see MARCO of LXVD2X_ROT/STXVD2X_ROT as more reference.
-                * If host is little-endian, kvm will call XXSWAPD for
-                * LXVD2X_ROT/STXVD2X_ROT.
-                * So, if host is little-endian,
-                * the postion of memeory should be swapped.
-                *
-                * Step3, return to guest, kvm reset register.
-                * Please see kvmppc_hv_entry->load_fp_state->REST_32VSRS
-                * as reference.
-                */
-                       if (kvmppc_check_vsx_disabled(vcpu))
-                               return EMULATE_DONE;
-                       vcpu->arch.mmio_vsx_copy_nums = 2;
-                       vcpu->arch.mmio_vsx_copy_type = KVMPPC_VSX_COPY_DWORD;
-                       emulated = kvmppc_handle_vsx_load(run, vcpu,
-                               KVM_MMIO_REG_VSX|rt, 8, 1, 0);
-                       break;
+                       if ((op.type & UPDATE) && (emulated != EMULATE_FAIL))
+                               kvmppc_set_gpr(vcpu, op.update_reg, op.ea);
 
-               case OP_31_XOP_LXVW4X:
-                       if (kvmppc_check_vsx_disabled(vcpu))
-                               return EMULATE_DONE;
-                       vcpu->arch.mmio_vsx_copy_nums = 4;
-                       vcpu->arch.mmio_vsx_copy_type = KVMPPC_VSX_COPY_WORD;
-                       emulated = kvmppc_handle_vsx_load(run, vcpu,
-                               KVM_MMIO_REG_VSX|rt, 4, 1, 0);
                        break;
-
-               case OP_31_XOP_LXVDSX:
-                       if (kvmppc_check_vsx_disabled(vcpu))
+#ifdef CONFIG_PPC_FPU
+               case STORE_FP:
+                       if (kvmppc_check_fp_disabled(vcpu))
                                return EMULATE_DONE;
-                       vcpu->arch.mmio_vsx_copy_nums = 1;
-                       vcpu->arch.mmio_vsx_copy_type =
-                                KVMPPC_VSX_COPY_DWORD_LOAD_DUMP;
-                       emulated = kvmppc_handle_vsx_load(run, vcpu,
-                               KVM_MMIO_REG_VSX|rt, 8, 1, 0);
-                       break;
 
-               case OP_31_XOP_STXSDX:
-                       if (kvmppc_check_vsx_disabled(vcpu))
-                               return EMULATE_DONE;
-                       vcpu->arch.mmio_vsx_copy_nums = 1;
-                       vcpu->arch.mmio_vsx_copy_type = KVMPPC_VSX_COPY_DWORD;
-                       emulated = kvmppc_handle_vsx_store(run, vcpu,
-                                                rs, 8, 1);
-                       break;
+                       /* The FP registers need to be flushed so that
+                        * kvmppc_handle_store() can read actual FP vals
+                        * from vcpu->arch.
+                        */
+                       if (vcpu->kvm->arch.kvm_ops->giveup_ext)
+                               vcpu->kvm->arch.kvm_ops->giveup_ext(vcpu,
+                                               MSR_FP);
 
-               case OP_31_XOP_STXSSPX:
-                       if (kvmppc_check_vsx_disabled(vcpu))
-                               return EMULATE_DONE;
-                       vcpu->arch.mmio_vsx_copy_nums = 1;
-                       vcpu->arch.mmio_vsx_copy_type = KVMPPC_VSX_COPY_DWORD;
-                       vcpu->arch.mmio_sp64_extend = 1;
-                       emulated = kvmppc_handle_vsx_store(run, vcpu,
-                                                rs, 4, 1);
-                       break;
+                       if (op.type & FPCONV)
+                               vcpu->arch.mmio_sp64_extend = 1;
 
-               case OP_31_XOP_STXSIWX:
-                       if (kvmppc_check_vsx_disabled(vcpu))
-                               return EMULATE_DONE;
-                       vcpu->arch.mmio_vsx_offset = 1;
-                       vcpu->arch.mmio_vsx_copy_nums = 1;
-                       vcpu->arch.mmio_vsx_copy_type = KVMPPC_VSX_COPY_WORD;
-                       emulated = kvmppc_handle_vsx_store(run, vcpu,
-                                                        rs, 4, 1);
-                       break;
+                       emulated = kvmppc_handle_store(run, vcpu,
+                                       VCPU_FPR(vcpu, op.reg), size, 1);
 
-               case OP_31_XOP_STXVD2X:
-                       if (kvmppc_check_vsx_disabled(vcpu))
-                               return EMULATE_DONE;
-                       vcpu->arch.mmio_vsx_copy_nums = 2;
-                       vcpu->arch.mmio_vsx_copy_type = KVMPPC_VSX_COPY_DWORD;
-                       emulated = kvmppc_handle_vsx_store(run, vcpu,
-                                                        rs, 8, 1);
-                       break;
+                       if ((op.type & UPDATE) && (emulated != EMULATE_FAIL))
+                               kvmppc_set_gpr(vcpu, op.update_reg, op.ea);
 
-               case OP_31_XOP_STXVW4X:
-                       if (kvmppc_check_vsx_disabled(vcpu))
-                               return EMULATE_DONE;
-                       vcpu->arch.mmio_vsx_copy_nums = 4;
-                       vcpu->arch.mmio_vsx_copy_type = KVMPPC_VSX_COPY_WORD;
-                       emulated = kvmppc_handle_vsx_store(run, vcpu,
-                                                        rs, 4, 1);
                        break;
-#endif /* CONFIG_VSX */
-
+#endif
 #ifdef CONFIG_ALTIVEC
-               case OP_31_XOP_LVX:
+               case STORE_VMX:
                        if (kvmppc_check_altivec_disabled(vcpu))
                                return EMULATE_DONE;
-                       vcpu->arch.vaddr_accessed &= ~0xFULL;
-                       vcpu->arch.paddr_accessed &= ~0xFULL;
-                       vcpu->arch.mmio_vmx_copy_nums = 2;
-                       emulated = kvmppc_handle_load128_by2x64(run, vcpu,
-                                       KVM_MMIO_REG_VMX|rt, 1);
-                       break;
 
-               case OP_31_XOP_STVX:
-                       if (kvmppc_check_altivec_disabled(vcpu))
-                               return EMULATE_DONE;
-                       vcpu->arch.vaddr_accessed &= ~0xFULL;
-                       vcpu->arch.paddr_accessed &= ~0xFULL;
-                       vcpu->arch.mmio_vmx_copy_nums = 2;
-                       emulated = kvmppc_handle_store128_by2x64(run, vcpu,
-                                       rs, 1);
-                       break;
-#endif /* CONFIG_ALTIVEC */
+                       /* Hardware enforces alignment of VMX accesses. */
+                       vcpu->arch.vaddr_accessed &= ~((unsigned long)size - 1);
+                       vcpu->arch.paddr_accessed &= ~((unsigned long)size - 1);
+
+                       if (vcpu->kvm->arch.kvm_ops->giveup_ext)
+                               vcpu->kvm->arch.kvm_ops->giveup_ext(vcpu,
+                                               MSR_VEC);
+                       if (size == 16) { /* stvx */
+                               vcpu->arch.mmio_copy_type =
+                                               KVMPPC_VMX_COPY_DWORD;
+                       } else if (size == 4) { /* stvewx  */
+                               vcpu->arch.mmio_copy_type =
+                                               KVMPPC_VMX_COPY_WORD;
+                       } else if (size == 2) { /* stvehx  */
+                               vcpu->arch.mmio_copy_type =
+                                               KVMPPC_VMX_COPY_HWORD;
+                       } else if (size == 1) { /* stvebx  */
+                               vcpu->arch.mmio_copy_type =
+                                               KVMPPC_VMX_COPY_BYTE;
+                       } else
+                               break;
+
+                       vcpu->arch.mmio_vmx_offset =
+                               (vcpu->arch.vaddr_accessed & 0xf)/size;
+
+                       if (size == 16) {
+                               vcpu->arch.mmio_vmx_copy_nums = 2;
+                               emulated = kvmppc_handle_vmx_store(run,
+                                               vcpu, op.reg, 8, 1);
+                       } else {
+                               vcpu->arch.mmio_vmx_copy_nums = 1;
+                               emulated = kvmppc_handle_vmx_store(run,
+                                               vcpu, op.reg, size, 1);
+                       }
 
-               default:
-                       emulated = EMULATE_FAIL;
                        break;
-               }
-               break;
-
-       case OP_LWZ:
-               emulated = kvmppc_handle_load(run, vcpu, rt, 4, 1);
-               break;
-
-#ifdef CONFIG_PPC_FPU
-       case OP_STFS:
-               if (kvmppc_check_fp_disabled(vcpu))
-                       return EMULATE_DONE;
-               vcpu->arch.mmio_sp64_extend = 1;
-               emulated = kvmppc_handle_store(run, vcpu,
-                       VCPU_FPR(vcpu, rs),
-                       4, 1);
-               break;
-
-       case OP_STFSU:
-               if (kvmppc_check_fp_disabled(vcpu))
-                       return EMULATE_DONE;
-               vcpu->arch.mmio_sp64_extend = 1;
-               emulated = kvmppc_handle_store(run, vcpu,
-                       VCPU_FPR(vcpu, rs),
-                       4, 1);
-               kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-               break;
-
-       case OP_STFD:
-               if (kvmppc_check_fp_disabled(vcpu))
-                       return EMULATE_DONE;
-               emulated = kvmppc_handle_store(run, vcpu,
-                       VCPU_FPR(vcpu, rs),
-                                      8, 1);
-               break;
-
-       case OP_STFDU:
-               if (kvmppc_check_fp_disabled(vcpu))
-                       return EMULATE_DONE;
-               emulated = kvmppc_handle_store(run, vcpu,
-                       VCPU_FPR(vcpu, rs),
-                                      8, 1);
-               kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-               break;
 #endif
+#ifdef CONFIG_VSX
+               case STORE_VSX: {
+                       int io_size_each;
+
+                       if (op.vsx_flags & VSX_CHECK_VEC) {
+                               if (kvmppc_check_altivec_disabled(vcpu))
+                                       return EMULATE_DONE;
+                       } else {
+                               if (kvmppc_check_vsx_disabled(vcpu))
+                                       return EMULATE_DONE;
+                       }
+
+                       if (vcpu->kvm->arch.kvm_ops->giveup_ext)
+                               vcpu->kvm->arch.kvm_ops->giveup_ext(vcpu,
+                                               MSR_VSX);
+
+                       if (op.vsx_flags & VSX_FPCONV)
+                               vcpu->arch.mmio_sp64_extend = 1;
+
+                       if (op.element_size == 8)
+                               vcpu->arch.mmio_copy_type =
+                                               KVMPPC_VSX_COPY_DWORD;
+                       else if (op.element_size == 4)
+                               vcpu->arch.mmio_copy_type =
+                                               KVMPPC_VSX_COPY_WORD;
+                       else
+                               break;
+
+                       if (size < op.element_size) {
+                               /* precise conversion case, like stxsspx */
+                               vcpu->arch.mmio_vsx_copy_nums = 1;
+                               io_size_each = size;
+                       } else { /* stxvw4x, stxvd2x, etc */
+                               vcpu->arch.mmio_vsx_copy_nums =
+                                               size/op.element_size;
+                               io_size_each = op.element_size;
+                       }
 
-       case OP_LD:
-               rt = get_rt(inst);
-               switch (inst & 3) {
-               case 0: /* ld */
-                       emulated = kvmppc_handle_load(run, vcpu, rt, 8, 1);
-                       break;
-               case 1: /* ldu */
-                       emulated = kvmppc_handle_load(run, vcpu, rt, 8, 1);
-                       kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-                       break;
-               case 2: /* lwa */
-                       emulated = kvmppc_handle_loads(run, vcpu, rt, 4, 1);
+                       emulated = kvmppc_handle_vsx_store(run, vcpu,
+                                       op.reg & 0x1f, io_size_each, 1);
                        break;
-               default:
-                       emulated = EMULATE_FAIL;
                }
-               break;
-
-       case OP_LWZU:
-               emulated = kvmppc_handle_load(run, vcpu, rt, 4, 1);
-               kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-               break;
-
-       case OP_LBZ:
-               emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1);
-               break;
-
-       case OP_LBZU:
-               emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1);
-               kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-               break;
-
-       case OP_STW:
-               emulated = kvmppc_handle_store(run, vcpu,
-                                              kvmppc_get_gpr(vcpu, rs),
-                                              4, 1);
-               break;
-
-       case OP_STD:
-               rs = get_rs(inst);
-               switch (inst & 3) {
-               case 0: /* std */
-                       emulated = kvmppc_handle_store(run, vcpu,
-                               kvmppc_get_gpr(vcpu, rs), 8, 1);
-                       break;
-               case 1: /* stdu */
-                       emulated = kvmppc_handle_store(run, vcpu,
-                               kvmppc_get_gpr(vcpu, rs), 8, 1);
-                       kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
+#endif
+               case CACHEOP:
+                       /* Do nothing. The guest is performing dcbi because
+                        * hardware DMA is not snooped by the dcache, but
+                        * emulated DMA either goes through the dcache as
+                        * normal writes, or the host kernel has handled dcache
+                        * coherence.
+                        */
+                       emulated = EMULATE_DONE;
                        break;
                default:
-                       emulated = EMULATE_FAIL;
+                       break;
                }
-               break;
-
-       case OP_STWU:
-               emulated = kvmppc_handle_store(run, vcpu,
-                               kvmppc_get_gpr(vcpu, rs), 4, 1);
-               kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-               break;
-
-       case OP_STB:
-               emulated = kvmppc_handle_store(run, vcpu,
-                               kvmppc_get_gpr(vcpu, rs), 1, 1);
-               break;
-
-       case OP_STBU:
-               emulated = kvmppc_handle_store(run, vcpu,
-                               kvmppc_get_gpr(vcpu, rs), 1, 1);
-               kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-               break;
-
-       case OP_LHZ:
-               emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1);
-               break;
-
-       case OP_LHZU:
-               emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1);
-               kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-               break;
-
-       case OP_LHA:
-               emulated = kvmppc_handle_loads(run, vcpu, rt, 2, 1);
-               break;
-
-       case OP_LHAU:
-               emulated = kvmppc_handle_loads(run, vcpu, rt, 2, 1);
-               kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-               break;
-
-       case OP_STH:
-               emulated = kvmppc_handle_store(run, vcpu,
-                               kvmppc_get_gpr(vcpu, rs), 2, 1);
-               break;
-
-       case OP_STHU:
-               emulated = kvmppc_handle_store(run, vcpu,
-                               kvmppc_get_gpr(vcpu, rs), 2, 1);
-               kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-               break;
-
-#ifdef CONFIG_PPC_FPU
-       case OP_LFS:
-               if (kvmppc_check_fp_disabled(vcpu))
-                       return EMULATE_DONE;
-               vcpu->arch.mmio_sp64_extend = 1;
-               emulated = kvmppc_handle_load(run, vcpu,
-                       KVM_MMIO_REG_FPR|rt, 4, 1);
-               break;
-
-       case OP_LFSU:
-               if (kvmppc_check_fp_disabled(vcpu))
-                       return EMULATE_DONE;
-               vcpu->arch.mmio_sp64_extend = 1;
-               emulated = kvmppc_handle_load(run, vcpu,
-                       KVM_MMIO_REG_FPR|rt, 4, 1);
-               kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-               break;
-
-       case OP_LFD:
-               if (kvmppc_check_fp_disabled(vcpu))
-                       return EMULATE_DONE;
-               emulated = kvmppc_handle_load(run, vcpu,
-                       KVM_MMIO_REG_FPR|rt, 8, 1);
-               break;
-
-       case OP_LFDU:
-               if (kvmppc_check_fp_disabled(vcpu))
-                       return EMULATE_DONE;
-               emulated = kvmppc_handle_load(run, vcpu,
-                       KVM_MMIO_REG_FPR|rt, 8, 1);
-               kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
-               break;
-#endif
-
-       default:
-               emulated = EMULATE_FAIL;
-               break;
        }
 
        if (emulated == EMULATE_FAIL) {
index 3764d000872ed67a5cce683293936bf433f67141..0e8c20c5eaace243850e255acf5be966c85f0a5c 100644 (file)
@@ -648,9 +648,8 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 #endif
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
        case KVM_CAP_PPC_HTM:
-               r = hv_enabled &&
-                   (!!(cur_cpu_spec->cpu_user_features2 & PPC_FEATURE2_HTM) ||
-                    cpu_has_feature(CPU_FTR_P9_TM_HV_ASSIST));
+               r = !!(cur_cpu_spec->cpu_user_features2 & PPC_FEATURE2_HTM) ||
+                    (hv_enabled && cpu_has_feature(CPU_FTR_P9_TM_HV_ASSIST));
                break;
 #endif
        default:
@@ -907,6 +906,26 @@ static inline void kvmppc_set_vsr_dword_dump(struct kvm_vcpu *vcpu,
        }
 }
 
+static inline void kvmppc_set_vsr_word_dump(struct kvm_vcpu *vcpu,
+       u32 gpr)
+{
+       union kvmppc_one_reg val;
+       int index = vcpu->arch.io_gpr & KVM_MMIO_REG_MASK;
+
+       if (vcpu->arch.mmio_vsx_tx_sx_enabled) {
+               val.vsx32val[0] = gpr;
+               val.vsx32val[1] = gpr;
+               val.vsx32val[2] = gpr;
+               val.vsx32val[3] = gpr;
+               VCPU_VSX_VR(vcpu, index) = val.vval;
+       } else {
+               val.vsx32val[0] = gpr;
+               val.vsx32val[1] = gpr;
+               VCPU_VSX_FPR(vcpu, index, 0) = val.vsxval[0];
+               VCPU_VSX_FPR(vcpu, index, 1) = val.vsxval[0];
+       }
+}
+
 static inline void kvmppc_set_vsr_word(struct kvm_vcpu *vcpu,
        u32 gpr32)
 {
@@ -933,30 +952,110 @@ static inline void kvmppc_set_vsr_word(struct kvm_vcpu *vcpu,
 #endif /* CONFIG_VSX */
 
 #ifdef CONFIG_ALTIVEC
+static inline int kvmppc_get_vmx_offset_generic(struct kvm_vcpu *vcpu,
+               int index, int element_size)
+{
+       int offset;
+       int elts = sizeof(vector128)/element_size;
+
+       if ((index < 0) || (index >= elts))
+               return -1;
+
+       if (kvmppc_need_byteswap(vcpu))
+               offset = elts - index - 1;
+       else
+               offset = index;
+
+       return offset;
+}
+
+static inline int kvmppc_get_vmx_dword_offset(struct kvm_vcpu *vcpu,
+               int index)
+{
+       return kvmppc_get_vmx_offset_generic(vcpu, index, 8);
+}
+
+static inline int kvmppc_get_vmx_word_offset(struct kvm_vcpu *vcpu,
+               int index)
+{
+       return kvmppc_get_vmx_offset_generic(vcpu, index, 4);
+}
+
+static inline int kvmppc_get_vmx_hword_offset(struct kvm_vcpu *vcpu,
+               int index)
+{
+       return kvmppc_get_vmx_offset_generic(vcpu, index, 2);
+}
+
+static inline int kvmppc_get_vmx_byte_offset(struct kvm_vcpu *vcpu,
+               int index)
+{
+       return kvmppc_get_vmx_offset_generic(vcpu, index, 1);
+}
+
+
 static inline void kvmppc_set_vmx_dword(struct kvm_vcpu *vcpu,
-               u64 gpr)
+       u64 gpr)
 {
+       union kvmppc_one_reg val;
+       int offset = kvmppc_get_vmx_dword_offset(vcpu,
+                       vcpu->arch.mmio_vmx_offset);
        int index = vcpu->arch.io_gpr & KVM_MMIO_REG_MASK;
-       u32 hi, lo;
-       u32 di;
 
-#ifdef __BIG_ENDIAN
-       hi = gpr >> 32;
-       lo = gpr & 0xffffffff;
-#else
-       lo = gpr >> 32;
-       hi = gpr & 0xffffffff;
-#endif
+       if (offset == -1)
+               return;
+
+       val.vval = VCPU_VSX_VR(vcpu, index);
+       val.vsxval[offset] = gpr;
+       VCPU_VSX_VR(vcpu, index) = val.vval;
+}
+
+static inline void kvmppc_set_vmx_word(struct kvm_vcpu *vcpu,
+       u32 gpr32)
+{
+       union kvmppc_one_reg val;
+       int offset = kvmppc_get_vmx_word_offset(vcpu,
+                       vcpu->arch.mmio_vmx_offset);
+       int index = vcpu->arch.io_gpr & KVM_MMIO_REG_MASK;
 
-       di = 2 - vcpu->arch.mmio_vmx_copy_nums;         /* doubleword index */
-       if (di > 1)
+       if (offset == -1)
                return;
 
-       if (vcpu->arch.mmio_host_swabbed)
-               di = 1 - di;
+       val.vval = VCPU_VSX_VR(vcpu, index);
+       val.vsx32val[offset] = gpr32;
+       VCPU_VSX_VR(vcpu, index) = val.vval;
+}
+
+static inline void kvmppc_set_vmx_hword(struct kvm_vcpu *vcpu,
+       u16 gpr16)
+{
+       union kvmppc_one_reg val;
+       int offset = kvmppc_get_vmx_hword_offset(vcpu,
+                       vcpu->arch.mmio_vmx_offset);
+       int index = vcpu->arch.io_gpr & KVM_MMIO_REG_MASK;
+
+       if (offset == -1)
+               return;
+
+       val.vval = VCPU_VSX_VR(vcpu, index);
+       val.vsx16val[offset] = gpr16;
+       VCPU_VSX_VR(vcpu, index) = val.vval;
+}
+
+static inline void kvmppc_set_vmx_byte(struct kvm_vcpu *vcpu,
+       u8 gpr8)
+{
+       union kvmppc_one_reg val;
+       int offset = kvmppc_get_vmx_byte_offset(vcpu,
+                       vcpu->arch.mmio_vmx_offset);
+       int index = vcpu->arch.io_gpr & KVM_MMIO_REG_MASK;
+
+       if (offset == -1)
+               return;
 
-       VCPU_VSX_VR(vcpu, index).u[di * 2] = hi;
-       VCPU_VSX_VR(vcpu, index).u[di * 2 + 1] = lo;
+       val.vval = VCPU_VSX_VR(vcpu, index);
+       val.vsx8val[offset] = gpr8;
+       VCPU_VSX_VR(vcpu, index) = val.vval;
 }
 #endif /* CONFIG_ALTIVEC */
 
@@ -1041,6 +1140,9 @@ static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu,
                kvmppc_set_gpr(vcpu, vcpu->arch.io_gpr, gpr);
                break;
        case KVM_MMIO_REG_FPR:
+               if (vcpu->kvm->arch.kvm_ops->giveup_ext)
+                       vcpu->kvm->arch.kvm_ops->giveup_ext(vcpu, MSR_FP);
+
                VCPU_FPR(vcpu, vcpu->arch.io_gpr & KVM_MMIO_REG_MASK) = gpr;
                break;
 #ifdef CONFIG_PPC_BOOK3S
@@ -1054,18 +1156,36 @@ static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu,
 #endif
 #ifdef CONFIG_VSX
        case KVM_MMIO_REG_VSX:
-               if (vcpu->arch.mmio_vsx_copy_type == KVMPPC_VSX_COPY_DWORD)
+               if (vcpu->kvm->arch.kvm_ops->giveup_ext)
+                       vcpu->kvm->arch.kvm_ops->giveup_ext(vcpu, MSR_VSX);
+
+               if (vcpu->arch.mmio_copy_type == KVMPPC_VSX_COPY_DWORD)
                        kvmppc_set_vsr_dword(vcpu, gpr);
-               else if (vcpu->arch.mmio_vsx_copy_type == KVMPPC_VSX_COPY_WORD)
+               else if (vcpu->arch.mmio_copy_type == KVMPPC_VSX_COPY_WORD)
                        kvmppc_set_vsr_word(vcpu, gpr);
-               else if (vcpu->arch.mmio_vsx_copy_type ==
+               else if (vcpu->arch.mmio_copy_type ==
                                KVMPPC_VSX_COPY_DWORD_LOAD_DUMP)
                        kvmppc_set_vsr_dword_dump(vcpu, gpr);
+               else if (vcpu->arch.mmio_copy_type ==
+                               KVMPPC_VSX_COPY_WORD_LOAD_DUMP)
+                       kvmppc_set_vsr_word_dump(vcpu, gpr);
                break;
 #endif
 #ifdef CONFIG_ALTIVEC
        case KVM_MMIO_REG_VMX:
-               kvmppc_set_vmx_dword(vcpu, gpr);
+               if (vcpu->kvm->arch.kvm_ops->giveup_ext)
+                       vcpu->kvm->arch.kvm_ops->giveup_ext(vcpu, MSR_VEC);
+
+               if (vcpu->arch.mmio_copy_type == KVMPPC_VMX_COPY_DWORD)
+                       kvmppc_set_vmx_dword(vcpu, gpr);
+               else if (vcpu->arch.mmio_copy_type == KVMPPC_VMX_COPY_WORD)
+                       kvmppc_set_vmx_word(vcpu, gpr);
+               else if (vcpu->arch.mmio_copy_type ==
+                               KVMPPC_VMX_COPY_HWORD)
+                       kvmppc_set_vmx_hword(vcpu, gpr);
+               else if (vcpu->arch.mmio_copy_type ==
+                               KVMPPC_VMX_COPY_BYTE)
+                       kvmppc_set_vmx_byte(vcpu, gpr);
                break;
 #endif
        default:
@@ -1228,7 +1348,7 @@ static inline int kvmppc_get_vsr_data(struct kvm_vcpu *vcpu, int rs, u64 *val)
        u32 dword_offset, word_offset;
        union kvmppc_one_reg reg;
        int vsx_offset = 0;
-       int copy_type = vcpu->arch.mmio_vsx_copy_type;
+       int copy_type = vcpu->arch.mmio_copy_type;
        int result = 0;
 
        switch (copy_type) {
@@ -1344,14 +1464,16 @@ static int kvmppc_emulate_mmio_vsx_loadstore(struct kvm_vcpu *vcpu,
 #endif /* CONFIG_VSX */
 
 #ifdef CONFIG_ALTIVEC
-/* handle quadword load access in two halves */
-int kvmppc_handle_load128_by2x64(struct kvm_run *run, struct kvm_vcpu *vcpu,
-               unsigned int rt, int is_default_endian)
+int kvmppc_handle_vmx_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
+               unsigned int rt, unsigned int bytes, int is_default_endian)
 {
        enum emulation_result emulated = EMULATE_DONE;
 
+       if (vcpu->arch.mmio_vsx_copy_nums > 2)
+               return EMULATE_FAIL;
+
        while (vcpu->arch.mmio_vmx_copy_nums) {
-               emulated = __kvmppc_handle_load(run, vcpu, rt, 8,
+               emulated = __kvmppc_handle_load(run, vcpu, rt, bytes,
                                is_default_endian, 0);
 
                if (emulated != EMULATE_DONE)
@@ -1359,55 +1481,127 @@ int kvmppc_handle_load128_by2x64(struct kvm_run *run, struct kvm_vcpu *vcpu,
 
                vcpu->arch.paddr_accessed += run->mmio.len;
                vcpu->arch.mmio_vmx_copy_nums--;
+               vcpu->arch.mmio_vmx_offset++;
        }
 
        return emulated;
 }
 
-static inline int kvmppc_get_vmx_data(struct kvm_vcpu *vcpu, int rs, u64 *val)
+int kvmppc_get_vmx_dword(struct kvm_vcpu *vcpu, int index, u64 *val)
 {
-       vector128 vrs = VCPU_VSX_VR(vcpu, rs);
-       u32 di;
-       u64 w0, w1;
+       union kvmppc_one_reg reg;
+       int vmx_offset = 0;
+       int result = 0;
 
-       di = 2 - vcpu->arch.mmio_vmx_copy_nums;         /* doubleword index */
-       if (di > 1)
+       vmx_offset =
+               kvmppc_get_vmx_dword_offset(vcpu, vcpu->arch.mmio_vmx_offset);
+
+       if (vmx_offset == -1)
                return -1;
 
-       if (vcpu->arch.mmio_host_swabbed)
-               di = 1 - di;
+       reg.vval = VCPU_VSX_VR(vcpu, index);
+       *val = reg.vsxval[vmx_offset];
 
-       w0 = vrs.u[di * 2];
-       w1 = vrs.u[di * 2 + 1];
+       return result;
+}
 
-#ifdef __BIG_ENDIAN
-       *val = (w0 << 32) | w1;
-#else
-       *val = (w1 << 32) | w0;
-#endif
-       return 0;
+int kvmppc_get_vmx_word(struct kvm_vcpu *vcpu, int index, u64 *val)
+{
+       union kvmppc_one_reg reg;
+       int vmx_offset = 0;
+       int result = 0;
+
+       vmx_offset =
+               kvmppc_get_vmx_word_offset(vcpu, vcpu->arch.mmio_vmx_offset);
+
+       if (vmx_offset == -1)
+               return -1;
+
+       reg.vval = VCPU_VSX_VR(vcpu, index);
+       *val = reg.vsx32val[vmx_offset];
+
+       return result;
+}
+
+int kvmppc_get_vmx_hword(struct kvm_vcpu *vcpu, int index, u64 *val)
+{
+       union kvmppc_one_reg reg;
+       int vmx_offset = 0;
+       int result = 0;
+
+       vmx_offset =
+               kvmppc_get_vmx_hword_offset(vcpu, vcpu->arch.mmio_vmx_offset);
+
+       if (vmx_offset == -1)
+               return -1;
+
+       reg.vval = VCPU_VSX_VR(vcpu, index);
+       *val = reg.vsx16val[vmx_offset];
+
+       return result;
 }
 
-/* handle quadword store in two halves */
-int kvmppc_handle_store128_by2x64(struct kvm_run *run, struct kvm_vcpu *vcpu,
-               unsigned int rs, int is_default_endian)
+int kvmppc_get_vmx_byte(struct kvm_vcpu *vcpu, int index, u64 *val)
+{
+       union kvmppc_one_reg reg;
+       int vmx_offset = 0;
+       int result = 0;
+
+       vmx_offset =
+               kvmppc_get_vmx_byte_offset(vcpu, vcpu->arch.mmio_vmx_offset);
+
+       if (vmx_offset == -1)
+               return -1;
+
+       reg.vval = VCPU_VSX_VR(vcpu, index);
+       *val = reg.vsx8val[vmx_offset];
+
+       return result;
+}
+
+int kvmppc_handle_vmx_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
+               unsigned int rs, unsigned int bytes, int is_default_endian)
 {
        u64 val = 0;
+       unsigned int index = rs & KVM_MMIO_REG_MASK;
        enum emulation_result emulated = EMULATE_DONE;
 
+       if (vcpu->arch.mmio_vsx_copy_nums > 2)
+               return EMULATE_FAIL;
+
        vcpu->arch.io_gpr = rs;
 
        while (vcpu->arch.mmio_vmx_copy_nums) {
-               if (kvmppc_get_vmx_data(vcpu, rs, &val) == -1)
+               switch (vcpu->arch.mmio_copy_type) {
+               case KVMPPC_VMX_COPY_DWORD:
+                       if (kvmppc_get_vmx_dword(vcpu, index, &val) == -1)
+                               return EMULATE_FAIL;
+
+                       break;
+               case KVMPPC_VMX_COPY_WORD:
+                       if (kvmppc_get_vmx_word(vcpu, index, &val) == -1)
+                               return EMULATE_FAIL;
+                       break;
+               case KVMPPC_VMX_COPY_HWORD:
+                       if (kvmppc_get_vmx_hword(vcpu, index, &val) == -1)
+                               return EMULATE_FAIL;
+                       break;
+               case KVMPPC_VMX_COPY_BYTE:
+                       if (kvmppc_get_vmx_byte(vcpu, index, &val) == -1)
+                               return EMULATE_FAIL;
+                       break;
+               default:
                        return EMULATE_FAIL;
+               }
 
-               emulated = kvmppc_handle_store(run, vcpu, val, 8,
+               emulated = kvmppc_handle_store(run, vcpu, val, bytes,
                                is_default_endian);
                if (emulated != EMULATE_DONE)
                        break;
 
                vcpu->arch.paddr_accessed += run->mmio.len;
                vcpu->arch.mmio_vmx_copy_nums--;
+               vcpu->arch.mmio_vmx_offset++;
        }
 
        return emulated;
@@ -1422,11 +1616,11 @@ static int kvmppc_emulate_mmio_vmx_loadstore(struct kvm_vcpu *vcpu,
        vcpu->arch.paddr_accessed += run->mmio.len;
 
        if (!vcpu->mmio_is_write) {
-               emulated = kvmppc_handle_load128_by2x64(run, vcpu,
-                               vcpu->arch.io_gpr, 1);
+               emulated = kvmppc_handle_vmx_load(run, vcpu,
+                               vcpu->arch.io_gpr, run->mmio.len, 1);
        } else {
-               emulated = kvmppc_handle_store128_by2x64(run, vcpu,
-                               vcpu->arch.io_gpr, 1);
+               emulated = kvmppc_handle_vmx_store(run, vcpu,
+                               vcpu->arch.io_gpr, run->mmio.len, 1);
        }
 
        switch (emulated) {
@@ -1570,8 +1764,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
                }
 #endif
 #ifdef CONFIG_ALTIVEC
-               if (vcpu->arch.mmio_vmx_copy_nums > 0)
+               if (vcpu->arch.mmio_vmx_copy_nums > 0) {
                        vcpu->arch.mmio_vmx_copy_nums--;
+                       vcpu->arch.mmio_vmx_offset++;
+               }
 
                if (vcpu->arch.mmio_vmx_copy_nums > 0) {
                        r = kvmppc_emulate_mmio_vmx_loadstore(vcpu, run);
@@ -1784,16 +1980,16 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
        void __user *argp = (void __user *)arg;
        long r;
 
-       vcpu_load(vcpu);
-
        switch (ioctl) {
        case KVM_ENABLE_CAP:
        {
                struct kvm_enable_cap cap;
                r = -EFAULT;
+               vcpu_load(vcpu);
                if (copy_from_user(&cap, argp, sizeof(cap)))
                        goto out;
                r = kvm_vcpu_ioctl_enable_cap(vcpu, &cap);
+               vcpu_put(vcpu);
                break;
        }
 
@@ -1815,9 +2011,11 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
        case KVM_DIRTY_TLB: {
                struct kvm_dirty_tlb dirty;
                r = -EFAULT;
+               vcpu_load(vcpu);
                if (copy_from_user(&dirty, argp, sizeof(dirty)))
                        goto out;
                r = kvm_vcpu_ioctl_dirty_tlb(vcpu, &dirty);
+               vcpu_put(vcpu);
                break;
        }
 #endif
@@ -1826,7 +2024,6 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
        }
 
 out:
-       vcpu_put(vcpu);
        return r;
 }
 
diff --git a/arch/powerpc/kvm/tm.S b/arch/powerpc/kvm/tm.S
new file mode 100644 (file)
index 0000000..90e330f
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Derived from book3s_hv_rmhandlers.S, which is:
+ *
+ * Copyright 2011 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
+ *
+ */
+
+#include <asm/reg.h>
+#include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
+#include <asm/export.h>
+#include <asm/tm.h>
+#include <asm/cputable.h>
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+#define VCPU_GPRS_TM(reg) (((reg) * ULONG_SIZE) + VCPU_GPR_TM)
+
+/*
+ * Save transactional state and TM-related registers.
+ * Called with:
+ * - r3 pointing to the vcpu struct
+ * - r4 points to the MSR with current TS bits:
+ *     (For HV KVM, it is VCPU_MSR ; For PR KVM, it is host MSR).
+ * This can modify all checkpointed registers, but
+ * restores r1, r2 before exit.
+ */
+_GLOBAL(__kvmppc_save_tm)
+       mflr    r0
+       std     r0, PPC_LR_STKOFF(r1)
+
+       /* Turn on TM. */
+       mfmsr   r8
+       li      r0, 1
+       rldimi  r8, r0, MSR_TM_LG, 63-MSR_TM_LG
+       ori     r8, r8, MSR_FP
+       oris    r8, r8, (MSR_VEC | MSR_VSX)@h
+       mtmsrd  r8
+
+       rldicl. r4, r4, 64 - MSR_TS_S_LG, 62
+       beq     1f      /* TM not active in guest. */
+
+       std     r1, HSTATE_SCRATCH2(r13)
+       std     r3, HSTATE_SCRATCH1(r13)
+
+#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
+BEGIN_FTR_SECTION
+       /* Emulation of the treclaim instruction needs TEXASR before treclaim */
+       mfspr   r6, SPRN_TEXASR
+       std     r6, VCPU_ORIG_TEXASR(r3)
+END_FTR_SECTION_IFSET(CPU_FTR_P9_TM_HV_ASSIST)
+#endif
+
+       /* Clear the MSR RI since r1, r13 are all going to be foobar. */
+       li      r5, 0
+       mtmsrd  r5, 1
+
+       li      r3, TM_CAUSE_KVM_RESCHED
+
+       /* All GPRs are volatile at this point. */
+       TRECLAIM(R3)
+
+       /* Temporarily store r13 and r9 so we have some regs to play with */
+       SET_SCRATCH0(r13)
+       GET_PACA(r13)
+       std     r9, PACATMSCRATCH(r13)
+       ld      r9, HSTATE_SCRATCH1(r13)
+
+       /* Get a few more GPRs free. */
+       std     r29, VCPU_GPRS_TM(29)(r9)
+       std     r30, VCPU_GPRS_TM(30)(r9)
+       std     r31, VCPU_GPRS_TM(31)(r9)
+
+       /* Save away PPR and DSCR soon so don't run with user values. */
+       mfspr   r31, SPRN_PPR
+       HMT_MEDIUM
+       mfspr   r30, SPRN_DSCR
+#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
+       ld      r29, HSTATE_DSCR(r13)
+       mtspr   SPRN_DSCR, r29
+#endif
+
+       /* Save all but r9, r13 & r29-r31 */
+       reg = 0
+       .rept   29
+       .if (reg != 9) && (reg != 13)
+       std     reg, VCPU_GPRS_TM(reg)(r9)
+       .endif
+       reg = reg + 1
+       .endr
+       /* ... now save r13 */
+       GET_SCRATCH0(r4)
+       std     r4, VCPU_GPRS_TM(13)(r9)
+       /* ... and save r9 */
+       ld      r4, PACATMSCRATCH(r13)
+       std     r4, VCPU_GPRS_TM(9)(r9)
+
+       /* Reload stack pointer and TOC. */
+       ld      r1, HSTATE_SCRATCH2(r13)
+       ld      r2, PACATOC(r13)
+
+       /* Set MSR RI now we have r1 and r13 back. */
+       li      r5, MSR_RI
+       mtmsrd  r5, 1
+
+       /* Save away checkpinted SPRs. */
+       std     r31, VCPU_PPR_TM(r9)
+       std     r30, VCPU_DSCR_TM(r9)
+       mflr    r5
+       mfcr    r6
+       mfctr   r7
+       mfspr   r8, SPRN_AMR
+       mfspr   r10, SPRN_TAR
+       mfxer   r11
+       std     r5, VCPU_LR_TM(r9)
+       stw     r6, VCPU_CR_TM(r9)
+       std     r7, VCPU_CTR_TM(r9)
+       std     r8, VCPU_AMR_TM(r9)
+       std     r10, VCPU_TAR_TM(r9)
+       std     r11, VCPU_XER_TM(r9)
+
+       /* Restore r12 as trap number. */
+       lwz     r12, VCPU_TRAP(r9)
+
+       /* Save FP/VSX. */
+       addi    r3, r9, VCPU_FPRS_TM
+       bl      store_fp_state
+       addi    r3, r9, VCPU_VRS_TM
+       bl      store_vr_state
+       mfspr   r6, SPRN_VRSAVE
+       stw     r6, VCPU_VRSAVE_TM(r9)
+1:
+       /*
+        * We need to save these SPRs after the treclaim so that the software
+        * error code is recorded correctly in the TEXASR.  Also the user may
+        * change these outside of a transaction, so they must always be
+        * context switched.
+        */
+       mfspr   r7, SPRN_TEXASR
+       std     r7, VCPU_TEXASR(r9)
+11:
+       mfspr   r5, SPRN_TFHAR
+       mfspr   r6, SPRN_TFIAR
+       std     r5, VCPU_TFHAR(r9)
+       std     r6, VCPU_TFIAR(r9)
+
+       ld      r0, PPC_LR_STKOFF(r1)
+       mtlr    r0
+       blr
+
+/*
+ * _kvmppc_save_tm_pr() is a wrapper around __kvmppc_save_tm(), so that it can
+ * be invoked from C function by PR KVM only.
+ */
+_GLOBAL(_kvmppc_save_tm_pr)
+       mflr    r5
+       std     r5, PPC_LR_STKOFF(r1)
+       stdu    r1, -SWITCH_FRAME_SIZE(r1)
+       SAVE_NVGPRS(r1)
+
+       /* save MSR since TM/math bits might be impacted
+        * by __kvmppc_save_tm().
+        */
+       mfmsr   r5
+       SAVE_GPR(5, r1)
+
+       /* also save DSCR/CR/TAR so that it can be recovered later */
+       mfspr   r6, SPRN_DSCR
+       SAVE_GPR(6, r1)
+
+       mfcr    r7
+       stw     r7, _CCR(r1)
+
+       mfspr   r8, SPRN_TAR
+       SAVE_GPR(8, r1)
+
+       bl      __kvmppc_save_tm
+
+       REST_GPR(8, r1)
+       mtspr   SPRN_TAR, r8
+
+       ld      r7, _CCR(r1)
+       mtcr    r7
+
+       REST_GPR(6, r1)
+       mtspr   SPRN_DSCR, r6
+
+       /* need preserve current MSR's MSR_TS bits */
+       REST_GPR(5, r1)
+       mfmsr   r6
+       rldicl  r6, r6, 64 - MSR_TS_S_LG, 62
+       rldimi  r5, r6, MSR_TS_S_LG, 63 - MSR_TS_T_LG
+       mtmsrd  r5
+
+       REST_NVGPRS(r1)
+       addi    r1, r1, SWITCH_FRAME_SIZE
+       ld      r5, PPC_LR_STKOFF(r1)
+       mtlr    r5
+       blr
+
+EXPORT_SYMBOL_GPL(_kvmppc_save_tm_pr);
+
+/*
+ * Restore transactional state and TM-related registers.
+ * Called with:
+ *  - r3 pointing to the vcpu struct.
+ *  - r4 is the guest MSR with desired TS bits:
+ *     For HV KVM, it is VCPU_MSR
+ *     For PR KVM, it is provided by caller
+ * This potentially modifies all checkpointed registers.
+ * It restores r1, r2 from the PACA.
+ */
+_GLOBAL(__kvmppc_restore_tm)
+       mflr    r0
+       std     r0, PPC_LR_STKOFF(r1)
+
+       /* Turn on TM/FP/VSX/VMX so we can restore them. */
+       mfmsr   r5
+       li      r6, MSR_TM >> 32
+       sldi    r6, r6, 32
+       or      r5, r5, r6
+       ori     r5, r5, MSR_FP
+       oris    r5, r5, (MSR_VEC | MSR_VSX)@h
+       mtmsrd  r5
+
+       /*
+        * The user may change these outside of a transaction, so they must
+        * always be context switched.
+        */
+       ld      r5, VCPU_TFHAR(r3)
+       ld      r6, VCPU_TFIAR(r3)
+       ld      r7, VCPU_TEXASR(r3)
+       mtspr   SPRN_TFHAR, r5
+       mtspr   SPRN_TFIAR, r6
+       mtspr   SPRN_TEXASR, r7
+
+       mr      r5, r4
+       rldicl. r5, r5, 64 - MSR_TS_S_LG, 62
+       beqlr           /* TM not active in guest */
+       std     r1, HSTATE_SCRATCH2(r13)
+
+       /* Make sure the failure summary is set, otherwise we'll program check
+        * when we trechkpt.  It's possible that this might have been not set
+        * on a kvmppc_set_one_reg() call but we shouldn't let this crash the
+        * host.
+        */
+       oris    r7, r7, (TEXASR_FS)@h
+       mtspr   SPRN_TEXASR, r7
+
+       /*
+        * We need to load up the checkpointed state for the guest.
+        * We need to do this early as it will blow away any GPRs, VSRs and
+        * some SPRs.
+        */
+
+       mr      r31, r3
+       addi    r3, r31, VCPU_FPRS_TM
+       bl      load_fp_state
+       addi    r3, r31, VCPU_VRS_TM
+       bl      load_vr_state
+       mr      r3, r31
+       lwz     r7, VCPU_VRSAVE_TM(r3)
+       mtspr   SPRN_VRSAVE, r7
+
+       ld      r5, VCPU_LR_TM(r3)
+       lwz     r6, VCPU_CR_TM(r3)
+       ld      r7, VCPU_CTR_TM(r3)
+       ld      r8, VCPU_AMR_TM(r3)
+       ld      r9, VCPU_TAR_TM(r3)
+       ld      r10, VCPU_XER_TM(r3)
+       mtlr    r5
+       mtcr    r6
+       mtctr   r7
+       mtspr   SPRN_AMR, r8
+       mtspr   SPRN_TAR, r9
+       mtxer   r10
+
+       /*
+        * Load up PPR and DSCR values but don't put them in the actual SPRs
+        * till the last moment to avoid running with userspace PPR and DSCR for
+        * too long.
+        */
+       ld      r29, VCPU_DSCR_TM(r3)
+       ld      r30, VCPU_PPR_TM(r3)
+
+       std     r2, PACATMSCRATCH(r13) /* Save TOC */
+
+       /* Clear the MSR RI since r1, r13 are all going to be foobar. */
+       li      r5, 0
+       mtmsrd  r5, 1
+
+       /* Load GPRs r0-r28 */
+       reg = 0
+       .rept   29
+       ld      reg, VCPU_GPRS_TM(reg)(r31)
+       reg = reg + 1
+       .endr
+
+       mtspr   SPRN_DSCR, r29
+       mtspr   SPRN_PPR, r30
+
+       /* Load final GPRs */
+       ld      29, VCPU_GPRS_TM(29)(r31)
+       ld      30, VCPU_GPRS_TM(30)(r31)
+       ld      31, VCPU_GPRS_TM(31)(r31)
+
+       /* TM checkpointed state is now setup.  All GPRs are now volatile. */
+       TRECHKPT
+
+       /* Now let's get back the state we need. */
+       HMT_MEDIUM
+       GET_PACA(r13)
+#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
+       ld      r29, HSTATE_DSCR(r13)
+       mtspr   SPRN_DSCR, r29
+#endif
+       ld      r1, HSTATE_SCRATCH2(r13)
+       ld      r2, PACATMSCRATCH(r13)
+
+       /* Set the MSR RI since we have our registers back. */
+       li      r5, MSR_RI
+       mtmsrd  r5, 1
+       ld      r0, PPC_LR_STKOFF(r1)
+       mtlr    r0
+       blr
+
+/*
+ * _kvmppc_restore_tm_pr() is a wrapper around __kvmppc_restore_tm(), so that it
+ * can be invoked from C function by PR KVM only.
+ */
+_GLOBAL(_kvmppc_restore_tm_pr)
+       mflr    r5
+       std     r5, PPC_LR_STKOFF(r1)
+       stdu    r1, -SWITCH_FRAME_SIZE(r1)
+       SAVE_NVGPRS(r1)
+
+       /* save MSR to avoid TM/math bits change */
+       mfmsr   r5
+       SAVE_GPR(5, r1)
+
+       /* also save DSCR/CR/TAR so that it can be recovered later */
+       mfspr   r6, SPRN_DSCR
+       SAVE_GPR(6, r1)
+
+       mfcr    r7
+       stw     r7, _CCR(r1)
+
+       mfspr   r8, SPRN_TAR
+       SAVE_GPR(8, r1)
+
+       bl      __kvmppc_restore_tm
+
+       REST_GPR(8, r1)
+       mtspr   SPRN_TAR, r8
+
+       ld      r7, _CCR(r1)
+       mtcr    r7
+
+       REST_GPR(6, r1)
+       mtspr   SPRN_DSCR, r6
+
+       /* need preserve current MSR's MSR_TS bits */
+       REST_GPR(5, r1)
+       mfmsr   r6
+       rldicl  r6, r6, 64 - MSR_TS_S_LG, 62
+       rldimi  r5, r6, MSR_TS_S_LG, 63 - MSR_TS_T_LG
+       mtmsrd  r5
+
+       REST_NVGPRS(r1)
+       addi    r1, r1, SWITCH_FRAME_SIZE
+       ld      r5, PPC_LR_STKOFF(r1)
+       mtlr    r5
+       blr
+
+EXPORT_SYMBOL_GPL(_kvmppc_restore_tm_pr);
+#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
index 8cecda4bd66ae43d79f1c16beb4e229ecd26cc92..5c8530d0c611898f012e2cc8f300a7112715c351 100644 (file)
@@ -215,7 +215,7 @@ void __init mem_topology_setup(void)
        /* Place all memblock_regions in the same node and merge contiguous
         * memblock_regions
         */
-       memblock_set_node(0, (phys_addr_t)ULLONG_MAX, &memblock.memory, 0);
+       memblock_set_node(0, PHYS_ADDR_MAX, &memblock.memory, 0);
 }
 
 void __init initmem_init(void)
index 42e581a268e1901997de938de01f5b9181f02033..f12680c9b9475e2b130da3369644e797575f7a80 100644 (file)
@@ -32,6 +32,7 @@ config RISCV
        select HAVE_MEMBLOCK_NODE_MAP
        select HAVE_DMA_CONTIGUOUS
        select HAVE_GENERIC_DMA_COHERENT
+       select HAVE_PERF_EVENTS
        select IRQ_DOMAIN
        select NO_BOOTMEM
        select RISCV_ISA_A if SMP
@@ -193,6 +194,19 @@ config RISCV_ISA_C
 config RISCV_ISA_A
        def_bool y
 
+menu "supported PMU type"
+       depends on PERF_EVENTS
+
+config RISCV_BASE_PMU
+       bool "Base Performance Monitoring Unit"
+       def_bool y
+       help
+         A base PMU that serves as a reference implementation and has limited
+         feature of perf.  It can run on any RISC-V machines so serves as the
+         fallback, but this option can also be disable to reduce kernel size.
+
+endmenu
+
 endmenu
 
 menu "Kernel type"
index 76e958a5414a88f9314b7bf1298eed790c1415a2..6d4a5f6c3f4f6e92b3c709520c5230da5a3826d7 100644 (file)
@@ -71,6 +71,9 @@ KBUILD_CFLAGS_MODULE += $(call cc-option,-mno-relax)
 # architectures.  It's faster to have GCC emit only aligned accesses.
 KBUILD_CFLAGS += $(call cc-option,-mstrict-align)
 
+# arch specific predefines for sparse
+CHECKFLAGS += -D__riscv -D__riscv_xlen=$(BITS)
+
 head-y := arch/riscv/kernel/head.o
 
 core-y += arch/riscv/kernel/ arch/riscv/mm/
index bca0eee733b05fc5f3217296184b57aac6f90faf..07326466871b0d74fb0c43f219bc49058f663468 100644 (file)
@@ -44,6 +44,7 @@ CONFIG_INPUT_MOUSEDEV=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_HVC_RISCV_SBI=y
 # CONFIG_PTP_1588_CLOCK is not set
 CONFIG_DRM=y
 CONFIG_DRM_RADEON=y
index 4286a5f838760c7ad4d922ddd2b49286c374df56..576ffdca06baf1d7fe51de655a63286550c93626 100644 (file)
@@ -25,6 +25,7 @@ generic-y += kdebug.h
 generic-y += kmap_types.h
 generic-y += kvm_para.h
 generic-y += local.h
+generic-y += local64.h
 generic-y += mm-arch-hooks.h
 generic-y += mman.h
 generic-y += module.h
index efd89a88d2d0e9b2bcd639a436a6143440a24d77..8f13074413a7d652729f7fc4871ac5d2a74eea3e 100644 (file)
@@ -47,7 +47,7 @@ static inline void flush_dcache_page(struct page *page)
 
 #else /* CONFIG_SMP */
 
-#define flush_icache_all() sbi_remote_fence_i(0)
+#define flush_icache_all() sbi_remote_fence_i(NULL)
 void flush_icache_mm(struct mm_struct *mm, bool local);
 
 #endif /* CONFIG_SMP */
diff --git a/arch/riscv/include/asm/perf_event.h b/arch/riscv/include/asm/perf_event.h
new file mode 100644 (file)
index 0000000..0e638a0
--- /dev/null
@@ -0,0 +1,84 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 SiFive
+ * Copyright (C) 2018 Andes Technology Corporation
+ *
+ */
+
+#ifndef _ASM_RISCV_PERF_EVENT_H
+#define _ASM_RISCV_PERF_EVENT_H
+
+#include <linux/perf_event.h>
+#include <linux/ptrace.h>
+
+#define RISCV_BASE_COUNTERS    2
+
+/*
+ * The RISCV_MAX_COUNTERS parameter should be specified.
+ */
+
+#ifdef CONFIG_RISCV_BASE_PMU
+#define RISCV_MAX_COUNTERS     2
+#endif
+
+#ifndef RISCV_MAX_COUNTERS
+#error "Please provide a valid RISCV_MAX_COUNTERS for the PMU."
+#endif
+
+/*
+ * These are the indexes of bits in counteren register *minus* 1,
+ * except for cycle.  It would be coherent if it can directly mapped
+ * to counteren bit definition, but there is a *time* register at
+ * counteren[1].  Per-cpu structure is scarce resource here.
+ *
+ * According to the spec, an implementation can support counter up to
+ * mhpmcounter31, but many high-end processors has at most 6 general
+ * PMCs, we give the definition to MHPMCOUNTER8 here.
+ */
+#define RISCV_PMU_CYCLE                0
+#define RISCV_PMU_INSTRET      1
+#define RISCV_PMU_MHPMCOUNTER3 2
+#define RISCV_PMU_MHPMCOUNTER4 3
+#define RISCV_PMU_MHPMCOUNTER5 4
+#define RISCV_PMU_MHPMCOUNTER6 5
+#define RISCV_PMU_MHPMCOUNTER7 6
+#define RISCV_PMU_MHPMCOUNTER8 7
+
+#define RISCV_OP_UNSUPP                (-EOPNOTSUPP)
+
+struct cpu_hw_events {
+       /* # currently enabled events*/
+       int                     n_events;
+       /* currently enabled events */
+       struct perf_event       *events[RISCV_MAX_COUNTERS];
+       /* vendor-defined PMU data */
+       void                    *platform;
+};
+
+struct riscv_pmu {
+       struct pmu      *pmu;
+
+       /* generic hw/cache events table */
+       const int       *hw_events;
+       const int       (*cache_events)[PERF_COUNT_HW_CACHE_MAX]
+                                      [PERF_COUNT_HW_CACHE_OP_MAX]
+                                      [PERF_COUNT_HW_CACHE_RESULT_MAX];
+       /* method used to map hw/cache events */
+       int             (*map_hw_event)(u64 config);
+       int             (*map_cache_event)(u64 config);
+
+       /* max generic hw events in map */
+       int             max_events;
+       /* number total counters, 2(base) + x(general) */
+       int             num_counters;
+       /* the width of the counter */
+       int             counter_width;
+
+       /* vendor-defined PMU features */
+       void            *platform;
+
+       irqreturn_t     (*handle_irq)(int irq_num, void *dev);
+       int             irq;
+};
+
+#endif /* _ASM_RISCV_PERF_EVENT_H */
index 7b209aec355db5edeff57c186f542ad4ac44c894..85c2d8bae9571ab2c3557b34b04b59d3355733a6 100644 (file)
@@ -49,7 +49,7 @@ static inline void flush_tlb_range(struct vm_area_struct *vma,
 
 #include <asm/sbi.h>
 
-#define flush_tlb_all() sbi_remote_sfence_vma(0, 0, -1)
+#define flush_tlb_all() sbi_remote_sfence_vma(NULL, 0, -1)
 #define flush_tlb_page(vma, addr) flush_tlb_range(vma, addr, 0)
 #define flush_tlb_range(vma, start, end) \
        sbi_remote_sfence_vma(mm_cpumask((vma)->vm_mm)->bits, \
index 14b0b22fb57875dfe920685265a79da317c517e0..473cfc84e412f3827703caaadffa34a8983c978d 100644 (file)
@@ -392,19 +392,21 @@ do {                                                              \
 })
 
 
-extern unsigned long __must_check __copy_user(void __user *to,
+extern unsigned long __must_check __asm_copy_to_user(void __user *to,
+       const void *from, unsigned long n);
+extern unsigned long __must_check __asm_copy_from_user(void *to,
        const void __user *from, unsigned long n);
 
 static inline unsigned long
 raw_copy_from_user(void *to, const void __user *from, unsigned long n)
 {
-       return __copy_user(to, from, n);
+       return __asm_copy_to_user(to, from, n);
 }
 
 static inline unsigned long
 raw_copy_to_user(void __user *to, const void *from, unsigned long n)
 {
-       return __copy_user(to, from, n);
+       return __asm_copy_from_user(to, from, n);
 }
 
 extern long strncpy_from_user(char *dest, const char __user *src, long count);
index 8586dd96c2f012ca42af358c0ab58cd2ce277322..e1274fc03af42de6b0a98fe0911e98d14db4dec8 100644 (file)
@@ -39,4 +39,6 @@ obj-$(CONFIG_MODULE_SECTIONS) += module-sections.o
 obj-$(CONFIG_FUNCTION_TRACER)  += mcount.o ftrace.o
 obj-$(CONFIG_DYNAMIC_FTRACE)   += mcount-dyn.o
 
+obj-$(CONFIG_PERF_EVENTS)      += perf_event.o
+
 clean:
index ce9bdc57a2a161b1ab16b8a593b031a0e2df72ed..5721624886a1cc8f0af054da3bec133b53de0381 100644 (file)
@@ -126,5 +126,5 @@ do_trace:
        RESTORE_ABI_STATE
        ret
 ENDPROC(_mcount)
-EXPORT_SYMBOL(_mcount)
 #endif
+EXPORT_SYMBOL(_mcount)
index 5dddba301d0a726ff78e97acca1b051c123a8bb7..1d5e9b934b8ca5b5b78a64af5e1c06e334b7e5f2 100644 (file)
 #include <linux/errno.h>
 #include <linux/moduleloader.h>
 
+static int apply_r_riscv_32_rela(struct module *me, u32 *location, Elf_Addr v)
+{
+       if (v != (u32)v) {
+               pr_err("%s: value %016llx out of range for 32-bit field\n",
+                      me->name, v);
+               return -EINVAL;
+       }
+       *location = v;
+       return 0;
+}
+
 static int apply_r_riscv_64_rela(struct module *me, u32 *location, Elf_Addr v)
 {
        *(u64 *)location = v;
@@ -265,6 +276,7 @@ static int apply_r_riscv_sub32_rela(struct module *me, u32 *location,
 
 static int (*reloc_handlers_rela[]) (struct module *me, u32 *location,
                                Elf_Addr v) = {
+       [R_RISCV_32]                    = apply_r_riscv_32_rela,
        [R_RISCV_64]                    = apply_r_riscv_64_rela,
        [R_RISCV_BRANCH]                = apply_r_riscv_branch_rela,
        [R_RISCV_JAL]                   = apply_r_riscv_jal_rela,
diff --git a/arch/riscv/kernel/perf_event.c b/arch/riscv/kernel/perf_event.c
new file mode 100644 (file)
index 0000000..b0e10c4
--- /dev/null
@@ -0,0 +1,485 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2008 Thomas Gleixner <tglx@linutronix.de>
+ * Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar
+ * Copyright (C) 2009 Jaswinder Singh Rajput
+ * Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter
+ * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra
+ * Copyright (C) 2009 Intel Corporation, <markus.t.metzger@intel.com>
+ * Copyright (C) 2009 Google, Inc., Stephane Eranian
+ * Copyright 2014 Tilera Corporation. All Rights Reserved.
+ * Copyright (C) 2018 Andes Technology Corporation
+ *
+ * Perf_events support for RISC-V platforms.
+ *
+ * Since the spec. (as of now, Priv-Spec 1.10) does not provide enough
+ * functionality for perf event to fully work, this file provides
+ * the very basic framework only.
+ *
+ * For platform portings, please check Documentations/riscv/pmu.txt.
+ *
+ * The Copyright line includes x86 and tile ones.
+ */
+
+#include <linux/kprobes.h>
+#include <linux/kernel.h>
+#include <linux/kdebug.h>
+#include <linux/mutex.h>
+#include <linux/bitmap.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/perf_event.h>
+#include <linux/atomic.h>
+#include <linux/of.h>
+#include <asm/perf_event.h>
+
+static const struct riscv_pmu *riscv_pmu __read_mostly;
+static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
+
+/*
+ * Hardware & cache maps and their methods
+ */
+
+static const int riscv_hw_event_map[] = {
+       [PERF_COUNT_HW_CPU_CYCLES]              = RISCV_PMU_CYCLE,
+       [PERF_COUNT_HW_INSTRUCTIONS]            = RISCV_PMU_INSTRET,
+       [PERF_COUNT_HW_CACHE_REFERENCES]        = RISCV_OP_UNSUPP,
+       [PERF_COUNT_HW_CACHE_MISSES]            = RISCV_OP_UNSUPP,
+       [PERF_COUNT_HW_BRANCH_INSTRUCTIONS]     = RISCV_OP_UNSUPP,
+       [PERF_COUNT_HW_BRANCH_MISSES]           = RISCV_OP_UNSUPP,
+       [PERF_COUNT_HW_BUS_CYCLES]              = RISCV_OP_UNSUPP,
+};
+
+#define C(x) PERF_COUNT_HW_CACHE_##x
+static const int riscv_cache_event_map[PERF_COUNT_HW_CACHE_MAX]
+[PERF_COUNT_HW_CACHE_OP_MAX]
+[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
+       [C(L1D)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP,
+                       [C(RESULT_MISS)] = RISCV_OP_UNSUPP,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP,
+                       [C(RESULT_MISS)] = RISCV_OP_UNSUPP,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP,
+                       [C(RESULT_MISS)] = RISCV_OP_UNSUPP,
+               },
+       },
+       [C(L1I)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP,
+                       [C(RESULT_MISS)] = RISCV_OP_UNSUPP,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP,
+                       [C(RESULT_MISS)] = RISCV_OP_UNSUPP,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP,
+                       [C(RESULT_MISS)] = RISCV_OP_UNSUPP,
+               },
+       },
+       [C(LL)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP,
+                       [C(RESULT_MISS)] = RISCV_OP_UNSUPP,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP,
+                       [C(RESULT_MISS)] = RISCV_OP_UNSUPP,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP,
+                       [C(RESULT_MISS)] = RISCV_OP_UNSUPP,
+               },
+       },
+       [C(DTLB)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)] =  RISCV_OP_UNSUPP,
+                       [C(RESULT_MISS)] =  RISCV_OP_UNSUPP,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP,
+                       [C(RESULT_MISS)] = RISCV_OP_UNSUPP,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP,
+                       [C(RESULT_MISS)] = RISCV_OP_UNSUPP,
+               },
+       },
+       [C(ITLB)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP,
+                       [C(RESULT_MISS)] = RISCV_OP_UNSUPP,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP,
+                       [C(RESULT_MISS)] = RISCV_OP_UNSUPP,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP,
+                       [C(RESULT_MISS)] = RISCV_OP_UNSUPP,
+               },
+       },
+       [C(BPU)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP,
+                       [C(RESULT_MISS)] = RISCV_OP_UNSUPP,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP,
+                       [C(RESULT_MISS)] = RISCV_OP_UNSUPP,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)] = RISCV_OP_UNSUPP,
+                       [C(RESULT_MISS)] = RISCV_OP_UNSUPP,
+               },
+       },
+};
+
+static int riscv_map_hw_event(u64 config)
+{
+       if (config >= riscv_pmu->max_events)
+               return -EINVAL;
+
+       return riscv_pmu->hw_events[config];
+}
+
+int riscv_map_cache_decode(u64 config, unsigned int *type,
+                          unsigned int *op, unsigned int *result)
+{
+       return -ENOENT;
+}
+
+static int riscv_map_cache_event(u64 config)
+{
+       unsigned int type, op, result;
+       int err = -ENOENT;
+               int code;
+
+       err = riscv_map_cache_decode(config, &type, &op, &result);
+       if (!riscv_pmu->cache_events || err)
+               return err;
+
+       if (type >= PERF_COUNT_HW_CACHE_MAX ||
+           op >= PERF_COUNT_HW_CACHE_OP_MAX ||
+           result >= PERF_COUNT_HW_CACHE_RESULT_MAX)
+               return -EINVAL;
+
+       code = (*riscv_pmu->cache_events)[type][op][result];
+       if (code == RISCV_OP_UNSUPP)
+               return -EINVAL;
+
+       return code;
+}
+
+/*
+ * Low-level functions: reading/writing counters
+ */
+
+static inline u64 read_counter(int idx)
+{
+       u64 val = 0;
+
+       switch (idx) {
+       case RISCV_PMU_CYCLE:
+               val = csr_read(cycle);
+               break;
+       case RISCV_PMU_INSTRET:
+               val = csr_read(instret);
+               break;
+       default:
+               WARN_ON_ONCE(idx < 0 || idx > RISCV_MAX_COUNTERS);
+               return -EINVAL;
+       }
+
+       return val;
+}
+
+static inline void write_counter(int idx, u64 value)
+{
+       /* currently not supported */
+       WARN_ON_ONCE(1);
+}
+
+/*
+ * pmu->read: read and update the counter
+ *
+ * Other architectures' implementation often have a xxx_perf_event_update
+ * routine, which can return counter values when called in the IRQ, but
+ * return void when being called by the pmu->read method.
+ */
+static void riscv_pmu_read(struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       u64 prev_raw_count, new_raw_count;
+       u64 oldval;
+       int idx = hwc->idx;
+       u64 delta;
+
+       do {
+               prev_raw_count = local64_read(&hwc->prev_count);
+               new_raw_count = read_counter(idx);
+
+               oldval = local64_cmpxchg(&hwc->prev_count, prev_raw_count,
+                                        new_raw_count);
+       } while (oldval != prev_raw_count);
+
+       /*
+        * delta is the value to update the counter we maintain in the kernel.
+        */
+       delta = (new_raw_count - prev_raw_count) &
+               ((1ULL << riscv_pmu->counter_width) - 1);
+       local64_add(delta, &event->count);
+       /*
+        * Something like local64_sub(delta, &hwc->period_left) here is
+        * needed if there is an interrupt for perf.
+        */
+}
+
+/*
+ * State transition functions:
+ *
+ * stop()/start() & add()/del()
+ */
+
+/*
+ * pmu->stop: stop the counter
+ */
+static void riscv_pmu_stop(struct perf_event *event, int flags)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
+       hwc->state |= PERF_HES_STOPPED;
+
+       if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
+               riscv_pmu->pmu->read(event);
+               hwc->state |= PERF_HES_UPTODATE;
+       }
+}
+
+/*
+ * pmu->start: start the event.
+ */
+static void riscv_pmu_start(struct perf_event *event, int flags)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED)))
+               return;
+
+       if (flags & PERF_EF_RELOAD) {
+               WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE));
+
+               /*
+                * Set the counter to the period to the next interrupt here,
+                * if you have any.
+                */
+       }
+
+       hwc->state = 0;
+       perf_event_update_userpage(event);
+
+       /*
+        * Since we cannot write to counters, this serves as an initialization
+        * to the delta-mechanism in pmu->read(); otherwise, the delta would be
+        * wrong when pmu->read is called for the first time.
+        */
+       local64_set(&hwc->prev_count, read_counter(hwc->idx));
+}
+
+/*
+ * pmu->add: add the event to PMU.
+ */
+static int riscv_pmu_add(struct perf_event *event, int flags)
+{
+       struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (cpuc->n_events == riscv_pmu->num_counters)
+               return -ENOSPC;
+
+       /*
+        * We don't have general conunters, so no binding-event-to-counter
+        * process here.
+        *
+        * Indexing using hwc->config generally not works, since config may
+        * contain extra information, but here the only info we have in
+        * hwc->config is the event index.
+        */
+       hwc->idx = hwc->config;
+       cpuc->events[hwc->idx] = event;
+       cpuc->n_events++;
+
+       hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+
+       if (flags & PERF_EF_START)
+               riscv_pmu->pmu->start(event, PERF_EF_RELOAD);
+
+       return 0;
+}
+
+/*
+ * pmu->del: delete the event from PMU.
+ */
+static void riscv_pmu_del(struct perf_event *event, int flags)
+{
+       struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+       struct hw_perf_event *hwc = &event->hw;
+
+       cpuc->events[hwc->idx] = NULL;
+       cpuc->n_events--;
+       riscv_pmu->pmu->stop(event, PERF_EF_UPDATE);
+       perf_event_update_userpage(event);
+}
+
+/*
+ * Interrupt: a skeletion for reference.
+ */
+
+static DEFINE_MUTEX(pmc_reserve_mutex);
+
+irqreturn_t riscv_base_pmu_handle_irq(int irq_num, void *dev)
+{
+       return IRQ_NONE;
+}
+
+static int reserve_pmc_hardware(void)
+{
+       int err = 0;
+
+       mutex_lock(&pmc_reserve_mutex);
+       if (riscv_pmu->irq >= 0 && riscv_pmu->handle_irq) {
+               err = request_irq(riscv_pmu->irq, riscv_pmu->handle_irq,
+                                 IRQF_PERCPU, "riscv-base-perf", NULL);
+       }
+       mutex_unlock(&pmc_reserve_mutex);
+
+       return err;
+}
+
+void release_pmc_hardware(void)
+{
+       mutex_lock(&pmc_reserve_mutex);
+       if (riscv_pmu->irq >= 0)
+               free_irq(riscv_pmu->irq, NULL);
+       mutex_unlock(&pmc_reserve_mutex);
+}
+
+/*
+ * Event Initialization/Finalization
+ */
+
+static atomic_t riscv_active_events = ATOMIC_INIT(0);
+
+static void riscv_event_destroy(struct perf_event *event)
+{
+       if (atomic_dec_return(&riscv_active_events) == 0)
+               release_pmc_hardware();
+}
+
+static int riscv_event_init(struct perf_event *event)
+{
+       struct perf_event_attr *attr = &event->attr;
+       struct hw_perf_event *hwc = &event->hw;
+       int err;
+       int code;
+
+       if (atomic_inc_return(&riscv_active_events) == 1) {
+               err = reserve_pmc_hardware();
+
+               if (err) {
+                       pr_warn("PMC hardware not available\n");
+                       atomic_dec(&riscv_active_events);
+                       return -EBUSY;
+               }
+       }
+
+       switch (event->attr.type) {
+       case PERF_TYPE_HARDWARE:
+               code = riscv_pmu->map_hw_event(attr->config);
+               break;
+       case PERF_TYPE_HW_CACHE:
+               code = riscv_pmu->map_cache_event(attr->config);
+               break;
+       case PERF_TYPE_RAW:
+               return -EOPNOTSUPP;
+       default:
+               return -ENOENT;
+       }
+
+       event->destroy = riscv_event_destroy;
+       if (code < 0) {
+               event->destroy(event);
+               return code;
+       }
+
+       /*
+        * idx is set to -1 because the index of a general event should not be
+        * decided until binding to some counter in pmu->add().
+        *
+        * But since we don't have such support, later in pmu->add(), we just
+        * use hwc->config as the index instead.
+        */
+       hwc->config = code;
+       hwc->idx = -1;
+
+       return 0;
+}
+
+/*
+ * Initialization
+ */
+
+static struct pmu min_pmu = {
+       .name           = "riscv-base",
+       .event_init     = riscv_event_init,
+       .add            = riscv_pmu_add,
+       .del            = riscv_pmu_del,
+       .start          = riscv_pmu_start,
+       .stop           = riscv_pmu_stop,
+       .read           = riscv_pmu_read,
+};
+
+static const struct riscv_pmu riscv_base_pmu = {
+       .pmu = &min_pmu,
+       .max_events = ARRAY_SIZE(riscv_hw_event_map),
+       .map_hw_event = riscv_map_hw_event,
+       .hw_events = riscv_hw_event_map,
+       .map_cache_event = riscv_map_cache_event,
+       .cache_events = &riscv_cache_event_map,
+       .counter_width = 63,
+       .num_counters = RISCV_BASE_COUNTERS + 0,
+       .handle_irq = &riscv_base_pmu_handle_irq,
+
+       /* This means this PMU has no IRQ. */
+       .irq = -1,
+};
+
+static const struct of_device_id riscv_pmu_of_ids[] = {
+       {.compatible = "riscv,base-pmu",        .data = &riscv_base_pmu},
+       { /* sentinel value */ }
+};
+
+int __init init_hw_perf_events(void)
+{
+       struct device_node *node = of_find_node_by_type(NULL, "pmu");
+       const struct of_device_id *of_id;
+
+       riscv_pmu = &riscv_base_pmu;
+
+       if (node) {
+               of_id = of_match_node(riscv_pmu_of_ids, node);
+
+               if (of_id)
+                       riscv_pmu = of_id->data;
+       }
+
+       perf_pmu_register(riscv_pmu->pmu, "cpu", PERF_TYPE_RAW);
+       return 0;
+}
+arch_initcall(init_hw_perf_events);
index 5517342487489b6ee35c4a95bbfa3d5c4a31f2aa..f247d6d2137c4515678052565b1ab43a29c523e2 100644 (file)
@@ -13,6 +13,7 @@
  * Assembly functions that may be used (directly or indirectly) by modules
  */
 EXPORT_SYMBOL(__clear_user);
-EXPORT_SYMBOL(__copy_user);
+EXPORT_SYMBOL(__asm_copy_to_user);
+EXPORT_SYMBOL(__asm_copy_from_user);
 EXPORT_SYMBOL(memset);
 EXPORT_SYMBOL(memcpy);
index b99d9dd21fd0bfdbe837969d22b01f4f220cc184..81a1952015a6556d3428f6e3ab3b541d7f371bfa 100644 (file)
@@ -148,7 +148,7 @@ int is_valid_bugaddr(unsigned long pc)
 
        if (pc < PAGE_OFFSET)
                return 0;
-       if (probe_kernel_address((bug_insn_t __user *)pc, insn))
+       if (probe_kernel_address((bug_insn_t *)pc, insn))
                return 0;
        return (insn == __BUG_INSN);
 }
index 58fb2877c865286a32894d343f483202f28c229e..399e6f0c2d98ee7be7926c490f3b356f2053f7d0 100644 (file)
@@ -13,7 +13,8 @@ _epc:
        .previous
        .endm
 
-ENTRY(__copy_user)
+ENTRY(__asm_copy_to_user)
+ENTRY(__asm_copy_from_user)
 
        /* Enable access to user memory */
        li t6, SR_SUM
@@ -63,7 +64,8 @@ ENTRY(__copy_user)
        addi a0, a0, 1
        bltu a1, a3, 5b
        j 3b
-ENDPROC(__copy_user)
+ENDPROC(__asm_copy_to_user)
+ENDPROC(__asm_copy_from_user)
 
 
 ENTRY(__clear_user)
@@ -84,7 +86,7 @@ ENTRY(__clear_user)
        bgeu t0, t1, 2f
        bltu a0, t0, 4f
 1:
-       fixup REG_S, zero, (a0), 10f
+       fixup REG_S, zero, (a0), 11f
        addi a0, a0, SZREG
        bltu a0, t1, 1b
 2:
@@ -96,12 +98,12 @@ ENTRY(__clear_user)
        li a0, 0
        ret
 4: /* Edge case: unalignment */
-       fixup sb, zero, (a0), 10f
+       fixup sb, zero, (a0), 11f
        addi a0, a0, 1
        bltu a0, t0, 4b
        j 1b
 5: /* Edge case: remainder */
-       fixup sb, zero, (a0), 10f
+       fixup sb, zero, (a0), 11f
        addi a0, a0, 1
        bltu a0, a3, 5b
        j 3b
@@ -109,9 +111,14 @@ ENDPROC(__clear_user)
 
        .section .fixup,"ax"
        .balign 4
+       /* Fixup code for __copy_user(10) and __clear_user(11) */
 10:
        /* Disable access to user memory */
        csrs sstatus, t6
-       sub a0, a3, a0
+       mv a0, a2
+       ret
+11:
+       csrs sstatus, t6
+       mv a0, a1
        ret
        .previous
index 0563fd3e84585769f7acd0f093f30a48eaab9f54..480bb02ccacdd07de17ffda81fae140ee748a505 100644 (file)
@@ -6,36 +6,38 @@
 
 struct css_general_char {
        u64 : 12;
-       u32 dynio : 1;   /* bit 12 */
-       u32 : 4;
-       u32 eadm : 1;    /* bit 17 */
-       u32 : 23;
-       u32 aif : 1;     /* bit 41 */
-       u32 : 3;
-       u32 mcss : 1;    /* bit 45 */
-       u32 fcs : 1;     /* bit 46 */
-       u32 : 1;
-       u32 ext_mb : 1;  /* bit 48 */
-       u32 : 7;
-       u32 aif_tdd : 1; /* bit 56 */
-       u32 : 1;
-       u32 qebsm : 1;   /* bit 58 */
-       u32 : 2;
-       u32 aiv : 1;     /* bit 61 */
-       u32 : 5;
-       u32 aif_osa : 1; /* bit 67 */
-       u32 : 12;
-       u32 eadm_rf : 1; /* bit 80 */
-       u32 : 1;
-       u32 cib : 1;     /* bit 82 */
-       u32 : 5;
-       u32 fcx : 1;     /* bit 88 */
-       u32 : 19;
-       u32 alt_ssi : 1; /* bit 108 */
-       u32 : 1;
-       u32 narf : 1;    /* bit 110 */
-       u32 : 12;
-       u32 util_str : 1;/* bit 123 */
+       u64 dynio : 1;   /* bit 12 */
+       u64 : 4;
+       u64 eadm : 1;    /* bit 17 */
+       u64 : 23;
+       u64 aif : 1;     /* bit 41 */
+       u64 : 3;
+       u64 mcss : 1;    /* bit 45 */
+       u64 fcs : 1;     /* bit 46 */
+       u64 : 1;
+       u64 ext_mb : 1;  /* bit 48 */
+       u64 : 7;
+       u64 aif_tdd : 1; /* bit 56 */
+       u64 : 1;
+       u64 qebsm : 1;   /* bit 58 */
+       u64 : 2;
+       u64 aiv : 1;     /* bit 61 */
+       u64 : 2;
+
+       u64 : 3;
+       u64 aif_osa : 1; /* bit 67 */
+       u64 : 12;
+       u64 eadm_rf : 1; /* bit 80 */
+       u64 : 1;
+       u64 cib : 1;     /* bit 82 */
+       u64 : 5;
+       u64 fcx : 1;     /* bit 88 */
+       u64 : 19;
+       u64 alt_ssi : 1; /* bit 108 */
+       u64 : 1;
+       u64 narf : 1;    /* bit 110 */
+       u64 : 12;
+       u64 util_str : 1;/* bit 123 */
 } __packed;
 
 extern struct css_general_char css_general_characteristics;
index 4d61a085982b3e2a669141372fd38c40c6ebb851..dd4f3d3e644fc537a8613e0c611d0932ae2d4707 100644 (file)
@@ -77,7 +77,7 @@ config SUPERH32
        select PERF_EVENTS
        select ARCH_HIBERNATION_POSSIBLE if MMU
        select SPARSE_IRQ
-       select HAVE_CC_STACKPROTECTOR
+       select HAVE_STACKPROTECTOR
 
 config SUPERH64
        def_bool "$(ARCH)" = "sh64"
@@ -687,7 +687,7 @@ config SMP
          People using multiprocessor machines who say Y here should also say
          Y to "Enhanced Real Time Clock Support", below.
 
-         See also <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO
+         See also <file:Documentation/lockup-watchdogs.txt> and the SMP-HOWTO
          available at <http://www.tldp.org/docs.html#howto>.
 
          If you don't know what to do here, say N.
index d7d232dea33e61839d02f50b623127ea87329c43..3cba60ff7aab0941ab557707ed39647734e9bc36 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/i2c.h>
-#include <linux/i2c-pca-platform.h>
+#include <linux/platform_data/i2c-pca-platform.h>
 #include <linux/i2c-algo-pca.h>
 #include <linux/usb/r8a66597.h>
 #include <linux/sh_intc.h>
index 68b1a67533cea1b4c54965af7991cd0cef224c17..4d1bfc848dd31b6face5540bca24b1871368eba4 100644 (file)
@@ -12,7 +12,7 @@
 struct kmem_cache *task_xstate_cachep = NULL;
 unsigned int xstate_size;
 
-#ifdef CONFIG_CC_STACKPROTECTOR
+#ifdef CONFIG_STACKPROTECTOR
 unsigned long __stack_chk_guard __read_mostly;
 EXPORT_SYMBOL(__stack_chk_guard);
 #endif
index 93522069cb155149535681e996c813cdcf7bb49e..27fddb56b3e1a1806cb0de99527edd4df4436f3e 100644 (file)
@@ -177,7 +177,7 @@ __switch_to(struct task_struct *prev, struct task_struct *next)
 {
        struct thread_struct *next_t = &next->thread;
 
-#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
+#if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_SMP)
        __stack_chk_guard = next->stack_canary;
 #endif
 
index 9a2b8877f1749a4ec067032c7c2002755f45e5d9..0f535debf8025df4cdd4d378f848c3a4049aaf4b 100644 (file)
@@ -178,7 +178,7 @@ config SMP
          Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
          Management" code will be disabled if you say Y here.
 
-         See also <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO
+         See also <file:Documentation/lockup-watchdogs.txt> and the SMP-HOWTO
          available at <http://www.tldp.org/docs.html#howto>.
 
          If you don't know what to do here, say N.
index 8aeb1aabe76e04ce694318e87ccd154f931c8d99..f396048a0d6808f7faddc7addbd6c461e3c835ad 100644 (file)
@@ -1620,7 +1620,7 @@ static void __init bootmem_init_nonnuma(void)
               (top_of_ram - total_ram) >> 20);
 
        init_node_masks_nonnuma();
-       memblock_set_node(0, (phys_addr_t)ULLONG_MAX, &memblock.memory, 0);
+       memblock_set_node(0, PHYS_ADDR_MAX, &memblock.memory, 0);
        allocate_node_data(0);
        node_set_online(0);
 }
index 3e7f228b22e17bf5e011402b9518cfdef41b697d..20da5a8ca9490ae469c12cef016edecb89542509 100644 (file)
@@ -80,7 +80,7 @@ config MAGIC_SYSRQ
          On UML, this is accomplished by sending a "sysrq" command with
          mconsole, followed by the letter for the requested command.
 
-         The keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
+         The keys are documented in <file:Documentation/admin-guide/sysrq.rst>. Don't say Y
          unless you really know what this hack does.
 
 config KERNEL_STACK_ORDER
index 627075e6d8751e0732151f85e55390d14b447324..50ee3bb5a63a9eb950d76baeba475bcf7f0700b8 100644 (file)
@@ -188,7 +188,7 @@ static int get_transport_options(struct arglist *def)
        if (strncmp(transport, TRANS_TAP, TRANS_TAP_LEN) == 0)
                return (vec_rx | VECTOR_BPF);
        if (strncmp(transport, TRANS_RAW, TRANS_RAW_LEN) == 0)
-               return (vec_rx | vec_tx);
+               return (vec_rx | vec_tx | VECTOR_QDISC_BYPASS);
        return (vec_rx | vec_tx);
 }
 
@@ -504,15 +504,19 @@ static struct vector_queue *create_queue(
 
        result = kmalloc(sizeof(struct vector_queue), GFP_KERNEL);
        if (result == NULL)
-               goto out_fail;
+               return NULL;
        result->max_depth = max_size;
        result->dev = vp->dev;
        result->mmsg_vector = kmalloc(
                (sizeof(struct mmsghdr) * max_size), GFP_KERNEL);
+       if (result->mmsg_vector == NULL)
+               goto out_mmsg_fail;
        result->skbuff_vector = kmalloc(
                (sizeof(void *) * max_size), GFP_KERNEL);
-       if (result->mmsg_vector == NULL || result->skbuff_vector == NULL)
-               goto out_fail;
+       if (result->skbuff_vector == NULL)
+               goto out_skb_fail;
+
+       /* further failures can be handled safely by destroy_queue*/
 
        mmsg_vector = result->mmsg_vector;
        for (i = 0; i < max_size; i++) {
@@ -563,6 +567,11 @@ static struct vector_queue *create_queue(
        result->head = 0;
        result->tail = 0;
        return result;
+out_skb_fail:
+       kfree(result->mmsg_vector);
+out_mmsg_fail:
+       kfree(result);
+       return NULL;
 out_fail:
        destroy_queue(result);
        return NULL;
@@ -1232,9 +1241,8 @@ static int vector_net_open(struct net_device *dev)
 
        if ((vp->options & VECTOR_QDISC_BYPASS) != 0) {
                if (!uml_raw_enable_qdisc_bypass(vp->fds->rx_fd))
-                       vp->options = vp->options | VECTOR_BPF;
+                       vp->options |= VECTOR_BPF;
        }
-
        if ((vp->options & VECTOR_BPF) != 0)
                vp->bpf = uml_vector_default_bpf(vp->fds->rx_fd, dev->dev_addr);
 
index b30d73ca29d08b8ff413c37275d8e65a05ac78e8..7adb4e6b658a1b86cc2d879caae17d6441402a8c 100644 (file)
        CON_INITCALL
   }
 
-  .uml.initcall.init : {
-       __uml_initcall_start = .;
-       *(.uml.initcall.init)
-       __uml_initcall_end = .;
-  }
-
   SECURITY_INIT
 
   .exitcall : {
index b3f5865a92c911b8ad82ff8ce1d4ec143d175296..c66de434a983b0a179b01597c13d0e9a049c6536 100644 (file)
@@ -64,14 +64,10 @@ struct uml_param {
         int (*setup_func)(char *, int *);
 };
 
-extern initcall_t __uml_initcall_start, __uml_initcall_end;
 extern initcall_t __uml_postsetup_start, __uml_postsetup_end;
 extern const char *__uml_help_start, *__uml_help_end;
 #endif
 
-#define __uml_initcall(fn)                                             \
-       static initcall_t __uml_initcall_##fn __uml_init_call = fn
-
 #define __uml_exitcall(fn)                                             \
        static exitcall_t __uml_exitcall_##fn __uml_exit_call = fn
 
@@ -108,7 +104,6 @@ extern struct uml_param __uml_setup_start, __uml_setup_end;
  */
 #define __uml_init_setup       __used __section(.uml.setup.init)
 #define __uml_setup_help       __used __section(.uml.help.init)
-#define __uml_init_call                __used __section(.uml.initcall.init)
 #define __uml_postsetup_call   __used __section(.uml.postsetup.init)
 #define __uml_exit_call                __used __section(.uml.exitcall.exit)
 
index 5f970ece5ac3cdb9af504b62b56762800748f7aa..f1fee2b9123942c117ac1d498027da2f33f004b9 100644 (file)
@@ -40,17 +40,6 @@ static void set_stklim(void)
        }
 }
 
-static __init void do_uml_initcalls(void)
-{
-       initcall_t *call;
-
-       call = &__uml_initcall_start;
-       while (call < &__uml_initcall_end) {
-               (*call)();
-               call++;
-       }
-}
-
 static void last_ditch_exit(int sig)
 {
        uml_cleanup();
@@ -151,7 +140,6 @@ int __init main(int argc, char **argv, char **envp)
        scan_elf_aux(envp);
 #endif
 
-       do_uml_initcalls();
        change_sig(SIGPIPE, 0);
        ret = linux_main(argc, argv);
 
index 1d9132b66039a2366d122400b733562c9eba68ec..1c8b9f13a9e1cb8f85c60d140cadc04cbd4f9575 100644 (file)
@@ -33,7 +33,7 @@
  *     Start addresses are inclusive and end addresses are exclusive;
  *     start addresses should be rounded down, end addresses up.
  *
- *     See Documentation/cachetlb.txt for more information.
+ *     See Documentation/core-api/cachetlb.rst for more information.
  *     Please note that the implementation of these, and the required
  *     effects are cache-type (VIVT/VIPT/PIPT) specific.
  *
index 455a670ab2390feec7dde6376882bb8cadd77d7f..f1dbb4ee19d781751ac22f233ec7dea5f9a66ed3 100644 (file)
@@ -130,7 +130,6 @@ config X86
        select HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD if X86_64
        select HAVE_ARCH_VMAP_STACK             if X86_64
        select HAVE_ARCH_WITHIN_STACK_FRAMES
-       select HAVE_CC_STACKPROTECTOR           if CC_HAS_SANE_STACKPROTECTOR
        select HAVE_CMPXCHG_DOUBLE
        select HAVE_CMPXCHG_LOCAL
        select HAVE_CONTEXT_TRACKING            if X86_64
@@ -182,6 +181,7 @@ config X86
        select HAVE_RCU_TABLE_FREE
        select HAVE_REGS_AND_STACK_ACCESS_API
        select HAVE_RELIABLE_STACKTRACE         if X86_64 && UNWINDER_FRAME_POINTER && STACK_VALIDATION
+       select HAVE_STACKPROTECTOR              if CC_HAS_SANE_STACKPROTECTOR
        select HAVE_STACK_VALIDATION            if X86_64
        select HAVE_RSEQ
        select HAVE_SYSCALL_TRACEPOINTS
@@ -327,7 +327,7 @@ config X86_64_SMP
 
 config X86_32_LAZY_GS
        def_bool y
-       depends on X86_32 && CC_STACKPROTECTOR_NONE
+       depends on X86_32 && !STACKPROTECTOR
 
 config ARCH_SUPPORTS_UPROBES
        def_bool y
index bef8e2b202a8c0a608fb3dad7e38fb58889ee88e..2582881d19ceeeb75a9a90588547914ccdefdbd0 100644 (file)
@@ -239,7 +239,7 @@ ENTRY(__switch_to_asm)
        movl    %esp, TASK_threadsp(%eax)
        movl    TASK_threadsp(%edx), %esp
 
-#ifdef CONFIG_CC_STACKPROTECTOR
+#ifdef CONFIG_STACKPROTECTOR
        movl    TASK_stack_canary(%edx), %ebx
        movl    %ebx, PER_CPU_VAR(stack_canary)+stack_canary_offset
 #endif
index 3166b967442966734b9db6e8fea541f501aa1e1e..73a522d53b5376b7eaa17cb3d0a7e7be317b02d1 100644 (file)
@@ -357,7 +357,7 @@ ENTRY(__switch_to_asm)
        movq    %rsp, TASK_threadsp(%rdi)
        movq    TASK_threadsp(%rsi), %rsp
 
-#ifdef CONFIG_CC_STACKPROTECTOR
+#ifdef CONFIG_STACKPROTECTOR
        movq    TASK_stack_canary(%rsi), %rbx
        movq    %rbx, PER_CPU_VAR(irq_stack_union)+stack_canary_offset
 #endif
index 7782cdbcd67d94e025b740e362f2a4e64e575887..82ed001e8909d69db9ab6827151534a921e2434d 100644 (file)
@@ -201,7 +201,7 @@ bool emulate_vsyscall(struct pt_regs *regs, unsigned long address)
 
        /*
         * Handle seccomp.  regs->ip must be the original value.
-        * See seccomp_send_sigsys and Documentation/prctl/seccomp_filter.txt.
+        * See seccomp_send_sigsys and Documentation/userspace-api/seccomp_filter.rst.
         *
         * We could optimize the seccomp disabled case, but performance
         * here doesn't matter.
index e28add6b791f29b70e342defe208c54d98d0d246..cfd29ee8c3da930eabc38a96d2aacbbbc1c965c3 100644 (file)
@@ -412,7 +412,7 @@ extern asmlinkage void ignore_sysret(void);
 void save_fsgs_for_kvm(void);
 #endif
 #else  /* X86_64 */
-#ifdef CONFIG_CC_STACKPROTECTOR
+#ifdef CONFIG_STACKPROTECTOR
 /*
  * Make sure stack canary segment base is cached-aligned:
  *   "For Intel Atom processors, avoid non zero segment base address
index 8f09012b92e779d7aabf4ad663b8eb10b2379c37..e293c122d0d54fbc802c1212edc9ed099be582f0 100644 (file)
 # define __KERNEL_PERCPU               0
 #endif
 
-#ifdef CONFIG_CC_STACKPROTECTOR
+#ifdef CONFIG_STACKPROTECTOR
 # define __KERNEL_STACK_CANARY         (GDT_ENTRY_STACK_CANARY*8)
 #else
 # define __KERNEL_STACK_CANARY         0
index 371b3a4af000764bcae483e8f1125765a35e76e8..8ec97a62c245175e87d96c0376eb962f51f8e91d 100644 (file)
@@ -34,7 +34,7 @@
 #ifndef _ASM_STACKPROTECTOR_H
 #define _ASM_STACKPROTECTOR_H 1
 
-#ifdef CONFIG_CC_STACKPROTECTOR
+#ifdef CONFIG_STACKPROTECTOR
 
 #include <asm/tsc.h>
 #include <asm/processor.h>
@@ -105,7 +105,7 @@ static inline void load_stack_canary_segment(void)
 #endif
 }
 
-#else  /* CC_STACKPROTECTOR */
+#else  /* STACKPROTECTOR */
 
 #define GDT_STACK_CANARY_INIT
 
@@ -121,5 +121,5 @@ static inline void load_stack_canary_segment(void)
 #endif
 }
 
-#endif /* CC_STACKPROTECTOR */
+#endif /* STACKPROTECTOR */
 #endif /* _ASM_STACKPROTECTOR_H */
index 76417a9aab73c3f7e3376261eb9ec592b16adf3b..dcb008c320fe05c2f236993815f18f20ab6e9d5d 100644 (file)
@@ -32,7 +32,7 @@
 void common(void) {
        BLANK();
        OFFSET(TASK_threadsp, task_struct, thread.sp);
-#ifdef CONFIG_CC_STACKPROTECTOR
+#ifdef CONFIG_STACKPROTECTOR
        OFFSET(TASK_stack_canary, task_struct, stack_canary);
 #endif
 
index f91ba53e06c8b90f9d5557a2713896a1a50100f0..a4a3be399f4b27ab5adf1df10c0a8ee4b2738e13 100644 (file)
@@ -50,7 +50,7 @@ void foo(void)
        DEFINE(TSS_sysenter_sp0, offsetof(struct cpu_entry_area, tss.x86_tss.sp0) -
               offsetofend(struct cpu_entry_area, entry_stack_page.stack));
 
-#ifdef CONFIG_CC_STACKPROTECTOR
+#ifdef CONFIG_STACKPROTECTOR
        BLANK();
        OFFSET(stack_canary_offset, stack_canary, canary);
 #endif
index bf51e51d808dd8914abd3b4bca69b37ce3ec023b..b2dcd161f5149492e8a24f06d7074d527308528c 100644 (file)
@@ -69,7 +69,7 @@ int main(void)
        OFFSET(TSS_sp1, tss_struct, x86_tss.sp1);
        BLANK();
 
-#ifdef CONFIG_CC_STACKPROTECTOR
+#ifdef CONFIG_STACKPROTECTOR
        DEFINE(stack_canary_offset, offsetof(union irq_stack_union, stack_canary));
        BLANK();
 #endif
index 910b47ee8078081e615f733440b61dd1df79dc78..0df7151cfef42cb908c9d76f0b4e78db1620f615 100644 (file)
@@ -1599,7 +1599,7 @@ DEFINE_PER_CPU(unsigned long, cpu_current_top_of_stack) =
        (unsigned long)&init_thread_union + THREAD_SIZE;
 EXPORT_PER_CPU_SYMBOL(cpu_current_top_of_stack);
 
-#ifdef CONFIG_CC_STACKPROTECTOR
+#ifdef CONFIG_STACKPROTECTOR
 DEFINE_PER_CPU_ALIGNED(struct stack_canary, stack_canary);
 #endif
 
index b59e4fb40fd9986c0cc6b629b4c7a3a18a6d23b4..abe6df15a8fbb798bf9cb8bfec5252494a943e63 100644 (file)
@@ -375,7 +375,7 @@ ENDPROC(startup_32_smp)
  */
 __INIT
 setup_once:
-#ifdef CONFIG_CC_STACKPROTECTOR
+#ifdef CONFIG_STACKPROTECTOR
        /*
         * Configure the stack canary. The linker can't handle this by
         * relocation.  Manually set base address in stack canary
index d0dd35d582da4c7eb7887d9063a6139ad4d1b405..559a12b6184de38c67ef4f2001963600f41f8753 100644 (file)
@@ -4429,16 +4429,14 @@ static int alloc_loaded_vmcs(struct loaded_vmcs *loaded_vmcs)
                        goto out_vmcs;
                memset(loaded_vmcs->msr_bitmap, 0xff, PAGE_SIZE);
 
-#if IS_ENABLED(CONFIG_HYPERV)
-               if (static_branch_unlikely(&enable_evmcs) &&
+               if (IS_ENABLED(CONFIG_HYPERV) &&
+                   static_branch_unlikely(&enable_evmcs) &&
                    (ms_hyperv.nested_features & HV_X64_NESTED_MSR_BITMAP)) {
                        struct hv_enlightened_vmcs *evmcs =
                                (struct hv_enlightened_vmcs *)loaded_vmcs->vmcs;
 
                        evmcs->hv_enlightenments_control.msr_bitmap = 1;
                }
-#endif
-
        }
        return 0;
 
index 6bcecc325e7ef9654e898982cb5ddb2064fa736b..0046aa70205aa2dfbc0577065250be717ca25b4e 100644 (file)
@@ -8567,7 +8567,7 @@ int kvm_arch_hardware_setup(void)
                /*
                 * Make sure the user can only configure tsc_khz values that
                 * fit into a signed integer.
-                * A min value is not calculated needed because it will always
+                * A min value is not calculated because it will always
                 * be 1 on all machines.
                 */
                u64 max = min(0x7fffffffULL,
index fec82b577c183f516b4c3c416d94127f9ccd26ad..cee58a972cb20ff948e6384df5d9fc25f3e47ab7 100644 (file)
@@ -706,7 +706,9 @@ void __init init_mem_mapping(void)
  */
 int devmem_is_allowed(unsigned long pagenr)
 {
-       if (page_is_ram(pagenr)) {
+       if (region_intersects(PFN_PHYS(pagenr), PAGE_SIZE,
+                               IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE)
+                       != REGION_DISJOINT) {
                /*
                 * For disallowed memory regions in the low 1MB range,
                 * request that the page be shown as all zeros.
index c893c6a3d7079cf1210ad9562644ec8eb240d1d7..979e0a02cbe1a12d67fad130592a6e68c98925c5 100644 (file)
@@ -692,7 +692,7 @@ void __init initmem_init(void)
        high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1) + 1;
 #endif
 
-       memblock_set_node(0, (phys_addr_t)ULLONG_MAX, &memblock.memory, 0);
+       memblock_set_node(0, PHYS_ADDR_MAX, &memblock.memory, 0);
        sparse_memory_present_with_active_regions(0);
 
 #ifdef CONFIG_FLATMEM
index 17383f9677faf25819aabb549b24cf0269f653d9..045f492d5f68260a581f44c210aa3753dc4bc225 100644 (file)
@@ -742,7 +742,7 @@ kernel_physical_mapping_init(unsigned long paddr_start,
 #ifndef CONFIG_NUMA
 void __init initmem_init(void)
 {
-       memblock_set_node(0, (phys_addr_t)ULLONG_MAX, &memblock.memory, 0);
+       memblock_set_node(0, PHYS_ADDR_MAX, &memblock.memory, 0);
 }
 #endif
 
index 17df332269b2b5a296ec4906dff660f023933c42..d575e8701955a3f46703162332a549946316f02d 100644 (file)
@@ -17,7 +17,6 @@ config XTENSA
        select GENERIC_SCHED_CLOCK
        select GENERIC_STRNCPY_FROM_USER if KASAN
        select HAVE_ARCH_KASAN if MMU
-       select HAVE_CC_STACKPROTECTOR
        select HAVE_DEBUG_KMEMLEAK
        select HAVE_DMA_CONTIGUOUS
        select HAVE_EXIT_THREAD
@@ -28,6 +27,7 @@ config XTENSA
        select HAVE_MEMBLOCK
        select HAVE_OPROFILE
        select HAVE_PERF_EVENTS
+       select HAVE_STACKPROTECTOR
        select IRQ_DOMAIN
        select MODULES_USE_ELF_RELA
        select NO_BOOTMEM
index 397d6a1a4224fb66b70dfc86cee06353e07fbc1b..a0d50be5a8cb192562537e1ef36a6dfd73f0011a 100644 (file)
@@ -88,7 +88,7 @@ static inline void __invalidate_icache_page_alias(unsigned long virt,
  *
  * Pages can get remapped. Because this might change the 'color' of that page,
  * we have to flush the cache before the PTE is changed.
- * (see also Documentation/cachetlb.txt)
+ * (see also Documentation/core-api/cachetlb.rst)
  */
 
 #if defined(CONFIG_MMU) && \
@@ -152,7 +152,7 @@ void local_flush_cache_page(struct vm_area_struct *vma,
                __invalidate_icache_range(start,(end) - (start));       \
        } while (0)
 
-/* This is not required, see Documentation/cachetlb.txt */
+/* This is not required, see Documentation/core-api/cachetlb.rst */
 #define        flush_icache_page(vma,page)                     do { } while (0)
 
 #define flush_dcache_mmap_lock(mapping)                        do { } while (0)
index 022cf918ec208db6e51627c786ec7f80f345c178..67904f55f1884f52893b3a99b1be785a48dc69da 100644 (file)
@@ -76,7 +76,7 @@ int main(void)
        DEFINE(TASK_PID, offsetof (struct task_struct, pid));
        DEFINE(TASK_THREAD, offsetof (struct task_struct, thread));
        DEFINE(TASK_THREAD_INFO, offsetof (struct task_struct, stack));
-#ifdef CONFIG_CC_STACKPROTECTOR
+#ifdef CONFIG_STACKPROTECTOR
        DEFINE(TASK_STACK_CANARY, offsetof(struct task_struct, stack_canary));
 #endif
        DEFINE(TASK_STRUCT_SIZE, sizeof (struct task_struct));
index 5caff0744f3cb7e75855a607028822a4850d7dbe..9cbc380e95727f2f0394f7cf778f412d086e05e3 100644 (file)
@@ -1971,7 +1971,7 @@ ENTRY(_switch_to)
        s32i    a1, a2, THREAD_SP       # save stack pointer
 #endif
 
-#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
+#if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_SMP)
        movi    a6, __stack_chk_guard
        l32i    a8, a3, TASK_STACK_CANARY
        s32i    a8, a6, 0
index 8dd0593fb2c4264e6f752589227f4d10aa4bcebe..483dcfb6e681d7d483ef8ebfb948d91b7ee8f1fd 100644 (file)
@@ -58,7 +58,7 @@ void (*pm_power_off)(void) = NULL;
 EXPORT_SYMBOL(pm_power_off);
 
 
-#ifdef CONFIG_CC_STACKPROTECTOR
+#ifdef CONFIG_STACKPROTECTOR
 #include <linux/stackprotector.h>
 unsigned long __stack_chk_guard __read_mostly;
 EXPORT_SYMBOL(__stack_chk_guard);
index 28ec55752b68e89bd1babc0b0c6eb4b3e4576014..eb50fd4977c2f5b5de3ef1a3c4ee597d1689936a 100644 (file)
@@ -114,7 +114,7 @@ config BLK_DEV_THROTTLING
        one needs to mount and use blkio cgroup controller for creating
        cgroups and specifying per device IO rate policies.
 
-       See Documentation/cgroups/blkio-controller.txt for more information.
+       See Documentation/cgroup-v1/blkio-controller.txt for more information.
 
 config BLK_DEV_THROTTLING_LOW
        bool "Block throttling .low limit interface support (EXPERIMENTAL)"
index 70356a2a11ab12a059654bdf8af0a3f2c0eb3b41..09b2ee6694fb16858a104b7021b986aff603a91a 100644 (file)
@@ -311,35 +311,6 @@ void blk_mq_tagset_busy_iter(struct blk_mq_tag_set *tagset,
 }
 EXPORT_SYMBOL(blk_mq_tagset_busy_iter);
 
-int blk_mq_tagset_iter(struct blk_mq_tag_set *set, void *data,
-                        int (fn)(void *, struct request *))
-{
-       int i, j, ret = 0;
-
-       if (WARN_ON_ONCE(!fn))
-               goto out;
-
-       for (i = 0; i < set->nr_hw_queues; i++) {
-               struct blk_mq_tags *tags = set->tags[i];
-
-               if (!tags)
-                       continue;
-
-               for (j = 0; j < tags->nr_tags; j++) {
-                       if (!tags->static_rqs[j])
-                               continue;
-
-                       ret = fn(data, tags->static_rqs[j]);
-                       if (ret)
-                               goto out;
-               }
-       }
-
-out:
-       return ret;
-}
-EXPORT_SYMBOL_GPL(blk_mq_tagset_iter);
-
 void blk_mq_queue_tag_busy_iter(struct request_queue *q, busy_iter_fn *fn,
                void *priv)
 {
index e9da5e6a8526f38bb6b3e581d7661eda4c520a38..70c65bb6c0131c84130fae44808acb51cf427ace 100644 (file)
@@ -671,6 +671,7 @@ static void __blk_mq_requeue_request(struct request *rq)
 
        if (blk_mq_request_started(rq)) {
                WRITE_ONCE(rq->state, MQ_RQ_IDLE);
+               rq->rq_flags &= ~RQF_TIMED_OUT;
                if (q->dma_drain_size && blk_rq_bytes(rq))
                        rq->nr_phys_segments--;
        }
@@ -770,6 +771,7 @@ EXPORT_SYMBOL(blk_mq_tag_to_rq);
 
 static void blk_mq_rq_timed_out(struct request *req, bool reserved)
 {
+       req->rq_flags |= RQF_TIMED_OUT;
        if (req->q->mq_ops->timeout) {
                enum blk_eh_timer_return ret;
 
@@ -779,6 +781,7 @@ static void blk_mq_rq_timed_out(struct request *req, bool reserved)
                WARN_ON_ONCE(ret != BLK_EH_RESET_TIMER);
        }
 
+       req->rq_flags &= ~RQF_TIMED_OUT;
        blk_add_timer(req);
 }
 
@@ -788,6 +791,8 @@ static bool blk_mq_req_expired(struct request *rq, unsigned long *next)
 
        if (blk_mq_rq_state(rq) != MQ_RQ_IN_FLIGHT)
                return false;
+       if (rq->rq_flags & RQF_TIMED_OUT)
+               return false;
 
        deadline = blk_rq_deadline(rq);
        if (time_after_eq(jiffies, deadline))
@@ -2349,7 +2354,6 @@ static void blk_mq_del_queue_tag_set(struct request_queue *q)
 
        mutex_lock(&set->tag_list_lock);
        list_del_rcu(&q->tag_set_list);
-       INIT_LIST_HEAD(&q->tag_set_list);
        if (list_is_singular(&set->tag_list)) {
                /* just transitioned to unshared */
                set->flags &= ~BLK_MQ_F_TAG_SHARED;
@@ -2357,8 +2361,8 @@ static void blk_mq_del_queue_tag_set(struct request_queue *q)
                blk_mq_update_tag_set_depth(set, false);
        }
        mutex_unlock(&set->tag_list_lock);
-
        synchronize_rcu();
+       INIT_LIST_HEAD(&q->tag_set_list);
 }
 
 static void blk_mq_add_queue_tag_set(struct blk_mq_tag_set *set,
index 24b20d86bcbcb3f160498fdf3eb5409f9a8730f4..fbc153aef166d7faa27b65f41d0870ca844d9aad 100644 (file)
@@ -188,7 +188,6 @@ int blk_queue_init_tags(struct request_queue *q, int depth,
         */
        q->queue_tags = tags;
        queue_flag_set_unlocked(QUEUE_FLAG_QUEUED, q);
-       INIT_LIST_HEAD(&q->tag_busy_list);
        return 0;
 }
 EXPORT_SYMBOL(blk_queue_init_tags);
@@ -374,27 +373,6 @@ int blk_queue_start_tag(struct request_queue *q, struct request *rq)
        rq->tag = tag;
        bqt->tag_index[tag] = rq;
        blk_start_request(rq);
-       list_add(&rq->queuelist, &q->tag_busy_list);
        return 0;
 }
 EXPORT_SYMBOL(blk_queue_start_tag);
-
-/**
- * blk_queue_invalidate_tags - invalidate all pending tags
- * @q:  the request queue for the device
- *
- *  Description:
- *   Hardware conditions may dictate a need to stop all pending requests.
- *   In this case, we will safely clear the block side of the tag queue and
- *   readd all requests to the request queue in the right order.
- **/
-void blk_queue_invalidate_tags(struct request_queue *q)
-{
-       struct list_head *tmp, *n;
-
-       lockdep_assert_held(q->queue_lock);
-
-       list_for_each_safe(tmp, n, &q->tag_busy_list)
-               blk_requeue_request(q, list_entry_rq(tmp));
-}
-EXPORT_SYMBOL(blk_queue_invalidate_tags);
index 132e657e2d913ca3fcff87c594de0957d8b6bd97..66602c48995643dcff921e6f10bba8cd203d3c5c 100644 (file)
@@ -693,6 +693,8 @@ static struct bsg_device *bsg_add_device(struct inode *inode,
        struct bsg_device *bd;
        unsigned char buf[32];
 
+       lockdep_assert_held(&bsg_mutex);
+
        if (!blk_get_queue(rq))
                return ERR_PTR(-ENXIO);
 
@@ -707,14 +709,12 @@ static struct bsg_device *bsg_add_device(struct inode *inode,
        bsg_set_block(bd, file);
 
        atomic_set(&bd->ref_count, 1);
-       mutex_lock(&bsg_mutex);
        hlist_add_head(&bd->dev_list, bsg_dev_idx_hash(iminor(inode)));
 
        strncpy(bd->name, dev_name(rq->bsg_dev.class_dev), sizeof(bd->name) - 1);
        bsg_dbg(bd, "bound to <%s>, max queue %d\n",
                format_dev_t(buf, inode->i_rdev), bd->max_queue);
 
-       mutex_unlock(&bsg_mutex);
        return bd;
 }
 
@@ -722,7 +722,7 @@ static struct bsg_device *__bsg_get_device(int minor, struct request_queue *q)
 {
        struct bsg_device *bd;
 
-       mutex_lock(&bsg_mutex);
+       lockdep_assert_held(&bsg_mutex);
 
        hlist_for_each_entry(bd, bsg_dev_idx_hash(minor), dev_list) {
                if (bd->queue == q) {
@@ -732,7 +732,6 @@ static struct bsg_device *__bsg_get_device(int minor, struct request_queue *q)
        }
        bd = NULL;
 found:
-       mutex_unlock(&bsg_mutex);
        return bd;
 }
 
@@ -746,17 +745,18 @@ static struct bsg_device *bsg_get_device(struct inode *inode, struct file *file)
         */
        mutex_lock(&bsg_mutex);
        bcd = idr_find(&bsg_minor_idr, iminor(inode));
-       mutex_unlock(&bsg_mutex);
 
-       if (!bcd)
-               return ERR_PTR(-ENODEV);
+       if (!bcd) {
+               bd = ERR_PTR(-ENODEV);
+               goto out_unlock;
+       }
 
        bd = __bsg_get_device(iminor(inode), bcd->queue);
-       if (bd)
-               return bd;
-
-       bd = bsg_add_device(inode, bcd->queue, file);
+       if (!bd)
+               bd = bsg_add_device(inode, bcd->queue, file);
 
+out_unlock:
+       mutex_unlock(&bsg_mutex);
        return bd;
 }
 
index 5f7663df6e8e306fb7181e7fb94c11a88a49c828..c94e93d8bccf038f4684c4cce93d558d9e7269ff 100644 (file)
@@ -13,7 +13,7 @@ config MODULE_SIG_KEY
 
          If this option is unchanged from its default "certs/signing_key.pem",
          then the kernel will automatically generate the private key and
-         certificate as described in Documentation/module-signing.txt
+         certificate as described in Documentation/admin-guide/module-signing.rst
 
 config SYSTEM_TRUSTED_KEYRING
        bool "Provide system-wide ring of trusted keys"
index 39aecad286fe482ff3f44fe08b286c2edbf3553b..26539e9a8bda41c37a664490e037f2365da7f15c 100644 (file)
@@ -1,6 +1,6 @@
 /* Asymmetric public-key cryptography key type
  *
- * See Documentation/security/asymmetric-keys.txt
+ * See Documentation/crypto/asymmetric-keys.txt
  *
  * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
index 11b7ba1709041864868a6ca2b05680a20b5fb3f9..28198314bc39f4f4a27da38565619f6e262a7fd4 100644 (file)
@@ -1,6 +1,6 @@
 /* Signature verification with an asymmetric key
  *
- * See Documentation/security/asymmetric-keys.txt
+ * See Documentation/crypto/asymmetric-keys.txt
  *
  * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
index cb6ac5c65c2e4c97f4cc9432d8d701b9e3b3f0da..38a286975c31e152206b3e55b28473a2763a717a 100644 (file)
@@ -233,11 +233,13 @@ static const struct lpss_device_desc lpt_sdio_dev_desc = {
 
 static const struct lpss_device_desc byt_pwm_dev_desc = {
        .flags = LPSS_SAVE_CTX,
+       .prv_offset = 0x800,
        .setup = byt_pwm_setup,
 };
 
 static const struct lpss_device_desc bsw_pwm_dev_desc = {
        .flags = LPSS_SAVE_CTX | LPSS_NO_D3_DELAY,
+       .prv_offset = 0x800,
        .setup = bsw_pwm_setup,
 };
 
index af354047ac4b67dc3be6eb55689387cc4219de4d..fa0729c1e776e21834f02caa2d42ac7867c5ad36 100644 (file)
@@ -2339,6 +2339,7 @@ static bool is_zero_bvecs(struct bio_vec *bvecs, u32 bytes)
 static int rbd_obj_issue_copyup(struct rbd_obj_request *obj_req, u32 bytes)
 {
        unsigned int num_osd_ops = obj_req->osd_req->r_num_ops;
+       int ret;
 
        dout("%s obj_req %p bytes %u\n", __func__, obj_req, bytes);
        rbd_assert(obj_req->osd_req->r_ops[0].op == CEPH_OSD_OP_STAT);
@@ -2353,6 +2354,11 @@ static int rbd_obj_issue_copyup(struct rbd_obj_request *obj_req, u32 bytes)
        if (!obj_req->osd_req)
                return -ENOMEM;
 
+       ret = osd_req_op_cls_init(obj_req->osd_req, 0, CEPH_OSD_OP_CALL, "rbd",
+                                 "copyup");
+       if (ret)
+               return ret;
+
        /*
         * Only send non-zero copyup data to save some I/O and network
         * bandwidth -- zero copyup data is equivalent to the object not
@@ -2362,9 +2368,6 @@ static int rbd_obj_issue_copyup(struct rbd_obj_request *obj_req, u32 bytes)
                dout("%s obj_req %p detected zeroes\n", __func__, obj_req);
                bytes = 0;
        }
-
-       osd_req_op_cls_init(obj_req->osd_req, 0, CEPH_OSD_OP_CALL, "rbd",
-                           "copyup");
        osd_req_op_cls_request_data_bvecs(obj_req->osd_req, 0,
                                          obj_req->copyup_bvecs,
                                          obj_req->copyup_bvec_count,
@@ -3397,7 +3400,6 @@ static void cancel_tasks_sync(struct rbd_device *rbd_dev)
 {
        dout("%s rbd_dev %p\n", __func__, rbd_dev);
 
-       cancel_delayed_work_sync(&rbd_dev->watch_dwork);
        cancel_work_sync(&rbd_dev->acquired_lock_work);
        cancel_work_sync(&rbd_dev->released_lock_work);
        cancel_delayed_work_sync(&rbd_dev->lock_dwork);
@@ -3415,6 +3417,7 @@ static void rbd_unregister_watch(struct rbd_device *rbd_dev)
        rbd_dev->watch_state = RBD_WATCH_STATE_UNREGISTERED;
        mutex_unlock(&rbd_dev->watch_mutex);
 
+       cancel_delayed_work_sync(&rbd_dev->watch_dwork);
        ceph_osdc_flush_notifies(&rbd_dev->rbd_client->client->osdc);
 }
 
index 410c30c42120ab9645838aa37768cbdc65e43104..212f447938ae95a695a7980f26263f017f72ee47 100644 (file)
@@ -81,7 +81,7 @@ config PRINTER
          corresponding drivers into the kernel.
 
          To compile this driver as a module, choose M here and read
-         <file:Documentation/parport.txt>.  The module will be called lp.
+         <file:Documentation/admin-guide/parport.rst>.  The module will be called lp.
 
          If you have several parallel ports, you can specify which ports to
          use with the "lp" kernel command line option.  (Try "man bootparam"
index a24a6afb50b6bd63531d39f98e503df052ea78b0..9760b526ca31da90c4c288ac096cb0fee7d16cbf 100644 (file)
@@ -6,7 +6,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
- * Standard functionality for the common clock API.  See Documentation/clk.txt
+ * Standard functionality for the common clock API.  See Documentation/driver-api/clk.rst
  */
 
 #include <linux/clk.h>
@@ -2747,7 +2747,7 @@ static int __clk_core_init(struct clk_core *core)
                goto out;
        }
 
-       /* check that clk_ops are sane.  See Documentation/clk.txt */
+       /* check that clk_ops are sane.  See Documentation/driver-api/clk.rst */
        if (core->ops->set_rate &&
            !((core->ops->round_rate || core->ops->determine_rate) &&
              core->ops->recalc_rate)) {
index 542192376ebffd1abf0401f2b3d809d23696f703..502bcbb61b047a5331b56d7bdfafaeee2e3cb61b 100644 (file)
@@ -194,7 +194,7 @@ struct ingenic_cgu {
 
 /**
  * struct ingenic_clk - private data for a clock
- * @hw: see Documentation/clk.txt
+ * @hw: see Documentation/driver-api/clk.rst
  * @cgu: a pointer to the CGU data
  * @idx: the index of this clock in cgu->clock_info
  */
index b451354735d3d6b80b003f8e6c3ea098d37041e0..08ba8473a284845ecbffab228dded0d3b3b4aaf1 100644 (file)
@@ -38,7 +38,7 @@
  * Each device has a channels list, which runs unlocked but is never modified
  * once the device is registered, it's just setup by the driver.
  *
- * See Documentation/dmaengine.txt for more details
+ * See Documentation/driver-api/dmaengine for more details
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 951b6c79f166a7d2b4ec14e12096559df9aed684..624a11cb07e23b775d097d930997cc6ebd171b06 100644 (file)
@@ -47,6 +47,7 @@ DEFINE_DMI_ATTR_WITH_SHOW(product_name,               0444, DMI_PRODUCT_NAME);
 DEFINE_DMI_ATTR_WITH_SHOW(product_version,     0444, DMI_PRODUCT_VERSION);
 DEFINE_DMI_ATTR_WITH_SHOW(product_serial,      0400, DMI_PRODUCT_SERIAL);
 DEFINE_DMI_ATTR_WITH_SHOW(product_uuid,                0400, DMI_PRODUCT_UUID);
+DEFINE_DMI_ATTR_WITH_SHOW(product_sku,         0444, DMI_PRODUCT_SKU);
 DEFINE_DMI_ATTR_WITH_SHOW(product_family,      0444, DMI_PRODUCT_FAMILY);
 DEFINE_DMI_ATTR_WITH_SHOW(board_vendor,                0444, DMI_BOARD_VENDOR);
 DEFINE_DMI_ATTR_WITH_SHOW(board_name,          0444, DMI_BOARD_NAME);
@@ -193,6 +194,7 @@ static void __init dmi_id_init_attr_table(void)
        ADD_DMI_ATTR(product_serial,    DMI_PRODUCT_SERIAL);
        ADD_DMI_ATTR(product_uuid,      DMI_PRODUCT_UUID);
        ADD_DMI_ATTR(product_family,    DMI_PRODUCT_FAMILY);
+       ADD_DMI_ATTR(product_sku,       DMI_PRODUCT_SKU);
        ADD_DMI_ATTR(board_vendor,      DMI_BOARD_VENDOR);
        ADD_DMI_ATTR(board_name,        DMI_BOARD_NAME);
        ADD_DMI_ATTR(board_version,     DMI_BOARD_VERSION);
index 54e66adef2525179e49ecfe9fc04e253ecc18e51..f2483548cde92d692f748d6a9c7da0cbf98274a3 100644 (file)
@@ -447,6 +447,7 @@ static void __init dmi_decode(const struct dmi_header *dm, void *dummy)
                dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
                dmi_save_ident(dm, DMI_PRODUCT_SERIAL, 7);
                dmi_save_uuid(dm, DMI_PRODUCT_UUID, 8);
+               dmi_save_ident(dm, DMI_PRODUCT_SKU, 25);
                dmi_save_ident(dm, DMI_PRODUCT_FAMILY, 26);
                break;
        case 2:         /* Base Board Information */
index 80d1a885def5c2dd8bd15591bcc7c62d9b2e3b8c..b5214c143feedac6f0bd81f4abbe4e60554648dc 100644 (file)
@@ -193,7 +193,7 @@ static __init void reserve_regions(void)
         * uses its own memory map instead.
         */
        memblock_dump_all();
-       memblock_remove(0, (phys_addr_t)ULLONG_MAX);
+       memblock_remove(0, PHYS_ADDR_MAX);
 
        for_each_efi_memory_desc(md) {
                paddr = md->phys_addr;
index 5a0fa939d70f961a998317cb88c8ee4705e1065f..cfe87b465819f8ef42d0da6a60ca2a2294433ab7 100644 (file)
@@ -28,10 +28,9 @@ static int efi_pstore_close(struct pstore_info *psi)
        return 0;
 }
 
-static inline u64 generic_id(unsigned long timestamp,
-                            unsigned int part, int count)
+static inline u64 generic_id(u64 timestamp, unsigned int part, int count)
 {
-       return ((u64) timestamp * 100 + part) * 1000 + count;
+       return (timestamp * 100 + part) * 1000 + count;
 }
 
 static int efi_pstore_read_func(struct efivar_entry *entry,
@@ -42,7 +41,8 @@ static int efi_pstore_read_func(struct efivar_entry *entry,
        int i;
        int cnt;
        unsigned int part;
-       unsigned long time, size;
+       unsigned long size;
+       u64 time;
 
        if (efi_guidcmp(entry->var.VendorGuid, vendor))
                return 0;
@@ -50,7 +50,7 @@ static int efi_pstore_read_func(struct efivar_entry *entry,
        for (i = 0; i < DUMP_NAME_LEN; i++)
                name[i] = entry->var.VariableName[i];
 
-       if (sscanf(name, "dump-type%u-%u-%d-%lu-%c",
+       if (sscanf(name, "dump-type%u-%u-%d-%llu-%c",
                   &record->type, &part, &cnt, &time, &data_type) == 5) {
                record->id = generic_id(time, part, cnt);
                record->part = part;
@@ -62,7 +62,7 @@ static int efi_pstore_read_func(struct efivar_entry *entry,
                else
                        record->compressed = false;
                record->ecc_notice_size = 0;
-       } else if (sscanf(name, "dump-type%u-%u-%d-%lu",
+       } else if (sscanf(name, "dump-type%u-%u-%d-%llu",
                   &record->type, &part, &cnt, &time) == 4) {
                record->id = generic_id(time, part, cnt);
                record->part = part;
@@ -71,7 +71,7 @@ static int efi_pstore_read_func(struct efivar_entry *entry,
                record->time.tv_nsec = 0;
                record->compressed = false;
                record->ecc_notice_size = 0;
-       } else if (sscanf(name, "dump-type%u-%u-%lu",
+       } else if (sscanf(name, "dump-type%u-%u-%llu",
                          &record->type, &part, &time) == 3) {
                /*
                 * Check if an old format,
@@ -250,9 +250,10 @@ static int efi_pstore_write(struct pstore_record *record)
        /* Since we copy the entire length of name, make sure it is wiped. */
        memset(name, 0, sizeof(name));
 
-       snprintf(name, sizeof(name), "dump-type%u-%u-%d-%lu-%c",
+       snprintf(name, sizeof(name), "dump-type%u-%u-%d-%lld-%c",
                 record->type, record->part, record->count,
-                record->time.tv_sec, record->compressed ? 'C' : 'D');
+                (long long)record->time.tv_sec,
+                record->compressed ? 'C' : 'D');
 
        for (i = 0; i < DUMP_NAME_LEN; i++)
                efi_name[i] = name[i];
@@ -327,15 +328,15 @@ static int efi_pstore_erase(struct pstore_record *record)
        char name[DUMP_NAME_LEN];
        int ret;
 
-       snprintf(name, sizeof(name), "dump-type%u-%u-%d-%lu",
+       snprintf(name, sizeof(name), "dump-type%u-%u-%d-%lld",
                 record->type, record->part, record->count,
-                record->time.tv_sec);
+                (long long)record->time.tv_sec);
        ret = efi_pstore_erase_name(name);
        if (ret != -ENOENT)
                return ret;
 
-       snprintf(name, sizeof(name), "dump-type%u-%u-%lu",
-               record->type, record->part, record->time.tv_sec);
+       snprintf(name, sizeof(name), "dump-type%u-%u-%lld",
+               record->type, record->part, (long long)record->time.tv_sec);
        ret = efi_pstore_erase_name(name);
 
        return ret;
index 8f6f45567bfa16d28602f39ed6f1f922e7e29f7f..305143fcc1ceed0d1231efa742864de460b608d0 100644 (file)
@@ -342,15 +342,12 @@ void get_local_mem_info(struct kgd_dev *kgd,
                        mem_info->local_mem_size_public,
                        mem_info->local_mem_size_private);
 
-       if (amdgpu_emu_mode == 1) {
-               mem_info->mem_clk_max = 100;
-               return;
-       }
-
        if (amdgpu_sriov_vf(adev))
                mem_info->mem_clk_max = adev->clock.default_mclk / 100;
-       else
+       else if (adev->powerplay.pp_funcs)
                mem_info->mem_clk_max = amdgpu_dpm_get_mclk(adev, false) / 100;
+       else
+               mem_info->mem_clk_max = 100;
 }
 
 uint64_t get_gpu_clock_counter(struct kgd_dev *kgd)
@@ -367,13 +364,12 @@ uint32_t get_max_engine_clock_in_mhz(struct kgd_dev *kgd)
        struct amdgpu_device *adev = (struct amdgpu_device *)kgd;
 
        /* the sclk is in quantas of 10kHz */
-       if (amdgpu_emu_mode == 1)
-               return 100;
-
        if (amdgpu_sriov_vf(adev))
                return adev->clock.default_sclk / 100;
-
-       return amdgpu_dpm_get_sclk(adev, false) / 100;
+       else if (adev->powerplay.pp_funcs)
+               return amdgpu_dpm_get_sclk(adev, false) / 100;
+       else
+               return 100;
 }
 
 void get_cu_info(struct kgd_dev *kgd, struct kfd_cu_info *cu_info)
index 1bcb2b2473357809e161bb081ce9a362729cd56d..daa06e7c5bb73e2d4073fad2177bf50eee0be006 100644 (file)
@@ -569,7 +569,6 @@ static const struct amdgpu_px_quirk amdgpu_px_quirk_list[] = {
        { 0x1002, 0x6900, 0x1002, 0x0124, AMDGPU_PX_QUIRK_FORCE_ATPX },
        { 0x1002, 0x6900, 0x1028, 0x0812, AMDGPU_PX_QUIRK_FORCE_ATPX },
        { 0x1002, 0x6900, 0x1028, 0x0813, AMDGPU_PX_QUIRK_FORCE_ATPX },
-       { 0x1002, 0x67DF, 0x1028, 0x0774, AMDGPU_PX_QUIRK_FORCE_ATPX },
        { 0, 0, 0, 0, 0 },
 };
 
index 9c1d491d742e095c24b9cff843cb9830c3d67753..82312a7bc6ad5b5a01e232b350f23ac889f47ed7 100644 (file)
@@ -522,6 +522,9 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
        struct amdgpu_bo_list_entry *e;
        struct list_head duplicates;
        unsigned i, tries = 10;
+       struct amdgpu_bo *gds;
+       struct amdgpu_bo *gws;
+       struct amdgpu_bo *oa;
        int r;
 
        INIT_LIST_HEAD(&p->validated);
@@ -652,31 +655,36 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
 
        amdgpu_cs_report_moved_bytes(p->adev, p->bytes_moved,
                                     p->bytes_moved_vis);
+
        if (p->bo_list) {
-               struct amdgpu_bo *gds = p->bo_list->gds_obj;
-               struct amdgpu_bo *gws = p->bo_list->gws_obj;
-               struct amdgpu_bo *oa = p->bo_list->oa_obj;
                struct amdgpu_vm *vm = &fpriv->vm;
                unsigned i;
 
+               gds = p->bo_list->gds_obj;
+               gws = p->bo_list->gws_obj;
+               oa = p->bo_list->oa_obj;
                for (i = 0; i < p->bo_list->num_entries; i++) {
                        struct amdgpu_bo *bo = p->bo_list->array[i].robj;
 
                        p->bo_list->array[i].bo_va = amdgpu_vm_bo_find(vm, bo);
                }
+       } else {
+               gds = p->adev->gds.gds_gfx_bo;
+               gws = p->adev->gds.gws_gfx_bo;
+               oa = p->adev->gds.oa_gfx_bo;
+       }
 
-               if (gds) {
-                       p->job->gds_base = amdgpu_bo_gpu_offset(gds);
-                       p->job->gds_size = amdgpu_bo_size(gds);
-               }
-               if (gws) {
-                       p->job->gws_base = amdgpu_bo_gpu_offset(gws);
-                       p->job->gws_size = amdgpu_bo_size(gws);
-               }
-               if (oa) {
-                       p->job->oa_base = amdgpu_bo_gpu_offset(oa);
-                       p->job->oa_size = amdgpu_bo_size(oa);
-               }
+       if (gds) {
+               p->job->gds_base = amdgpu_bo_gpu_offset(gds);
+               p->job->gds_size = amdgpu_bo_size(gds);
+       }
+       if (gws) {
+               p->job->gws_base = amdgpu_bo_gpu_offset(gws);
+               p->job->gws_size = amdgpu_bo_size(gws);
+       }
+       if (oa) {
+               p->job->oa_base = amdgpu_bo_gpu_offset(oa);
+               p->job->oa_size = amdgpu_bo_size(oa);
        }
 
        if (!r && p->uf_entry.robj) {
index 290e279abf0dcc862b636025ee48d256fb737f02..3317d1536f4fc352247756e3c650d72c9236916b 100644 (file)
@@ -1730,6 +1730,18 @@ static int amdgpu_device_ip_late_set_cg_state(struct amdgpu_device *adev)
                        }
                }
        }
+
+       if (adev->powerplay.pp_feature & PP_GFXOFF_MASK) {
+               /* enable gfx powergating */
+               amdgpu_device_ip_set_powergating_state(adev,
+                                                      AMD_IP_BLOCK_TYPE_GFX,
+                                                      AMD_PG_STATE_GATE);
+               /* enable gfxoff */
+               amdgpu_device_ip_set_powergating_state(adev,
+                                                      AMD_IP_BLOCK_TYPE_SMC,
+                                                      AMD_PG_STATE_GATE);
+       }
+
        return 0;
 }
 
index 2c8e27370284d53f3b4a440e637ba93759c7a49c..5fb156a01774ea5d245348f6e4341dfba5ca76aa 100644 (file)
@@ -30,6 +30,7 @@
 #include <drm/drmP.h>
 #include <drm/amdgpu_drm.h>
 #include "amdgpu.h"
+#include "amdgpu_display.h"
 
 void amdgpu_gem_object_free(struct drm_gem_object *gobj)
 {
@@ -235,6 +236,13 @@ int amdgpu_gem_create_ioctl(struct drm_device *dev, void *data,
        /* create a gem object to contain this object in */
        if (args->in.domains & (AMDGPU_GEM_DOMAIN_GDS |
            AMDGPU_GEM_DOMAIN_GWS | AMDGPU_GEM_DOMAIN_OA)) {
+               if (flags & AMDGPU_GEM_CREATE_VM_ALWAYS_VALID) {
+                       /* if gds bo is created from user space, it must be
+                        * passed to bo list
+                        */
+                       DRM_ERROR("GDS bo cannot be per-vm-bo\n");
+                       return -EINVAL;
+               }
                flags |= AMDGPU_GEM_CREATE_NO_CPU_ACCESS;
                if (args->in.domains == AMDGPU_GEM_DOMAIN_GDS)
                        size = size << AMDGPU_GDS_SHIFT;
@@ -749,15 +757,16 @@ int amdgpu_mode_dumb_create(struct drm_file *file_priv,
        struct amdgpu_device *adev = dev->dev_private;
        struct drm_gem_object *gobj;
        uint32_t handle;
+       u32 domain;
        int r;
 
        args->pitch = amdgpu_align_pitch(adev, args->width,
                                         DIV_ROUND_UP(args->bpp, 8), 0);
        args->size = (u64)args->pitch * args->height;
        args->size = ALIGN(args->size, PAGE_SIZE);
-
-       r = amdgpu_gem_object_create(adev, args->size, 0,
-                                    AMDGPU_GEM_DOMAIN_VRAM,
+       domain = amdgpu_bo_get_preferred_pin_domain(adev,
+                               amdgpu_display_supported_domains(adev));
+       r = amdgpu_gem_object_create(adev, args->size, 0, domain,
                                     AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED,
                                     false, NULL, &gobj);
        if (r)
index 6a9e46ae7f0a460cc47ebf443f6098c7362965d8..5e4e1bd9038379fe62666e44318162adfc544fea 100644 (file)
@@ -703,11 +703,7 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain,
        /* This assumes only APU display buffers are pinned with (VRAM|GTT).
         * See function amdgpu_display_supported_domains()
         */
-       if (domain == (AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT)) {
-               domain = AMDGPU_GEM_DOMAIN_VRAM;
-               if (adev->gmc.real_vram_size <= AMDGPU_SG_THRESHOLD)
-                       domain = AMDGPU_GEM_DOMAIN_GTT;
-       }
+       domain = amdgpu_bo_get_preferred_pin_domain(adev, domain);
 
        if (bo->pin_count) {
                uint32_t mem_type = bo->tbo.mem.mem_type;
@@ -1066,3 +1062,14 @@ u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo)
 
        return bo->tbo.offset;
 }
+
+uint32_t amdgpu_bo_get_preferred_pin_domain(struct amdgpu_device *adev,
+                                           uint32_t domain)
+{
+       if (domain == (AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT)) {
+               domain = AMDGPU_GEM_DOMAIN_VRAM;
+               if (adev->gmc.real_vram_size <= AMDGPU_SG_THRESHOLD)
+                       domain = AMDGPU_GEM_DOMAIN_GTT;
+       }
+       return domain;
+}
index 540e03fa159f4b6c1025bdbb22e8749af33c2bbd..731748033878b35a32f70a6fe4eda9d0d44835cb 100644 (file)
@@ -289,7 +289,8 @@ int amdgpu_bo_restore_from_shadow(struct amdgpu_device *adev,
                                  struct reservation_object *resv,
                                  struct dma_fence **fence,
                                  bool direct);
-
+uint32_t amdgpu_bo_get_preferred_pin_domain(struct amdgpu_device *adev,
+                                           uint32_t domain);
 
 /*
  * sub allocation
index 8851bcdfc2609f28a43ac27322bc3ff957a7a942..127e87b470ff4da368c8c1feb0576f0b6cb0c62c 100644 (file)
@@ -49,8 +49,6 @@ static void amdgpu_vcn_idle_work_handler(struct work_struct *work);
 
 int amdgpu_vcn_sw_init(struct amdgpu_device *adev)
 {
-       struct amdgpu_ring *ring;
-       struct drm_sched_rq *rq;
        unsigned long bo_size;
        const char *fw_name;
        const struct common_firmware_header *hdr;
@@ -84,6 +82,7 @@ int amdgpu_vcn_sw_init(struct amdgpu_device *adev)
        }
 
        hdr = (const struct common_firmware_header *)adev->vcn.fw->data;
+       adev->vcn.fw_version = le32_to_cpu(hdr->ucode_version);
        family_id = le32_to_cpu(hdr->ucode_version) & 0xff;
        version_major = (le32_to_cpu(hdr->ucode_version) >> 24) & 0xff;
        version_minor = (le32_to_cpu(hdr->ucode_version) >> 8) & 0xff;
@@ -102,24 +101,6 @@ int amdgpu_vcn_sw_init(struct amdgpu_device *adev)
                return r;
        }
 
-       ring = &adev->vcn.ring_dec;
-       rq = &ring->sched.sched_rq[DRM_SCHED_PRIORITY_NORMAL];
-       r = drm_sched_entity_init(&ring->sched, &adev->vcn.entity_dec,
-                                 rq, NULL);
-       if (r != 0) {
-               DRM_ERROR("Failed setting up VCN dec run queue.\n");
-               return r;
-       }
-
-       ring = &adev->vcn.ring_enc[0];
-       rq = &ring->sched.sched_rq[DRM_SCHED_PRIORITY_NORMAL];
-       r = drm_sched_entity_init(&ring->sched, &adev->vcn.entity_enc,
-                                 rq, NULL);
-       if (r != 0) {
-               DRM_ERROR("Failed setting up VCN enc run queue.\n");
-               return r;
-       }
-
        return 0;
 }
 
@@ -129,10 +110,6 @@ int amdgpu_vcn_sw_fini(struct amdgpu_device *adev)
 
        kfree(adev->vcn.saved_bo);
 
-       drm_sched_entity_fini(&adev->vcn.ring_dec.sched, &adev->vcn.entity_dec);
-
-       drm_sched_entity_fini(&adev->vcn.ring_enc[0].sched, &adev->vcn.entity_enc);
-
        amdgpu_bo_free_kernel(&adev->vcn.vcpu_bo,
                              &adev->vcn.gpu_addr,
                              (void **)&adev->vcn.cpu_addr);
@@ -278,7 +255,7 @@ int amdgpu_vcn_dec_ring_test_ring(struct amdgpu_ring *ring)
 }
 
 static int amdgpu_vcn_dec_send_msg(struct amdgpu_ring *ring,
-                                  struct amdgpu_bo *bo, bool direct,
+                                  struct amdgpu_bo *bo,
                                   struct dma_fence **fence)
 {
        struct amdgpu_device *adev = ring->adev;
@@ -306,19 +283,12 @@ static int amdgpu_vcn_dec_send_msg(struct amdgpu_ring *ring,
        }
        ib->length_dw = 16;
 
-       if (direct) {
-               r = amdgpu_ib_schedule(ring, 1, ib, NULL, &f);
-               job->fence = dma_fence_get(f);
-               if (r)
-                       goto err_free;
+       r = amdgpu_ib_schedule(ring, 1, ib, NULL, &f);
+       job->fence = dma_fence_get(f);
+       if (r)
+               goto err_free;
 
-               amdgpu_job_free(job);
-       } else {
-               r = amdgpu_job_submit(job, ring, &adev->vcn.entity_dec,
-                                     AMDGPU_FENCE_OWNER_UNDEFINED, &f);
-               if (r)
-                       goto err_free;
-       }
+       amdgpu_job_free(job);
 
        amdgpu_bo_fence(bo, f, false);
        amdgpu_bo_unreserve(bo);
@@ -370,11 +340,11 @@ static int amdgpu_vcn_dec_get_create_msg(struct amdgpu_ring *ring, uint32_t hand
        for (i = 14; i < 1024; ++i)
                msg[i] = cpu_to_le32(0x0);
 
-       return amdgpu_vcn_dec_send_msg(ring, bo, true, fence);
+       return amdgpu_vcn_dec_send_msg(ring, bo, fence);
 }
 
 static int amdgpu_vcn_dec_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
-                              bool direct, struct dma_fence **fence)
+                              struct dma_fence **fence)
 {
        struct amdgpu_device *adev = ring->adev;
        struct amdgpu_bo *bo = NULL;
@@ -396,7 +366,7 @@ static int amdgpu_vcn_dec_get_destroy_msg(struct amdgpu_ring *ring, uint32_t han
        for (i = 6; i < 1024; ++i)
                msg[i] = cpu_to_le32(0x0);
 
-       return amdgpu_vcn_dec_send_msg(ring, bo, direct, fence);
+       return amdgpu_vcn_dec_send_msg(ring, bo, fence);
 }
 
 int amdgpu_vcn_dec_ring_test_ib(struct amdgpu_ring *ring, long timeout)
@@ -410,7 +380,7 @@ int amdgpu_vcn_dec_ring_test_ib(struct amdgpu_ring *ring, long timeout)
                goto error;
        }
 
-       r = amdgpu_vcn_dec_get_destroy_msg(ring, 1, true, &fence);
+       r = amdgpu_vcn_dec_get_destroy_msg(ring, 1, &fence);
        if (r) {
                DRM_ERROR("amdgpu: failed to get destroy ib (%ld).\n", r);
                goto error;
index 181e6afa984727b42bfa83c3d7e7895c34d718b5..773010b9ff153f89aaa5747df5dc09b07baa8cd7 100644 (file)
@@ -67,8 +67,6 @@ struct amdgpu_vcn {
        struct amdgpu_ring      ring_dec;
        struct amdgpu_ring      ring_enc[AMDGPU_VCN_MAX_ENC_RINGS];
        struct amdgpu_irq_src   irq;
-       struct drm_sched_entity entity_dec;
-       struct drm_sched_entity entity_enc;
        unsigned                num_enc_rings;
 };
 
index ccba88cc8c54227e6a20cd9b84a0234f8f0590e6..b0eb2f537392d192d84d3884bd685f7084e9e220 100644 (file)
@@ -2123,7 +2123,8 @@ int amdgpu_vm_bo_clear_mappings(struct amdgpu_device *adev,
                        before->last = saddr - 1;
                        before->offset = tmp->offset;
                        before->flags = tmp->flags;
-                       list_add(&before->list, &tmp->list);
+                       before->bo_va = tmp->bo_va;
+                       list_add(&before->list, &tmp->bo_va->invalids);
                }
 
                /* Remember mapping split at the end */
@@ -2133,7 +2134,8 @@ int amdgpu_vm_bo_clear_mappings(struct amdgpu_device *adev,
                        after->offset = tmp->offset;
                        after->offset += after->start - tmp->start;
                        after->flags = tmp->flags;
-                       list_add(&after->list, &tmp->list);
+                       after->bo_va = tmp->bo_va;
+                       list_add(&after->list, &tmp->bo_va->invalids);
                }
 
                list_del(&tmp->list);
index 60608b3df881202651ae8cba2f4f9720c0dd8217..d5ebe566809b22e401f88582a7b73d9caf4faf81 100644 (file)
@@ -64,7 +64,7 @@ static u32 df_v3_6_get_hbm_channel_number(struct amdgpu_device *adev)
        int fb_channel_number;
 
        fb_channel_number = adev->df_funcs->get_fb_channel_number(adev);
-       if (fb_channel_number > ARRAY_SIZE(df_v3_6_channel_number))
+       if (fb_channel_number >= ARRAY_SIZE(df_v3_6_channel_number))
                fb_channel_number = 0;
 
        return df_v3_6_channel_number[fb_channel_number];
index d7530fdfaad51055bb2fe3d8013b4055f8a46173..a69153435ea7ec9ccf4180b70ead070734549688 100644 (file)
@@ -111,6 +111,7 @@ static const struct soc15_reg_golden golden_settings_gc_9_0_vg10[] =
 
 static const struct soc15_reg_golden golden_settings_gc_9_0_vg20[] =
 {
+       SOC15_REG_GOLDEN_VALUE(GC, 0, mmCB_DCC_CONFIG, 0x0f000080, 0x04000080),
        SOC15_REG_GOLDEN_VALUE(GC, 0, mmCB_HW_CONTROL_2, 0x0f000000, 0x0a000000),
        SOC15_REG_GOLDEN_VALUE(GC, 0, mmCB_HW_CONTROL_3, 0x30000000, 0x10000000),
        SOC15_REG_GOLDEN_VALUE(GC, 0, mmGB_ADDR_CONFIG, 0xf3e777ff, 0x22014042),
@@ -1837,13 +1838,15 @@ static void gfx_v9_1_parse_ind_reg_list(int *register_list_format,
                                int indirect_offset,
                                int list_size,
                                int *unique_indirect_regs,
-                               int *unique_indirect_reg_count,
+                               int unique_indirect_reg_count,
                                int *indirect_start_offsets,
-                               int *indirect_start_offsets_count)
+                               int *indirect_start_offsets_count,
+                               int max_start_offsets_count)
 {
        int idx;
 
        for (; indirect_offset < list_size; indirect_offset++) {
+               WARN_ON(*indirect_start_offsets_count >= max_start_offsets_count);
                indirect_start_offsets[*indirect_start_offsets_count] = indirect_offset;
                *indirect_start_offsets_count = *indirect_start_offsets_count + 1;
 
@@ -1851,14 +1854,14 @@ static void gfx_v9_1_parse_ind_reg_list(int *register_list_format,
                        indirect_offset += 2;
 
                        /* look for the matching indice */
-                       for (idx = 0; idx < *unique_indirect_reg_count; idx++) {
+                       for (idx = 0; idx < unique_indirect_reg_count; idx++) {
                                if (unique_indirect_regs[idx] ==
                                        register_list_format[indirect_offset] ||
                                        !unique_indirect_regs[idx])
                                        break;
                        }
 
-                       BUG_ON(idx >= *unique_indirect_reg_count);
+                       BUG_ON(idx >= unique_indirect_reg_count);
 
                        if (!unique_indirect_regs[idx])
                                unique_indirect_regs[idx] = register_list_format[indirect_offset];
@@ -1893,9 +1896,10 @@ static int gfx_v9_1_init_rlc_save_restore_list(struct amdgpu_device *adev)
                                    adev->gfx.rlc.reg_list_format_direct_reg_list_length,
                                    adev->gfx.rlc.reg_list_format_size_bytes >> 2,
                                    unique_indirect_regs,
-                                   &unique_indirect_reg_count,
+                                   unique_indirect_reg_count,
                                    indirect_start_offsets,
-                                   &indirect_start_offsets_count);
+                                   &indirect_start_offsets_count,
+                                   ARRAY_SIZE(indirect_start_offsets));
 
        /* enable auto inc in case it is disabled */
        tmp = RREG32(SOC15_REG_OFFSET(GC, 0, mmRLC_SRM_CNTL));
@@ -3404,11 +3408,6 @@ static int gfx_v9_0_late_init(void *handle)
        if (r)
                return r;
 
-       r = amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_GFX,
-                                                  AMD_PG_STATE_GATE);
-       if (r)
-               return r;
-
        return 0;
 }
 
index 0c768e388ace5f9f8fc70c500ef09e20ccae9743..727071fee6f64d9148076b1bb1916bf4136b223c 100644 (file)
@@ -47,6 +47,8 @@ MODULE_FIRMWARE("amdgpu/vega20_asd.bin");
 
 #define smnMP1_FIRMWARE_FLAGS 0x3010028
 
+static uint32_t sos_old_versions[] = {1517616, 1510592, 1448594, 1446554};
+
 static int
 psp_v3_1_get_fw_type(struct amdgpu_firmware_info *ucode, enum psp_gfx_fw_type *type)
 {
@@ -210,12 +212,31 @@ static int psp_v3_1_bootloader_load_sysdrv(struct psp_context *psp)
        return ret;
 }
 
+static bool psp_v3_1_match_version(struct amdgpu_device *adev, uint32_t ver)
+{
+       int i;
+
+       if (ver == adev->psp.sos_fw_version)
+               return true;
+
+       /*
+        * Double check if the latest four legacy versions.
+        * If yes, it is still the right version.
+        */
+       for (i = 0; i < sizeof(sos_old_versions) / sizeof(uint32_t); i++) {
+               if (sos_old_versions[i] == adev->psp.sos_fw_version)
+                       return true;
+       }
+
+       return false;
+}
+
 static int psp_v3_1_bootloader_load_sos(struct psp_context *psp)
 {
        int ret;
        unsigned int psp_gfxdrv_command_reg = 0;
        struct amdgpu_device *adev = psp->adev;
-       uint32_t sol_reg;
+       uint32_t sol_reg, ver;
 
        /* Check sOS sign of life register to confirm sys driver and sOS
         * are already been loaded.
@@ -248,6 +269,10 @@ static int psp_v3_1_bootloader_load_sos(struct psp_context *psp)
                           RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_81),
                           0, true);
 
+       ver = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_58);
+       if (!psp_v3_1_match_version(adev, ver))
+               DRM_WARN("SOS version doesn't match\n");
+
        return ret;
 }
 
index 68b4a22a88925728d1dd9f4b303601ac73694a42..83f2717fcf81a4077b7e7187ad0c0e2c7abdd046 100644 (file)
@@ -685,6 +685,7 @@ static int soc15_common_early_init(void *handle)
                        AMD_CG_SUPPORT_BIF_MGCG |
                        AMD_CG_SUPPORT_BIF_LS |
                        AMD_CG_SUPPORT_HDP_MGCG |
+                       AMD_CG_SUPPORT_HDP_LS |
                        AMD_CG_SUPPORT_ROM_MGCG |
                        AMD_CG_SUPPORT_VCE_MGCG |
                        AMD_CG_SUPPORT_UVD_MGCG;
index 110b294ebed3e554a9bc44d75a9a30ebcd51e61a..29684c3ea4ef2b6d1586721f0b095dfd961eb989 100644 (file)
@@ -769,14 +769,14 @@ static int vcn_v1_0_stop(struct amdgpu_device *adev)
        return 0;
 }
 
-bool vcn_v1_0_is_idle(void *handle)
+static bool vcn_v1_0_is_idle(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
        return (RREG32_SOC15(VCN, 0, mmUVD_STATUS) == 0x2);
 }
 
-int vcn_v1_0_wait_for_idle(void *handle)
+static int vcn_v1_0_wait_for_idle(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        int ret = 0;
index f9b9ab90558c92c223050d5c47a8547cb1d1ca06..f9add85157e7355432aab9d0d14728f8906774f9 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/moduleparam.h>
 #include <linux/version.h>
 #include <linux/types.h>
+#include <linux/pm_runtime.h>
 
 #include <drm/drmP.h>
 #include <drm/drm_atomic.h>
@@ -2095,12 +2096,6 @@ convert_color_depth_from_display_info(const struct drm_connector *connector)
 {
        uint32_t bpc = connector->display_info.bpc;
 
-       /* Limited color depth to 8bit
-        * TODO: Still need to handle deep color
-        */
-       if (bpc > 8)
-               bpc = 8;
-
        switch (bpc) {
        case 0:
                /* Temporary Work around, DRM don't parse color depth for
@@ -2316,27 +2311,22 @@ decide_crtc_timing_for_drm_display_mode(struct drm_display_mode *drm_mode,
        }
 }
 
-static int create_fake_sink(struct amdgpu_dm_connector *aconnector)
+static struct dc_sink *
+create_fake_sink(struct amdgpu_dm_connector *aconnector)
 {
-       struct dc_sink *sink = NULL;
        struct dc_sink_init_data sink_init_data = { 0 };
-
+       struct dc_sink *sink = NULL;
        sink_init_data.link = aconnector->dc_link;
        sink_init_data.sink_signal = aconnector->dc_link->connector_signal;
 
        sink = dc_sink_create(&sink_init_data);
        if (!sink) {
                DRM_ERROR("Failed to create sink!\n");
-               return -ENOMEM;
+               return NULL;
        }
-
        sink->sink_signal = SIGNAL_TYPE_VIRTUAL;
-       aconnector->fake_enable = true;
-
-       aconnector->dc_sink = sink;
-       aconnector->dc_link->local_sink = sink;
 
-       return 0;
+       return sink;
 }
 
 static void set_multisync_trigger_params(
@@ -2399,7 +2389,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
        struct dc_stream_state *stream = NULL;
        struct drm_display_mode mode = *drm_mode;
        bool native_mode_found = false;
-
+       struct dc_sink *sink = NULL;
        if (aconnector == NULL) {
                DRM_ERROR("aconnector is NULL!\n");
                return stream;
@@ -2417,15 +2407,18 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
                        return stream;
                }
 
-               if (create_fake_sink(aconnector))
+               sink = create_fake_sink(aconnector);
+               if (!sink)
                        return stream;
+       } else {
+               sink = aconnector->dc_sink;
        }
 
-       stream = dc_create_stream_for_sink(aconnector->dc_sink);
+       stream = dc_create_stream_for_sink(sink);
 
        if (stream == NULL) {
                DRM_ERROR("Failed to create stream for sink!\n");
-               return stream;
+               goto finish;
        }
 
        list_for_each_entry(preferred_mode, &aconnector->base.modes, head) {
@@ -2464,12 +2457,15 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
        fill_audio_info(
                &stream->audio_info,
                drm_connector,
-               aconnector->dc_sink);
+               sink);
 
        update_stream_signal(stream);
 
        if (dm_state && dm_state->freesync_capable)
                stream->ignore_msa_timing_param = true;
+finish:
+       if (sink && sink->sink_signal == SIGNAL_TYPE_VIRTUAL)
+               dc_sink_release(sink);
 
        return stream;
 }
@@ -2714,6 +2710,9 @@ void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector)
        struct dm_connector_state *state =
                to_dm_connector_state(connector->state);
 
+       if (connector->state)
+               __drm_atomic_helper_connector_destroy_state(connector->state);
+
        kfree(state);
 
        state = kzalloc(sizeof(*state), GFP_KERNEL);
@@ -2724,8 +2723,7 @@ void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector)
                state->underscan_hborder = 0;
                state->underscan_vborder = 0;
 
-               connector->state = &state->base;
-               connector->state->connector = connector;
+               __drm_atomic_helper_connector_reset(connector, &state->base);
        }
 }
 
@@ -3083,17 +3081,6 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane,
                }
        }
 
-       /* It's a hack for s3 since in 4.9 kernel filter out cursor buffer
-        * prepare and cleanup in drm_atomic_helper_prepare_planes
-        * and drm_atomic_helper_cleanup_planes because fb doens't in s3.
-        * IN 4.10 kernel this code should be removed and amdgpu_device_suspend
-        * code touching fram buffers should be avoided for DC.
-        */
-       if (plane->type == DRM_PLANE_TYPE_CURSOR) {
-               struct amdgpu_crtc *acrtc = to_amdgpu_crtc(new_state->crtc);
-
-               acrtc->cursor_bo = obj;
-       }
        return 0;
 }
 
@@ -4281,6 +4268,8 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
                        if (dm_old_crtc_state->stream)
                                remove_stream(adev, acrtc, dm_old_crtc_state->stream);
 
+                       pm_runtime_get_noresume(dev->dev);
+
                        acrtc->enabled = true;
                        acrtc->hw_mode = new_crtc_state->mode;
                        crtc->hwmode = new_crtc_state->mode;
@@ -4469,6 +4458,16 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
                drm_atomic_helper_wait_for_flip_done(dev, state);
 
        drm_atomic_helper_cleanup_planes(dev, state);
+
+       /* Finally, drop a runtime PM reference for each newly disabled CRTC,
+        * so we can put the GPU into runtime suspend if we're not driving any
+        * displays anymore
+        */
+       pm_runtime_mark_last_busy(dev->dev);
+       for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
+               if (old_crtc_state->active && !new_crtc_state->active)
+                       pm_runtime_put_autosuspend(dev->dev);
+       }
 }
 
 
index 4be21bf5474981a8b954f4b1fb6b5c6a283cc82b..a910f01838ab0dd1a7d395f82b9d542d5abfbbf0 100644 (file)
@@ -555,6 +555,9 @@ static inline int dm_irq_state(struct amdgpu_device *adev,
                return 0;
        }
 
+       if (acrtc->otg_inst == -1)
+               return 0;
+
        irq_source = dal_irq_type + acrtc->otg_inst;
 
        st = (state == AMDGPU_IRQ_STATE_ENABLE);
index 0229c7edb8ad75242b89416e52e39373b0e105fc..5a3346124a0177da27c6d205559a2f363f5aa40d 100644 (file)
@@ -234,6 +234,33 @@ static void pp_to_dc_clock_levels(
        }
 }
 
+static void pp_to_dc_clock_levels_with_latency(
+               const struct pp_clock_levels_with_latency *pp_clks,
+               struct dm_pp_clock_levels_with_latency *clk_level_info,
+               enum dm_pp_clock_type dc_clk_type)
+{
+       uint32_t i;
+
+       if (pp_clks->num_levels > DM_PP_MAX_CLOCK_LEVELS) {
+               DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n",
+                               DC_DECODE_PP_CLOCK_TYPE(dc_clk_type),
+                               pp_clks->num_levels,
+                               DM_PP_MAX_CLOCK_LEVELS);
+
+               clk_level_info->num_levels = DM_PP_MAX_CLOCK_LEVELS;
+       } else
+               clk_level_info->num_levels = pp_clks->num_levels;
+
+       DRM_DEBUG("DM_PPLIB: values for %s clock\n",
+                       DC_DECODE_PP_CLOCK_TYPE(dc_clk_type));
+
+       for (i = 0; i < clk_level_info->num_levels; i++) {
+               DRM_DEBUG("DM_PPLIB:\t %d\n", pp_clks->data[i].clocks_in_khz);
+               clk_level_info->data[i].clocks_in_khz = pp_clks->data[i].clocks_in_khz;
+               clk_level_info->data[i].latency_in_us = pp_clks->data[i].latency_in_us;
+       }
+}
+
 bool dm_pp_get_clock_levels_by_type(
                const struct dc_context *ctx,
                enum dm_pp_clock_type clk_type,
@@ -311,8 +338,22 @@ bool dm_pp_get_clock_levels_by_type_with_latency(
        enum dm_pp_clock_type clk_type,
        struct dm_pp_clock_levels_with_latency *clk_level_info)
 {
-       /* TODO: to be implemented */
-       return false;
+       struct amdgpu_device *adev = ctx->driver_context;
+       void *pp_handle = adev->powerplay.pp_handle;
+       struct pp_clock_levels_with_latency pp_clks = { 0 };
+       const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
+
+       if (!pp_funcs || !pp_funcs->get_clock_by_type_with_latency)
+               return false;
+
+       if (pp_funcs->get_clock_by_type_with_latency(pp_handle,
+                                                    dc_to_pp_clock_type(clk_type),
+                                                    &pp_clks))
+               return false;
+
+       pp_to_dc_clock_levels_with_latency(&pp_clks, clk_level_info, clk_type);
+
+       return true;
 }
 
 bool dm_pp_get_clock_levels_by_type_with_voltage(
index e61dd97d0928ce910420c3ef74fc1bd8e97da42b..f28989860fd81cdc70643421350f167b41183d35 100644 (file)
@@ -449,6 +449,11 @@ static inline unsigned int clamp_ux_dy(
                return min_clamp;
 }
 
+unsigned int dc_fixpt_u3d19(struct fixed31_32 arg)
+{
+       return ux_dy(arg.value, 3, 19);
+}
+
 unsigned int dc_fixpt_u2d19(struct fixed31_32 arg)
 {
        return ux_dy(arg.value, 2, 19);
index 7d609c71394bba4049ba7722b912c435cf18b11b..7857cb42b3e62e5603af2408128e4cefb6531a0c 100644 (file)
@@ -1630,17 +1630,42 @@ static enum dc_status read_hpd_rx_irq_data(
        struct dc_link *link,
        union hpd_irq_data *irq_data)
 {
+       static enum dc_status retval;
+
        /* The HW reads 16 bytes from 200h on HPD,
         * but if we get an AUX_DEFER, the HW cannot retry
         * and this causes the CTS tests 4.3.2.1 - 3.2.4 to
         * fail, so we now explicitly read 6 bytes which is
         * the req from the above mentioned test cases.
+        *
+        * For DP 1.4 we need to read those from 2002h range.
         */
-       return core_link_read_dpcd(
-       link,
-       DP_SINK_COUNT,
-       irq_data->raw,
-       sizeof(union hpd_irq_data));
+       if (link->dpcd_caps.dpcd_rev.raw < DPCD_REV_14)
+               retval = core_link_read_dpcd(
+                       link,
+                       DP_SINK_COUNT,
+                       irq_data->raw,
+                       sizeof(union hpd_irq_data));
+       else {
+               /* Read 2 bytes at this location,... */
+               retval = core_link_read_dpcd(
+                       link,
+                       DP_SINK_COUNT_ESI,
+                       irq_data->raw,
+                       2);
+
+               if (retval != DC_OK)
+                       return retval;
+
+               /* ... then read remaining 4 at the other location */
+               retval = core_link_read_dpcd(
+                       link,
+                       DP_LANE0_1_STATUS_ESI,
+                       &irq_data->raw[2],
+                       4);
+       }
+
+       return retval;
 }
 
 static bool allow_hpd_rx_irq(const struct dc_link *link)
@@ -2278,7 +2303,7 @@ static void dp_wa_power_up_0010FA(struct dc_link *link, uint8_t *dpcd_data,
 
 static bool retrieve_link_cap(struct dc_link *link)
 {
-       uint8_t dpcd_data[DP_TRAINING_AUX_RD_INTERVAL - DP_DPCD_REV + 1];
+       uint8_t dpcd_data[DP_ADAPTER_CAP - DP_DPCD_REV + 1];
 
        union down_stream_port_count down_strm_port_count;
        union edp_configuration_cap edp_config_cap;
index 0a6d483dc046a81b499b7d9df8c4e090d6191eee..c0e813c7ddd41db3a372218e564f0f1d70882b2e 100644 (file)
@@ -72,7 +72,8 @@ static void dce110_update_generic_info_packet(
        uint32_t max_retries = 50;
 
        /*we need turn on clock before programming AFMT block*/
-       REG_UPDATE(AFMT_CNTL, AFMT_AUDIO_CLOCK_EN, 1);
+       if (REG(AFMT_CNTL))
+               REG_UPDATE(AFMT_CNTL, AFMT_AUDIO_CLOCK_EN, 1);
 
        if (REG(AFMT_VBI_PACKET_CONTROL1)) {
                if (packet_index >= 8)
@@ -719,7 +720,8 @@ static void dce110_stream_encoder_update_hdmi_info_packets(
                        const uint32_t *content =
                                (const uint32_t *) &info_frame->avi.sb[0];
                        /*we need turn on clock before programming AFMT block*/
-                       REG_UPDATE(AFMT_CNTL, AFMT_AUDIO_CLOCK_EN, 1);
+                       if (REG(AFMT_CNTL))
+                               REG_UPDATE(AFMT_CNTL, AFMT_AUDIO_CLOCK_EN, 1);
 
                        REG_WRITE(AFMT_AVI_INFO0, content[0]);
 
index 9150d26944508e4a91ec5d16af7cb2d6fa3b589e..e2994d3370448028d86de5d6e11b6cfa8d4acc01 100644 (file)
@@ -121,10 +121,10 @@ static void reset_lb_on_vblank(struct dc_context *ctx)
                frame_count = dm_read_reg(ctx, mmCRTC_STATUS_FRAME_COUNT);
 
 
-               for (retry = 100; retry > 0; retry--) {
+               for (retry = 10000; retry > 0; retry--) {
                        if (frame_count != dm_read_reg(ctx, mmCRTC_STATUS_FRAME_COUNT))
                                break;
-                       msleep(1);
+                       udelay(10);
                }
                if (!retry)
                        dm_error("Frame count did not increase for 100ms.\n");
@@ -147,14 +147,14 @@ static void wait_for_fbc_state_changed(
        uint32_t addr = mmFBC_STATUS;
        uint32_t value;
 
-       while (counter < 10) {
+       while (counter < 1000) {
                value = dm_read_reg(cp110->base.ctx, addr);
                if (get_reg_field_value(
                        value,
                        FBC_STATUS,
                        FBC_ENABLE_STATUS) == enabled)
                        break;
-               msleep(10);
+               udelay(100);
                counter++;
        }
 
index a92fb0aa2ff3b3f727c6d8e4c0bd38c6b42d902f..c29052b6da5a8603bbf8b771dad34e62d5678590 100644 (file)
@@ -1004,9 +1004,9 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx, int option)
                /*don't free audio if it is from retrain or internal disable stream*/
                if (option == FREE_ACQUIRED_RESOURCE && dc->caps.dynamic_audio == true) {
                        /*we have to dynamic arbitrate the audio endpoints*/
-                       pipe_ctx->stream_res.audio = NULL;
                        /*we free the resource, need reset is_audio_acquired*/
                        update_audio_usage(&dc->current_state->res_ctx, dc->res_pool, pipe_ctx->stream_res.audio, false);
+                       pipe_ctx->stream_res.audio = NULL;
                }
 
                /* TODO: notify audio driver for if audio modes list changed
index 46a35c7f01df64f9d0aa67482cecd9d2fc3b6603..c69fa4bfab0af125974e18fcc6f9adc798edfd2f 100644 (file)
@@ -132,8 +132,7 @@ void dpp_set_gamut_remap_bypass(struct dcn10_dpp *dpp)
 
 #define IDENTITY_RATIO(ratio) (dc_fixpt_u2d19(ratio) == (1 << 19))
 
-
-bool dpp_get_optimal_number_of_taps(
+static bool dpp_get_optimal_number_of_taps(
                struct dpp *dpp,
                struct scaler_data *scl_data,
                const struct scaling_taps *in_taps)
index 5944a3ba040904e942bce17995a99a3e264745fb..e862cafa6501b78e7601fe9e95ebf7f81b728130 100644 (file)
@@ -1424,12 +1424,8 @@ void dpp1_set_degamma(
                enum ipp_degamma_mode mode);
 
 void dpp1_set_degamma_pwl(struct dpp *dpp_base,
-                                                                const struct pwl_params *params);
+               const struct pwl_params *params);
 
-bool dpp_get_optimal_number_of_taps(
-               struct dpp *dpp,
-               struct scaler_data *scl_data,
-               const struct scaling_taps *in_taps);
 
 void dpp_read_state(struct dpp *dpp_base,
                struct dcn_dpp_state *s);
index 4ddd6273d5a5bc64888c8c4b02fb1caa4b28fd61..f862fd148ccaff5190597a9fc34118299c57122e 100644 (file)
@@ -565,16 +565,16 @@ static void dpp1_dscl_set_manual_ratio_init(
        uint32_t init_int = 0;
 
        REG_SET(SCL_HORZ_FILTER_SCALE_RATIO, 0,
-                       SCL_H_SCALE_RATIO, dc_fixpt_u2d19(data->ratios.horz) << 5);
+                       SCL_H_SCALE_RATIO, dc_fixpt_u3d19(data->ratios.horz) << 5);
 
        REG_SET(SCL_VERT_FILTER_SCALE_RATIO, 0,
-                       SCL_V_SCALE_RATIO, dc_fixpt_u2d19(data->ratios.vert) << 5);
+                       SCL_V_SCALE_RATIO, dc_fixpt_u3d19(data->ratios.vert) << 5);
 
        REG_SET(SCL_HORZ_FILTER_SCALE_RATIO_C, 0,
-                       SCL_H_SCALE_RATIO_C, dc_fixpt_u2d19(data->ratios.horz_c) << 5);
+                       SCL_H_SCALE_RATIO_C, dc_fixpt_u3d19(data->ratios.horz_c) << 5);
 
        REG_SET(SCL_VERT_FILTER_SCALE_RATIO_C, 0,
-                       SCL_V_SCALE_RATIO_C, dc_fixpt_u2d19(data->ratios.vert_c) << 5);
+                       SCL_V_SCALE_RATIO_C, dc_fixpt_u3d19(data->ratios.vert_c) << 5);
 
        /*
         * 0.24 format for fraction, first five bits zeroed
index d2ab78b35a7ae8e267b1ca2e814d719cd90ffe48..c28085be39ff9530730481f98e3c2c800ea167cc 100644 (file)
@@ -396,11 +396,15 @@ bool hubp1_program_surface_flip_and_addr(
                if (address->grph_stereo.right_addr.quad_part == 0)
                        break;
 
-               REG_UPDATE_4(DCSURF_SURFACE_CONTROL,
+               REG_UPDATE_8(DCSURF_SURFACE_CONTROL,
                                PRIMARY_SURFACE_TMZ, address->tmz_surface,
                                PRIMARY_SURFACE_TMZ_C, address->tmz_surface,
                                PRIMARY_META_SURFACE_TMZ, address->tmz_surface,
-                               PRIMARY_META_SURFACE_TMZ_C, address->tmz_surface);
+                               PRIMARY_META_SURFACE_TMZ_C, address->tmz_surface,
+                               SECONDARY_SURFACE_TMZ, address->tmz_surface,
+                               SECONDARY_SURFACE_TMZ_C, address->tmz_surface,
+                               SECONDARY_META_SURFACE_TMZ, address->tmz_surface,
+                               SECONDARY_META_SURFACE_TMZ_C, address->tmz_surface);
 
                if (address->grph_stereo.right_meta_addr.quad_part != 0) {
 
@@ -459,9 +463,11 @@ void hubp1_dcc_control(struct hubp *hubp, bool enable,
        uint32_t dcc_ind_64b_blk = independent_64b_blks ? 1 : 0;
        struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp);
 
-       REG_UPDATE_2(DCSURF_SURFACE_CONTROL,
+       REG_UPDATE_4(DCSURF_SURFACE_CONTROL,
                        PRIMARY_SURFACE_DCC_EN, dcc_en,
-                       PRIMARY_SURFACE_DCC_IND_64B_BLK, dcc_ind_64b_blk);
+                       PRIMARY_SURFACE_DCC_IND_64B_BLK, dcc_ind_64b_blk,
+                       SECONDARY_SURFACE_DCC_EN, dcc_en,
+                       SECONDARY_SURFACE_DCC_IND_64B_BLK, dcc_ind_64b_blk);
 }
 
 void hubp1_program_surface_config(
index af384034398f0bde6f5db3896eb49bbc599df0fd..d901d5092969d6897022243cea08b6351caaa0f1 100644 (file)
        HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, PRIMARY_META_SURFACE_TMZ_C, mask_sh),\
        HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, PRIMARY_SURFACE_DCC_EN, mask_sh),\
        HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, PRIMARY_SURFACE_DCC_IND_64B_BLK, mask_sh),\
+       HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, SECONDARY_SURFACE_TMZ, mask_sh),\
+       HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, SECONDARY_SURFACE_TMZ_C, mask_sh),\
+       HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, SECONDARY_META_SURFACE_TMZ, mask_sh),\
+       HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, SECONDARY_META_SURFACE_TMZ_C, mask_sh),\
+       HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, SECONDARY_SURFACE_DCC_EN, mask_sh),\
+       HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, SECONDARY_SURFACE_DCC_IND_64B_BLK, mask_sh),\
        HUBP_SF(HUBPRET0_HUBPRET_CONTROL, DET_BUF_PLANE1_BASE_ADDRESS, mask_sh),\
        HUBP_SF(HUBPRET0_HUBPRET_CONTROL, CROSSBAR_SRC_CB_B, mask_sh),\
        HUBP_SF(HUBPRET0_HUBPRET_CONTROL, CROSSBAR_SRC_CR_R, mask_sh),\
        type SECONDARY_META_SURFACE_TMZ_C;\
        type PRIMARY_SURFACE_DCC_EN;\
        type PRIMARY_SURFACE_DCC_IND_64B_BLK;\
+       type SECONDARY_SURFACE_DCC_EN;\
+       type SECONDARY_SURFACE_DCC_IND_64B_BLK;\
        type DET_BUF_PLANE1_BASE_ADDRESS;\
        type CROSSBAR_SRC_CB_B;\
        type CROSSBAR_SRC_CR_R;\
index 653b7b2efe2e4b33ac9b96384b6cd9e4a9d709a2..c928ee4cd3826dbd813132cc2b074e4f6b5815c2 100644 (file)
@@ -319,6 +319,10 @@ void enc1_stream_encoder_dp_set_stream_attribute(
                REG_UPDATE(DP_PIXEL_FORMAT, DP_COMPONENT_DEPTH,
                                DP_COMPONENT_PIXEL_DEPTH_12BPC);
                break;
+       case COLOR_DEPTH_161616:
+               REG_UPDATE(DP_PIXEL_FORMAT, DP_COMPONENT_DEPTH,
+                               DP_COMPONENT_PIXEL_DEPTH_16BPC);
+               break;
        default:
                REG_UPDATE(DP_PIXEL_FORMAT, DP_COMPONENT_DEPTH,
                                DP_COMPONENT_PIXEL_DEPTH_6BPC);
index bb0d4ebba9f081289a9dc08184f85f57a6fed54a..a981b3e99ab39f0b973ae19437010c31e63466a6 100644 (file)
@@ -496,6 +496,8 @@ static inline int dc_fixpt_ceil(struct fixed31_32 arg)
  * fractional
  */
 
+unsigned int dc_fixpt_u3d19(struct fixed31_32 arg);
+
 unsigned int dc_fixpt_u2d19(struct fixed31_32 arg);
 
 unsigned int dc_fixpt_u0d19(struct fixed31_32 arg);
index 88f7c69df6b9649a75ab48db7aa794c8b9cac3fd..06fac509e987358fc491f6e2e7b48b2d531f8bde 100644 (file)
 /* DF_CS_AON0_DramBaseAddress0 */
 #define DF_CS_UMC_AON0_DramBaseAddress0__AddrRngVal__SHIFT                                             0x0
 #define DF_CS_UMC_AON0_DramBaseAddress0__LgcyMmioHoleEn__SHIFT                                         0x1
-#define DF_CS_UMC_AON0_DramBaseAddress0__IntLvNumChan__SHIFT                                           0x4
-#define DF_CS_UMC_AON0_DramBaseAddress0__IntLvAddrSel__SHIFT                                           0x8
+#define DF_CS_UMC_AON0_DramBaseAddress0__IntLvNumChan__SHIFT                                           0x2
+#define DF_CS_UMC_AON0_DramBaseAddress0__IntLvAddrSel__SHIFT                                           0x9
 #define DF_CS_UMC_AON0_DramBaseAddress0__DramBaseAddr__SHIFT                                           0xc
 #define DF_CS_UMC_AON0_DramBaseAddress0__AddrRngVal_MASK                                               0x00000001L
 #define DF_CS_UMC_AON0_DramBaseAddress0__LgcyMmioHoleEn_MASK                                           0x00000002L
-#define DF_CS_UMC_AON0_DramBaseAddress0__IntLvNumChan_MASK                                             0x000000F0L
-#define DF_CS_UMC_AON0_DramBaseAddress0__IntLvAddrSel_MASK                                             0x00000700L
+#define DF_CS_UMC_AON0_DramBaseAddress0__IntLvNumChan_MASK                                             0x0000003CL
+#define DF_CS_UMC_AON0_DramBaseAddress0__IntLvAddrSel_MASK                                             0x00000E00L
 #define DF_CS_UMC_AON0_DramBaseAddress0__DramBaseAddr_MASK                                             0xFFFFF000L
 
 #endif
index c6c1666ac1201c65a5646eb66aa6a88c2a592509..092d800b703a7627a2b98fdda7be54b5b6f7ff11 100644 (file)
@@ -2026,17 +2026,15 @@ enum atom_smu11_syspll_id {
   SMU11_SYSPLL3_1_ID          = 6,
 };
 
-
 enum atom_smu11_syspll0_clock_id {
-  SMU11_SYSPLL0_SOCCLK_ID   = 0,       //      SOCCLK
-  SMU11_SYSPLL0_MP0CLK_ID   = 1,       //      MP0CLK
-  SMU11_SYSPLL0_DCLK_ID     = 2,       //      DCLK
-  SMU11_SYSPLL0_VCLK_ID     = 3,       //      VCLK
-  SMU11_SYSPLL0_ECLK_ID     = 4,       //      ECLK
+  SMU11_SYSPLL0_ECLK_ID     = 0,       //      ECLK
+  SMU11_SYSPLL0_SOCCLK_ID   = 1,       //      SOCCLK
+  SMU11_SYSPLL0_MP0CLK_ID   = 2,       //      MP0CLK
+  SMU11_SYSPLL0_DCLK_ID     = 3,       //      DCLK
+  SMU11_SYSPLL0_VCLK_ID     = 4,       //      VCLK
   SMU11_SYSPLL0_DCEFCLK_ID  = 5,       //      DCEFCLK
 };
 
-
 enum atom_smu11_syspll1_0_clock_id {
   SMU11_SYSPLL1_0_UCLKA_ID   = 0,       // UCLK_a
 };
index b493369e6d0f9daac4bf28777b6461917937eac9..d567be49c31b8c6e346dba9f65a7dbc955f05db7 100644 (file)
@@ -180,7 +180,6 @@ static int pp_late_init(void *handle)
 {
        struct amdgpu_device *adev = handle;
        struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle;
-       int ret;
 
        if (hwmgr && hwmgr->pm_en) {
                mutex_lock(&hwmgr->smu_lock);
@@ -191,13 +190,6 @@ static int pp_late_init(void *handle)
        if (adev->pm.smu_prv_buffer_size != 0)
                pp_reserve_vram_for_smu(adev);
 
-       if (hwmgr->hwmgr_func->gfx_off_control &&
-           (hwmgr->feature_mask & PP_GFXOFF_MASK)) {
-               ret = hwmgr->hwmgr_func->gfx_off_control(hwmgr, true);
-               if (ret)
-                       pr_err("gfx off enabling failed!\n");
-       }
-
        return 0;
 }
 
@@ -245,7 +237,7 @@ static int pp_set_powergating_state(void *handle,
        }
 
        if (hwmgr->hwmgr_func->enable_per_cu_power_gating == NULL) {
-               pr_info("%s was not implemented.\n", __func__);
+               pr_debug("%s was not implemented.\n", __func__);
                return 0;
        }
 
index e45a1fcc7f086e4e949668ac2b264652f809b591..91ffb7bc4ee72512f9a31aebbce9eaec3939d9d7 100644 (file)
@@ -265,19 +265,18 @@ int psm_adjust_power_state_dynamic(struct pp_hwmgr *hwmgr, bool skip,
        if (skip)
                return 0;
 
-       if (!hwmgr->ps)
-               /*
-                * for vega12/vega20 which does not support power state manager
-                * DAL clock limits should also be honoured
-                */
-               phm_apply_clock_adjust_rules(hwmgr);
-
        phm_pre_display_configuration_changed(hwmgr);
 
        phm_display_configuration_changed(hwmgr);
 
        if (hwmgr->ps)
                power_state_management(hwmgr, new_ps);
+       else
+               /*
+                * for vega12/vega20 which does not support power state manager
+                * DAL clock limits should also be honoured
+                */
+               phm_apply_clock_adjust_rules(hwmgr);
 
        phm_notify_smc_display_config_after_ps_adjustment(hwmgr);
 
index c97b0e5ba43b68395ccf0919900b896ffbea069f..5325661fedffb9480b26fb7b94269a30fb32334a 100644 (file)
@@ -496,7 +496,9 @@ int pp_atomfwctrl_get_clk_information_by_clkid(struct pp_hwmgr *hwmgr, BIOS_CLKI
        uint32_t ix;
 
        parameters.clk_id = id;
+       parameters.syspll_id = 0;
        parameters.command = GET_SMU_CLOCK_INFO_V3_1_GET_CLOCK_FREQ;
+       parameters.dfsdid = 0;
 
        ix = GetIndexIntoMasterCmdTable(getsmuclockinfo);
 
@@ -505,7 +507,7 @@ int pp_atomfwctrl_get_clk_information_by_clkid(struct pp_hwmgr *hwmgr, BIOS_CLKI
                return -EINVAL;
 
        output = (struct atom_get_smu_clock_info_output_parameters_v3_1 *)&parameters;
-       *frequency = output->atom_smu_outputclkfreq.smu_clock_freq_hz / 10000;
+       *frequency = le32_to_cpu(output->atom_smu_outputclkfreq.smu_clock_freq_hz) / 10000;
 
        return 0;
 }
index f0d48b183d22c7fe72bead64356c1fdc49c8a37c..35bd9870ab10811cd46c79adc3d8020267e828cd 100644 (file)
@@ -870,12 +870,6 @@ static int init_over_drive_limits(
        hwmgr->platform_descriptor.maxOverdriveVDDC = 0;
        hwmgr->platform_descriptor.overdriveVDDCStep = 0;
 
-       if (hwmgr->platform_descriptor.overdriveLimit.engineClock == 0 \
-               || hwmgr->platform_descriptor.overdriveLimit.memoryClock == 0) {
-               hwmgr->od_enabled = false;
-               pr_debug("OverDrive feature not support by VBIOS\n");
-       }
-
        return 0;
 }
 
index ce64dfabd34bd0cd40cf194c56156f1630d15098..925e17104f9092cd1f343591a524a906c20d1b80 100644 (file)
@@ -1074,12 +1074,6 @@ static int init_overdrive_limits(struct pp_hwmgr *hwmgr,
                                powerplay_table,
                                (const ATOM_FIRMWARE_INFO_V2_1 *)fw_info);
 
-       if (hwmgr->platform_descriptor.overdriveLimit.engineClock == 0
-               && hwmgr->platform_descriptor.overdriveLimit.memoryClock == 0) {
-               hwmgr->od_enabled = false;
-               pr_debug("OverDrive feature not support by VBIOS\n");
-       }
-
        return result;
 }
 
index 85f84f4d8be570d20e5e50694e33cbf6e53e7288..d4bc83e813896903b33b22fca4dbed1b88b2c159 100644 (file)
@@ -53,8 +53,37 @@ static const unsigned long SMU10_Magic = (unsigned long) PHM_Rv_Magic;
 
 
 static int smu10_display_clock_voltage_request(struct pp_hwmgr *hwmgr,
-               struct pp_display_clock_request *clock_req);
+               struct pp_display_clock_request *clock_req)
+{
+       struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);
+       enum amd_pp_clock_type clk_type = clock_req->clock_type;
+       uint32_t clk_freq = clock_req->clock_freq_in_khz / 1000;
+       PPSMC_Msg        msg;
 
+       switch (clk_type) {
+       case amd_pp_dcf_clock:
+               if (clk_freq == smu10_data->dcf_actual_hard_min_freq)
+                       return 0;
+               msg =  PPSMC_MSG_SetHardMinDcefclkByFreq;
+               smu10_data->dcf_actual_hard_min_freq = clk_freq;
+               break;
+       case amd_pp_soc_clock:
+                msg = PPSMC_MSG_SetHardMinSocclkByFreq;
+               break;
+       case amd_pp_f_clock:
+               if (clk_freq == smu10_data->f_actual_hard_min_freq)
+                       return 0;
+               smu10_data->f_actual_hard_min_freq = clk_freq;
+               msg = PPSMC_MSG_SetHardMinFclkByFreq;
+               break;
+       default:
+               pr_info("[DisplayClockVoltageRequest]Invalid Clock Type!");
+               return -EINVAL;
+       }
+       smum_send_msg_to_smc_with_parameter(hwmgr, msg, clk_freq);
+
+       return 0;
+}
 
 static struct smu10_power_state *cast_smu10_ps(struct pp_hw_power_state *hw_ps)
 {
@@ -284,7 +313,7 @@ static int smu10_disable_gfx_off(struct pp_hwmgr *hwmgr)
 
 static int smu10_disable_dpm_tasks(struct pp_hwmgr *hwmgr)
 {
-       return smu10_disable_gfx_off(hwmgr);
+       return 0;
 }
 
 static int smu10_enable_gfx_off(struct pp_hwmgr *hwmgr)
@@ -299,7 +328,7 @@ static int smu10_enable_gfx_off(struct pp_hwmgr *hwmgr)
 
 static int smu10_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
 {
-       return smu10_enable_gfx_off(hwmgr);
+       return 0;
 }
 
 static int smu10_gfx_off_control(struct pp_hwmgr *hwmgr, bool enable)
@@ -1000,6 +1029,12 @@ static int smu10_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr,
        case amd_pp_soc_clock:
                pclk_vol_table = pinfo->vdd_dep_on_socclk;
                break;
+       case amd_pp_disp_clock:
+               pclk_vol_table = pinfo->vdd_dep_on_dispclk;
+               break;
+       case amd_pp_phy_clock:
+               pclk_vol_table = pinfo->vdd_dep_on_phyclk;
+               break;
        default:
                return -EINVAL;
        }
@@ -1017,39 +1052,7 @@ static int smu10_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr,
        return 0;
 }
 
-static int smu10_display_clock_voltage_request(struct pp_hwmgr *hwmgr,
-               struct pp_display_clock_request *clock_req)
-{
-       struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend);
-       enum amd_pp_clock_type clk_type = clock_req->clock_type;
-       uint32_t clk_freq = clock_req->clock_freq_in_khz / 1000;
-       PPSMC_Msg        msg;
 
-       switch (clk_type) {
-       case amd_pp_dcf_clock:
-               if (clk_freq == smu10_data->dcf_actual_hard_min_freq)
-                       return 0;
-               msg =  PPSMC_MSG_SetHardMinDcefclkByFreq;
-               smu10_data->dcf_actual_hard_min_freq = clk_freq;
-               break;
-       case amd_pp_soc_clock:
-                msg = PPSMC_MSG_SetHardMinSocclkByFreq;
-               break;
-       case amd_pp_f_clock:
-               if (clk_freq == smu10_data->f_actual_hard_min_freq)
-                       return 0;
-               smu10_data->f_actual_hard_min_freq = clk_freq;
-               msg = PPSMC_MSG_SetHardMinFclkByFreq;
-               break;
-       default:
-               pr_info("[DisplayClockVoltageRequest]Invalid Clock Type!");
-               return -EINVAL;
-       }
-
-       smum_send_msg_to_smc_with_parameter(hwmgr, msg, clk_freq);
-
-       return 0;
-}
 
 static int smu10_get_max_high_clocks(struct pp_hwmgr *hwmgr, struct amd_pp_simple_clock_info *clocks)
 {
@@ -1182,6 +1185,7 @@ static const struct pp_hwmgr_func smu10_hwmgr_funcs = {
        .set_mmhub_powergating_by_smu = smu10_set_mmhub_powergating_by_smu,
        .smus_notify_pwe = smu10_smus_notify_pwe,
        .gfx_off_control = smu10_gfx_off_control,
+       .display_clock_voltage_request = smu10_display_clock_voltage_request,
 };
 
 int smu10_init_function_pointers(struct pp_hwmgr *hwmgr)
index 45e9b8cb169d8f6408b038c1bc1e32935417b54a..f8e866ceda02222a7c59e92a2d63cec1c4ea9dde 100644 (file)
@@ -791,7 +791,8 @@ static int smu7_setup_dpm_tables_v1(struct pp_hwmgr *hwmgr)
                        data->dpm_table.sclk_table.count++;
                }
        }
-
+       if (hwmgr->platform_descriptor.overdriveLimit.engineClock == 0)
+               hwmgr->platform_descriptor.overdriveLimit.engineClock = dep_sclk_table->entries[i-1].clk;
        /* Initialize Mclk DPM table based on allow Mclk values */
        data->dpm_table.mclk_table.count = 0;
        for (i = 0; i < dep_mclk_table->count; i++) {
@@ -806,6 +807,8 @@ static int smu7_setup_dpm_tables_v1(struct pp_hwmgr *hwmgr)
                }
        }
 
+       if (hwmgr->platform_descriptor.overdriveLimit.memoryClock == 0)
+               hwmgr->platform_descriptor.overdriveLimit.memoryClock = dep_mclk_table->entries[i-1].clk;
        return 0;
 }
 
@@ -3752,14 +3755,17 @@ static int smu7_trim_dpm_states(struct pp_hwmgr *hwmgr,
 static int smu7_generate_dpm_level_enable_mask(
                struct pp_hwmgr *hwmgr, const void *input)
 {
-       int result;
+       int result = 0;
        const struct phm_set_power_state_input *states =
                        (const struct phm_set_power_state_input *)input;
        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
        const struct smu7_power_state *smu7_ps =
                        cast_const_phw_smu7_power_state(states->pnew_state);
 
-       result = smu7_trim_dpm_states(hwmgr, smu7_ps);
+       /*skip the trim if od is enabled*/
+       if (!hwmgr->od_enabled)
+               result = smu7_trim_dpm_states(hwmgr, smu7_ps);
+
        if (result)
                return result;
 
index d156b7bb92ae74a3b9b899f2e3a7907c5b0410f0..05e680d55dbbe06a6c951aa33d599e2dd6584424 100644 (file)
@@ -321,8 +321,12 @@ static int vega10_odn_initial_default_setting(struct pp_hwmgr *hwmgr)
                odn_table->min_vddc = dep_table[0]->entries[0].vddc;
 
        i = od_table[2]->count - 1;
-       od_table[2]->entries[i].clk = hwmgr->platform_descriptor.overdriveLimit.memoryClock;
-       od_table[2]->entries[i].vddc = odn_table->max_vddc;
+       od_table[2]->entries[i].clk = hwmgr->platform_descriptor.overdriveLimit.memoryClock > od_table[2]->entries[i].clk ?
+                                       hwmgr->platform_descriptor.overdriveLimit.memoryClock :
+                                       od_table[2]->entries[i].clk;
+       od_table[2]->entries[i].vddc = odn_table->max_vddc > od_table[2]->entries[i].vddc ?
+                                       odn_table->max_vddc :
+                                       od_table[2]->entries[i].vddc;
 
        return 0;
 }
@@ -1311,6 +1315,9 @@ static int vega10_setup_default_dpm_tables(struct pp_hwmgr *hwmgr)
        vega10_setup_default_single_dpm_table(hwmgr,
                        dpm_table,
                        dep_gfx_table);
+       if (hwmgr->platform_descriptor.overdriveLimit.engineClock == 0)
+               hwmgr->platform_descriptor.overdriveLimit.engineClock =
+                                       dpm_table->dpm_levels[dpm_table->count-1].value;
        vega10_init_dpm_state(&(dpm_table->dpm_state));
 
        /* Initialize Mclk DPM table based on allow Mclk values */
@@ -1319,6 +1326,10 @@ static int vega10_setup_default_dpm_tables(struct pp_hwmgr *hwmgr)
        vega10_setup_default_single_dpm_table(hwmgr,
                        dpm_table,
                        dep_mclk_table);
+       if (hwmgr->platform_descriptor.overdriveLimit.memoryClock == 0)
+               hwmgr->platform_descriptor.overdriveLimit.memoryClock =
+                                       dpm_table->dpm_levels[dpm_table->count-1].value;
+
        vega10_init_dpm_state(&(dpm_table->dpm_state));
 
        data->dpm_table.eclk_table.count = 0;
index a9efd8554fbc2ffb103643b3a80683966c74f4b2..dbe4b1f66784961ea028b3fcfee564e830617f80 100644 (file)
@@ -1104,7 +1104,7 @@ static int vega10_enable_psm_gc_edc_config(struct pp_hwmgr *hwmgr)
        for (count = 0; count < num_se; count++) {
                data = GRBM_GFX_INDEX__INSTANCE_BROADCAST_WRITES_MASK | GRBM_GFX_INDEX__SH_BROADCAST_WRITES_MASK | ( count << GRBM_GFX_INDEX__SE_INDEX__SHIFT);
                WREG32_SOC15(GC, 0, mmGRBM_GFX_INDEX, data);
-               result |= vega10_program_didt_config_registers(hwmgr, PSMSEEDCStallPatternConfig_Vega10, VEGA10_CONFIGREG_DIDT);
+               result = vega10_program_didt_config_registers(hwmgr, PSMSEEDCStallPatternConfig_Vega10, VEGA10_CONFIGREG_DIDT);
                result |= vega10_program_didt_config_registers(hwmgr, PSMSEEDCStallDelayConfig_Vega10, VEGA10_CONFIGREG_DIDT);
                result |= vega10_program_didt_config_registers(hwmgr, PSMSEEDCCtrlResetConfig_Vega10, VEGA10_CONFIGREG_DIDT);
                result |= vega10_program_didt_config_registers(hwmgr, PSMSEEDCCtrlConfig_Vega10, VEGA10_CONFIGREG_DIDT);
index 0768d259c07c335f51971c634ac2bd41e014f12a..16b1a9cf6cf08219db8b4724cb29a55d8bef68f4 100644 (file)
@@ -267,12 +267,6 @@ static int init_over_drive_limits(
        hwmgr->platform_descriptor.maxOverdriveVDDC = 0;
        hwmgr->platform_descriptor.overdriveVDDCStep = 0;
 
-       if (hwmgr->platform_descriptor.overdriveLimit.engineClock == 0 ||
-               hwmgr->platform_descriptor.overdriveLimit.memoryClock == 0) {
-               hwmgr->od_enabled = false;
-               pr_debug("OverDrive feature not support by VBIOS\n");
-       }
-
        return 0;
 }
 
index df1578d6f42e65f05300eaeef866b698585e5591..44d480768dfe2d202790ee4a3303e55d348af783 100644 (file)
@@ -349,8 +349,13 @@ static bool drm_sched_entity_add_dependency_cb(struct drm_sched_entity *entity)
        struct dma_fence * fence = entity->dependency;
        struct drm_sched_fence *s_fence;
 
-       if (fence->context == entity->fence_context) {
-               /* We can ignore fences from ourself */
+       if (fence->context == entity->fence_context ||
+            fence->context == entity->fence_context + 1) {
+                /*
+                 * Fence is a scheduled/finished fence from a job
+                 * which belongs to the same entity, we can ignore
+                 * fences from ourself
+                 */
                dma_fence_put(entity->dependency);
                return false;
        }
index c987c826daa30fcc066ef01cffd5e5dafc86317b..0426d66660d1c549bcc4c249aec60135025575ed 100644 (file)
@@ -2,7 +2,6 @@ config DRM_SHMOBILE
        tristate "DRM Support for SH Mobile"
        depends on DRM && ARM
        depends on ARCH_SHMOBILE || COMPILE_TEST
-       depends on FB_SH_MOBILE_MERAM || !FB_SH_MOBILE_MERAM
        select BACKLIGHT_CLASS_DEVICE
        select BACKLIGHT_LCD_SUPPORT
        select DRM_KMS_HELPER
index e7738939a86dc9f3f8b9c21825f79536f233beb2..40df8887fc1765e3452f5490ccf9fc242f614cbc 100644 (file)
@@ -21,8 +21,6 @@
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_plane_helper.h>
 
-#include <video/sh_mobile_meram.h>
-
 #include "shmob_drm_backlight.h"
 #include "shmob_drm_crtc.h"
 #include "shmob_drm_drv.h"
@@ -47,20 +45,12 @@ static int shmob_drm_clk_on(struct shmob_drm_device *sdev)
                if (ret < 0)
                        return ret;
        }
-#if 0
-       if (sdev->meram_dev && sdev->meram_dev->pdev)
-               pm_runtime_get_sync(&sdev->meram_dev->pdev->dev);
-#endif
 
        return 0;
 }
 
 static void shmob_drm_clk_off(struct shmob_drm_device *sdev)
 {
-#if 0
-       if (sdev->meram_dev && sdev->meram_dev->pdev)
-               pm_runtime_put_sync(&sdev->meram_dev->pdev->dev);
-#endif
        if (sdev->clock)
                clk_disable_unprepare(sdev->clock);
 }
@@ -269,12 +259,6 @@ static void shmob_drm_crtc_stop(struct shmob_drm_crtc *scrtc)
        if (!scrtc->started)
                return;
 
-       /* Disable the MERAM cache. */
-       if (scrtc->cache) {
-               sh_mobile_meram_cache_free(sdev->meram, scrtc->cache);
-               scrtc->cache = NULL;
-       }
-
        /* Stop the LCDC. */
        shmob_drm_crtc_start_stop(scrtc, false);
 
@@ -305,7 +289,6 @@ static void shmob_drm_crtc_compute_base(struct shmob_drm_crtc *scrtc,
 {
        struct drm_crtc *crtc = &scrtc->crtc;
        struct drm_framebuffer *fb = crtc->primary->fb;
-       struct shmob_drm_device *sdev = crtc->dev->dev_private;
        struct drm_gem_cma_object *gem;
        unsigned int bpp;
 
@@ -321,11 +304,6 @@ static void shmob_drm_crtc_compute_base(struct shmob_drm_crtc *scrtc,
                              + y / (bpp == 4 ? 2 : 1) * fb->pitches[1]
                              + x * (bpp == 16 ? 2 : 1);
        }
-
-       if (scrtc->cache)
-               sh_mobile_meram_cache_update(sdev->meram, scrtc->cache,
-                                            scrtc->dma[0], scrtc->dma[1],
-                                            &scrtc->dma[0], &scrtc->dma[1]);
 }
 
 static void shmob_drm_crtc_update_base(struct shmob_drm_crtc *scrtc)
@@ -372,9 +350,7 @@ static int shmob_drm_crtc_mode_set(struct drm_crtc *crtc,
 {
        struct shmob_drm_crtc *scrtc = to_shmob_crtc(crtc);
        struct shmob_drm_device *sdev = crtc->dev->dev_private;
-       const struct sh_mobile_meram_cfg *mdata = sdev->pdata->meram;
        const struct shmob_drm_format_info *format;
-       void *cache;
 
        format = shmob_drm_format_info(crtc->primary->fb->format->format);
        if (format == NULL) {
@@ -386,24 +362,6 @@ static int shmob_drm_crtc_mode_set(struct drm_crtc *crtc,
        scrtc->format = format;
        scrtc->line_size = crtc->primary->fb->pitches[0];
 
-       if (sdev->meram) {
-               /* Enable MERAM cache if configured. We need to de-init
-                * configured ICBs before we can re-initialize them.
-                */
-               if (scrtc->cache) {
-                       sh_mobile_meram_cache_free(sdev->meram, scrtc->cache);
-                       scrtc->cache = NULL;
-               }
-
-               cache = sh_mobile_meram_cache_alloc(sdev->meram, mdata,
-                                                   crtc->primary->fb->pitches[0],
-                                                   adjusted_mode->vdisplay,
-                                                   format->meram,
-                                                   &scrtc->line_size);
-               if (!IS_ERR(cache))
-                       scrtc->cache = cache;
-       }
-
        shmob_drm_crtc_compute_base(scrtc, x, y);
 
        return 0;
index f152973df11c9859d36df6366ad4e34aea213291..c11f421737dc413db9b99579e23b5e2147a51dca 100644 (file)
@@ -28,7 +28,6 @@ struct shmob_drm_crtc {
        int dpms;
 
        const struct shmob_drm_format_info *format;
-       void *cache;
        unsigned long dma[2];
        unsigned int line_size;
        bool started;
index 02ea315ba69ac3a7ec16c5dd2184aaf93f856b74..088a6e55fa29dd3e14f3096a7606d882889c3b52 100644 (file)
@@ -23,7 +23,6 @@
 struct clk;
 struct device;
 struct drm_device;
-struct sh_mobile_meram_info;
 
 struct shmob_drm_device {
        struct device *dev;
@@ -31,7 +30,6 @@ struct shmob_drm_device {
 
        void __iomem *mmio;
        struct clk *clock;
-       struct sh_mobile_meram_info *meram;
        u32 lddckr;
        u32 ldmt1r;
 
index d36919b14da76bacf8b23e8e9a92f8b5fb90c89a..447638581c08037c4b3f3458e23ef710b2cd9a10 100644 (file)
@@ -18,8 +18,6 @@
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 
-#include <video/sh_mobile_meram.h>
-
 #include "shmob_drm_crtc.h"
 #include "shmob_drm_drv.h"
 #include "shmob_drm_kms.h"
@@ -35,55 +33,46 @@ static const struct shmob_drm_format_info shmob_drm_format_infos[] = {
                .bpp = 16,
                .yuv = false,
                .lddfr = LDDFR_PKF_RGB16,
-               .meram = SH_MOBILE_MERAM_PF_RGB,
        }, {
                .fourcc = DRM_FORMAT_RGB888,
                .bpp = 24,
                .yuv = false,
                .lddfr = LDDFR_PKF_RGB24,
-               .meram = SH_MOBILE_MERAM_PF_RGB,
        }, {
                .fourcc = DRM_FORMAT_ARGB8888,
                .bpp = 32,
                .yuv = false,
                .lddfr = LDDFR_PKF_ARGB32,
-               .meram = SH_MOBILE_MERAM_PF_RGB,
        }, {
                .fourcc = DRM_FORMAT_NV12,
                .bpp = 12,
                .yuv = true,
                .lddfr = LDDFR_CC | LDDFR_YF_420,
-               .meram = SH_MOBILE_MERAM_PF_NV,
        }, {
                .fourcc = DRM_FORMAT_NV21,
                .bpp = 12,
                .yuv = true,
                .lddfr = LDDFR_CC | LDDFR_YF_420,
-               .meram = SH_MOBILE_MERAM_PF_NV,
        }, {
                .fourcc = DRM_FORMAT_NV16,
                .bpp = 16,
                .yuv = true,
                .lddfr = LDDFR_CC | LDDFR_YF_422,
-               .meram = SH_MOBILE_MERAM_PF_NV,
        }, {
                .fourcc = DRM_FORMAT_NV61,
                .bpp = 16,
                .yuv = true,
                .lddfr = LDDFR_CC | LDDFR_YF_422,
-               .meram = SH_MOBILE_MERAM_PF_NV,
        }, {
                .fourcc = DRM_FORMAT_NV24,
                .bpp = 24,
                .yuv = true,
                .lddfr = LDDFR_CC | LDDFR_YF_444,
-               .meram = SH_MOBILE_MERAM_PF_NV24,
        }, {
                .fourcc = DRM_FORMAT_NV42,
                .bpp = 24,
                .yuv = true,
                .lddfr = LDDFR_CC | LDDFR_YF_444,
-               .meram = SH_MOBILE_MERAM_PF_NV24,
        },
 };
 
index 06d5b7caa0265d64b54913fe2bddf84ea8c3bbc1..753e2817dc2c73011a10b4afb3bf987068d83abe 100644 (file)
@@ -24,7 +24,6 @@ struct shmob_drm_format_info {
        unsigned int bpp;
        bool yuv;
        u32 lddfr;
-       unsigned int meram;
 };
 
 const struct shmob_drm_format_info *shmob_drm_format_info(u32 fourcc);
index 97f6e4a3eb0de0e86634cb4c4d9d3c2501b5dfab..1d0359f713ca4223ac8c568d63d3d9dd2f815f0a 100644 (file)
@@ -17,8 +17,6 @@
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 
-#include <video/sh_mobile_meram.h>
-
 #include "shmob_drm_drv.h"
 #include "shmob_drm_kms.h"
 #include "shmob_drm_plane.h"
index 29437eabe0957d67893808ed7d668f54770c3fd7..b677e5d524e698234f2af458c73b07cf4a22f116 100644 (file)
@@ -6,7 +6,7 @@ config VGA_ARB
          Some "legacy" VGA devices implemented on PCI typically have the same
          hard-decoded addresses as they did on ISA. When multiple PCI devices
          are accessed at same time they need some kind of coordination. Please
-         see Documentation/vgaarbiter.txt for more details. Select this to
+         see Documentation/gpu/vgaarbiter.rst for more details. Select this to
          enable VGA arbiter.
 
 config VGA_ARB_MAX_GPUS
index 1c5e74cb9279bbbea68b220b233c16cc4403f02e..c61b045557798e073778ba1efcb786f6bc3c946e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * vgaarb.c: Implements the VGA arbitration. For details refer to
- * Documentation/vgaarbiter.txt
+ * Documentation/gpu/vgaarbiter.rst
  *
  *
  * (C) Copyright 2005 Benjamin Herrenschmidt <benh@kernel.crashing.org>
index 0108c5991a0417679d04a9d048d757d9e3f178f4..e50d8fe4d36c58f3715ba72932a682fc36c75654 100644 (file)
@@ -14,7 +14,7 @@ config USB_HID
 
          You can't use this driver and the HIDBP (Boot Protocol) keyboard
          and mouse drivers at the same time. More information is available:
-         <file:Documentation/input/input.txt>.
+         <file:Documentation/input/input.rst>.
 
          If unsure, say Y.
 
index 3df0efd69ae336035c8f6994ef3230f6cff920f6..4a34f311e1ff4df2cd6cdfcff7ea1662c95a06eb 100644 (file)
@@ -519,9 +519,7 @@ static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
                        }
                }
        } else {                /* normal 7bit address  */
-               addr = msg->addr << 1;
-               if (flags & I2C_M_RD)
-                       addr |= 1;
+               addr = i2c_8bit_addr_from_msg(msg);
                if (flags & I2C_M_REV_DIR_ADDR)
                        addr ^= 1;
                ret = try_address(i2c_adap, addr, retries);
index e370804ec8bc62d10830eadba8ac93f7af50aedd..883a290f6a4d05f29fc1919f4d68f1d4c089eb6e 100644 (file)
@@ -112,11 +112,8 @@ static int pca_address(struct i2c_algo_pca_data *adap,
                       struct i2c_msg *msg)
 {
        int sta = pca_get_con(adap);
-       int addr;
+       int addr = i2c_8bit_addr_from_msg(msg);
 
-       addr = ((0x7f & msg->addr) << 1);
-       if (msg->flags & I2C_M_RD)
-               addr |= 1;
        DEB2("=== SLAVE ADDRESS %#04x+%c=%#04x\n",
             msg->addr, msg->flags & I2C_M_RD ? 'R' : 'W', addr);
 
index 270d84bfc2c68b526d6b8119afa67f4cb3c37543..5c29a4d397cff2a7860c6511a2fbee820945b4ed 100644 (file)
@@ -291,13 +291,9 @@ static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf,
 static int pcf_doAddress(struct i2c_algo_pcf_data *adap,
                         struct i2c_msg *msg)
 {
-       unsigned short flags = msg->flags;
-       unsigned char addr;
+       unsigned char addr = i2c_8bit_addr_from_msg(msg);
 
-       addr = msg->addr << 1;
-       if (flags & I2C_M_RD)
-               addr |= 1;
-       if (flags & I2C_M_REV_DIR_ADDR)
+       if (msg->flags & I2C_M_REV_DIR_ADDR)
                addr ^= 1;
        i2c_outb(adap, addr);
 
index fce9f2ca0570d50cb9a3c336686e19931b04c3ab..4f8df2ec87b1b360d0bfefeb796c065edd348a61 100644 (file)
@@ -943,6 +943,7 @@ config I2C_STM32F4
 config I2C_STM32F7
        tristate "STMicroelectronics STM32F7 I2C support"
        depends on ARCH_STM32 || COMPILE_TEST
+       select I2C_SLAVE
        help
          Enable this option to add support for STM32 I2C controller embedded
          in STM32F7 SoCs.
index 189e34ba050f81fe16844e9a1511d859bf29a165..5a869144a0c5cdc942584153c68570db3892c702 100644 (file)
@@ -94,7 +94,8 @@ obj-$(CONFIG_I2C_SIRF)                += i2c-sirf.o
 obj-$(CONFIG_I2C_SPRD)         += i2c-sprd.o
 obj-$(CONFIG_I2C_ST)           += i2c-st.o
 obj-$(CONFIG_I2C_STM32F4)      += i2c-stm32f4.o
-obj-$(CONFIG_I2C_STM32F7)      += i2c-stm32f7.o
+i2c-stm32f7-drv-objs := i2c-stm32f7.o i2c-stm32.o
+obj-$(CONFIG_I2C_STM32F7)      += i2c-stm32f7-drv.o
 obj-$(CONFIG_I2C_STU300)       += i2c-stu300.o
 obj-$(CONFIG_I2C_SUN6I_P2WI)   += i2c-sun6i-p2wi.o
 obj-$(CONFIG_I2C_SYNQUACER)    += i2c-synquacer.o
index 7d4aeb4465b329847ad145772829ad3e92082159..60e4d0e939a3814ffe142edba612817de7590c48 100644 (file)
@@ -335,13 +335,12 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus)
 {
        u32 command = ASPEED_I2CD_M_START_CMD | ASPEED_I2CD_M_TX_CMD;
        struct i2c_msg *msg = &bus->msgs[bus->msgs_index];
-       u8 slave_addr = msg->addr << 1;
+       u8 slave_addr = i2c_8bit_addr_from_msg(msg);
 
        bus->master_state = ASPEED_I2C_MASTER_START;
        bus->buf_index = 0;
 
        if (msg->flags & I2C_M_RD) {
-               slave_addr |= 1;
                command |= ASPEED_I2CD_M_RX_CMD;
                /* Need to let the hardware know to NACK after RX. */
                if (msg->len == 1 && !(msg->flags & I2C_M_RECV_LEN))
index bfd1fdff64a97bd63ac36df280c264fbc598e132..3f3e8b3bf5ff9df550991d18530fe45f41c870d3 100644 (file)
@@ -518,8 +518,16 @@ static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id)
         * the RXRDY interrupt first in order to not keep garbage data in the
         * Receive Holding Register for the next transfer.
         */
-       if (irqstatus & AT91_TWI_RXRDY)
-               at91_twi_read_next_byte(dev);
+       if (irqstatus & AT91_TWI_RXRDY) {
+               /*
+                * Read all available bytes at once by polling RXRDY usable w/
+                * and w/o FIFO. With FIFO enabled we could also read RXFL and
+                * avoid polling RXRDY.
+                */
+               do {
+                       at91_twi_read_next_byte(dev);
+               } while (at91_twi_read(dev, AT91_TWI_SR) & AT91_TWI_RXRDY);
+       }
 
        /*
         * When a NACK condition is detected, the I2C controller sets the NACK,
index 13f07482ec68cedb1e24eb1d92ac6939a394a97f..8e60048a33f8f88b5e10cf48d0cfc3a84f781424 100644 (file)
@@ -351,13 +351,15 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
                 *   addr_2: addr[7:0]
                 */
                addr_1 = 0xF0 | ((msg->addr >> 7) & 0x06);
+               if (i2c_m_rd(msg))
+                       addr_1 |= 1;    /* Set the R/nW bit of the address */
                addr_2 = msg->addr & 0xFF;
        } else {
                /* 7-bit address
                 *   addr_1: addr[6:0] | (R/nW)
                 *   addr_2: dont care
                 */
-               addr_1 = (msg->addr << 1) & 0xFF;
+               addr_1 = i2c_8bit_addr_from_msg(msg);
                addr_2 = 0;
        }
 
@@ -365,7 +367,6 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
                /* I2C read transfer */
                rx_xfer = i2c_m_recv_len(msg) ? I2C_SMBUS_BLOCK_MAX : msg->len;
                tx_xfer = 0;
-               addr_1 |= 1;    /* Set the R/nW bit of the address */
        } else {
                /* I2C write transfer */
                rx_xfer = 0;
@@ -532,23 +533,23 @@ static int axxia_i2c_probe(struct platform_device *pdev)
        if (idev->bus_clk_rate == 0)
                idev->bus_clk_rate = 100000;    /* default clock rate */
 
+       ret = clk_prepare_enable(idev->i2c_clk);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to enable clock\n");
+               return ret;
+       }
+
        ret = axxia_i2c_init(idev);
        if (ret) {
                dev_err(&pdev->dev, "failed to initialize\n");
-               return ret;
+               goto error_disable_clk;
        }
 
        ret = devm_request_irq(&pdev->dev, irq, axxia_i2c_isr, 0,
                               pdev->name, idev);
        if (ret) {
                dev_err(&pdev->dev, "failed to claim IRQ%d\n", irq);
-               return ret;
-       }
-
-       ret = clk_prepare_enable(idev->i2c_clk);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to enable clock\n");
-               return ret;
+               goto error_disable_clk;
        }
 
        i2c_set_adapdata(&idev->adapter, idev);
@@ -563,12 +564,14 @@ static int axxia_i2c_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, idev);
 
        ret = i2c_add_adapter(&idev->adapter);
-       if (ret) {
-               clk_disable_unprepare(idev->i2c_clk);
-               return ret;
-       }
+       if (ret)
+               goto error_disable_clk;
 
        return 0;
+
+error_disable_clk:
+       clk_disable_unprepare(idev->i2c_clk);
+       return ret;
 }
 
 static int axxia_i2c_remove(struct platform_device *pdev)
index 27ebd90de43bb781208d66c0e43c29dce1ccd450..48914dfc8ce88ff54246a2f450ef2bc3ae9afe4d 100644 (file)
@@ -149,18 +149,17 @@ u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
        return ((ic_clk * (tLOW + tf) + 500000) / 1000000) - 1 + offset;
 }
 
-void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable)
-{
-       dw_writel(dev, enable, DW_IC_ENABLE);
-}
-
-void __i2c_dw_enable_and_wait(struct dw_i2c_dev *dev, bool enable)
+void __i2c_dw_disable(struct dw_i2c_dev *dev)
 {
        int timeout = 100;
 
        do {
-               __i2c_dw_enable(dev, enable);
-               if ((dw_readl(dev, DW_IC_ENABLE_STATUS) & 1) == enable)
+               __i2c_dw_disable_nowait(dev);
+               /*
+                * The enable status register may be unimplemented, but
+                * in that case this test reads zero and exits the loop.
+                */
+               if ((dw_readl(dev, DW_IC_ENABLE_STATUS) & 1) == 0)
                        return;
 
                /*
@@ -171,8 +170,7 @@ void __i2c_dw_enable_and_wait(struct dw_i2c_dev *dev, bool enable)
                usleep_range(25, 250);
        } while (timeout--);
 
-       dev_warn(dev->dev, "timeout in %sabling adapter\n",
-                enable ? "en" : "dis");
+       dev_warn(dev->dev, "timeout in disabling adapter\n");
 }
 
 unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev)
@@ -277,7 +275,7 @@ u32 i2c_dw_func(struct i2c_adapter *adap)
 void i2c_dw_disable(struct dw_i2c_dev *dev)
 {
        /* Disable controller */
-       __i2c_dw_enable_and_wait(dev, false);
+       __i2c_dw_disable(dev);
 
        /* Disable all interupts */
        dw_writel(dev, 0, DW_IC_INTR_MASK);
index 8707c76b2fee10b08e7957a137ff89b67ea095fe..d690e648bc015efcd96d63b81c11969e9a6ceaae 100644 (file)
@@ -297,8 +297,6 @@ u32 dw_readl(struct dw_i2c_dev *dev, int offset);
 void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset);
 u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset);
 u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset);
-void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable);
-void __i2c_dw_enable_and_wait(struct dw_i2c_dev *dev, bool enable);
 unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev);
 int i2c_dw_prepare_clk(struct dw_i2c_dev *dev, bool prepare);
 int i2c_dw_acquire_lock(struct dw_i2c_dev *dev);
@@ -309,6 +307,18 @@ u32 i2c_dw_func(struct i2c_adapter *adap);
 void i2c_dw_disable(struct dw_i2c_dev *dev);
 void i2c_dw_disable_int(struct dw_i2c_dev *dev);
 
+static inline void __i2c_dw_enable(struct dw_i2c_dev *dev)
+{
+       dw_writel(dev, 1, DW_IC_ENABLE);
+}
+
+static inline void __i2c_dw_disable_nowait(struct dw_i2c_dev *dev)
+{
+       dw_writel(dev, 0, DW_IC_ENABLE);
+}
+
+void __i2c_dw_disable(struct dw_i2c_dev *dev);
+
 extern u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev);
 extern int i2c_dw_probe(struct dw_i2c_dev *dev);
 #if IS_ENABLED(CONFIG_I2C_DESIGNWARE_SLAVE)
index 0cdba29ae0a9ad25212f21a56acf76f46c1b5213..27436a937492d1afdefe77264bcd1afaf7d91856 100644 (file)
@@ -81,7 +81,7 @@ static int i2c_dw_init_master(struct dw_i2c_dev *dev)
        comp_param1 = dw_readl(dev, DW_IC_COMP_PARAM_1);
 
        /* Disable the adapter */
-       __i2c_dw_enable_and_wait(dev, false);
+       __i2c_dw_disable(dev);
 
        /* Set standard and fast speed deviders for high/low periods */
 
@@ -180,7 +180,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
        u32 ic_con, ic_tar = 0;
 
        /* Disable the adapter */
-       __i2c_dw_enable_and_wait(dev, false);
+       __i2c_dw_disable(dev);
 
        /* If the slave address is ten bit address, enable 10BITADDR */
        ic_con = dw_readl(dev, DW_IC_CON);
@@ -209,7 +209,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
        i2c_dw_disable_int(dev);
 
        /* Enable the adapter */
-       __i2c_dw_enable(dev, true);
+       __i2c_dw_enable(dev);
 
        /* Dummy read to avoid the register getting stuck on Bay Trail */
        dw_readl(dev, DW_IC_ENABLE_STATUS);
@@ -462,7 +462,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
         * additional interrupts are a hardware bug or this driver doesn't
         * handle them correctly yet.
         */
-       __i2c_dw_enable(dev, false);
+       __i2c_dw_disable_nowait(dev);
 
        if (dev->msg_err) {
                ret = dev->msg_err;
index d42558d1b002ff6c23466e5cc60c49a7833bb438..8ce2cd36847717f72a6e2057d8a23922591b7050 100644 (file)
@@ -75,7 +75,7 @@ static int i2c_dw_init_slave(struct dw_i2c_dev *dev)
        comp_param1 = dw_readl(dev, DW_IC_COMP_PARAM_1);
 
        /* Disable the adapter. */
-       __i2c_dw_enable_and_wait(dev, false);
+       __i2c_dw_disable(dev);
 
        /* Configure SDA Hold Time if required. */
        reg = dw_readl(dev, DW_IC_COMP_VERSION);
@@ -119,11 +119,11 @@ static int i2c_dw_reg_slave(struct i2c_client *slave)
         * Set slave address in the IC_SAR register,
         * the address to which the DW_apb_i2c responds.
         */
-       __i2c_dw_enable(dev, false);
+       __i2c_dw_disable_nowait(dev);
        dw_writel(dev, slave->addr, DW_IC_SAR);
        dev->slave = slave;
 
-       __i2c_dw_enable(dev, true);
+       __i2c_dw_enable(dev);
 
        dev->cmd_err = 0;
        dev->msg_write_idx = 0;
index f718ee4e3332fe3ced0cf3abff9c59b21f56b99b..3f28317cde3935af5729e7ad7f816a64260ea267 100644 (file)
@@ -360,11 +360,11 @@ static int diolan_usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
                        if (ret < 0)
                                goto abort;
                }
+               ret = diolan_i2c_put_byte_ack(dev,
+                                             i2c_8bit_addr_from_msg(pmsg));
+               if (ret < 0)
+                       goto abort;
                if (pmsg->flags & I2C_M_RD) {
-                       ret =
-                           diolan_i2c_put_byte_ack(dev, (pmsg->addr << 1) | 1);
-                       if (ret < 0)
-                               goto abort;
                        for (j = 0; j < pmsg->len; j++) {
                                u8 byte;
                                bool ack = j < pmsg->len - 1;
@@ -393,9 +393,6 @@ static int diolan_usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
                                pmsg->buf[j] = byte;
                        }
                } else {
-                       ret = diolan_i2c_put_byte_ack(dev, pmsg->addr << 1);
-                       if (ret < 0)
-                               goto abort;
                        for (j = 0; j < pmsg->len; j++) {
                                ret = diolan_i2c_put_byte_ack(dev,
                                                              pmsg->buf[j]);
index aa336ba89aa3fe93ca07b224b851881ff98c9d92..5f2bab878b2cd34f88af4cd62ee7ce54b0d02ce4 100644 (file)
@@ -144,8 +144,7 @@ static void efm32_i2c_send_next_msg(struct efm32_i2c_ddata *ddata)
        struct i2c_msg *cur_msg = &ddata->msgs[ddata->current_msg];
 
        efm32_i2c_write32(ddata, REG_CMD, REG_CMD_START);
-       efm32_i2c_write32(ddata, REG_TXDATA, cur_msg->addr << 1 |
-                       (cur_msg->flags & I2C_M_RD ? 1 : 0));
+       efm32_i2c_write32(ddata, REG_TXDATA, i2c_8bit_addr_from_msg(cur_msg));
 }
 
 static void efm32_i2c_send_next_byte(struct efm32_i2c_ddata *ddata)
index bdeab0174fec2099b4572bbe9dea6bd9d32514db..835d54ac2971caffbadfd2ca58481079652e7271 100644 (file)
@@ -414,7 +414,7 @@ static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap,
                iowrite32(addr_8_lsb, p + PCH_I2CDR);
        } else {
                /* set 7 bit slave address and R/W bit as 0 */
-               iowrite32(addr << 1, p + PCH_I2CDR);
+               iowrite32(i2c_8bit_addr_from_msg(msgs), p + PCH_I2CDR);
                if (first)
                        pch_i2c_start(adap);
        }
@@ -538,8 +538,7 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
                iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR);
        } else {
                /* 7 address bits + R/W bit */
-               addr = (((addr) << 1) | (I2C_RD));
-               iowrite32(addr, p + PCH_I2CDR);
+               iowrite32(i2c_8bit_addr_from_msg(msgs), p + PCH_I2CDR);
        }
 
        /* check if it is the first message */
index d2e84480fbe96093549666df92a55f4f7196259f..ba9b6ea48a31362951bdc5a50b53fc2b222bf1d7 100644 (file)
@@ -149,7 +149,7 @@ static int __em_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
        em_clear_set_bit(priv, 0, I2C_BIT_STT0, I2C_OFS_IICC0);
 
        /* Send slave address and R/W type */
-       writeb((msg->addr << 1) | read, priv->base + I2C_OFS_IIC0);
+       writeb(i2c_8bit_addr_from_msg(msg), priv->base + I2C_OFS_IIC0);
 
        /* Wait for transaction */
        status = em_i2c_wait_for_event(priv);
index 12ec8484e65375cd24cc7b18fcd2fe5a7a458374..de82ad8ff5347cdb7a8ddfc6005619633164ef40 100644 (file)
@@ -707,7 +707,7 @@ static int exynos5_i2c_xfer(struct i2c_adapter *adap,
                        struct i2c_msg *msgs, int num)
 {
        struct exynos5_i2c *i2c = adap->algo_data;
-       int i = 0, ret = 0, stop = 0;
+       int i, ret;
 
        if (i2c->suspended) {
                dev_err(i2c->dev, "HS-I2C is not initialized.\n");
@@ -718,30 +718,15 @@ static int exynos5_i2c_xfer(struct i2c_adapter *adap,
        if (ret)
                return ret;
 
-       for (i = 0; i < num; i++, msgs++) {
-               stop = (i == num - 1);
-
-               ret = exynos5_i2c_xfer_msg(i2c, msgs, stop);
-
-               if (ret < 0)
-                       goto out;
-       }
-
-       if (i == num) {
-               ret = num;
-       } else {
-               /* Only one message, cannot access the device */
-               if (i == 1)
-                       ret = -EREMOTEIO;
-               else
-                       ret = i;
-
-               dev_warn(i2c->dev, "xfer message failed\n");
+       for (i = 0; i < num; ++i) {
+               ret = exynos5_i2c_xfer_msg(i2c, msgs + i, i + 1 == num);
+               if (ret)
+                       break;
        }
 
- out:
        clk_disable(i2c->clk);
-       return ret;
+
+       return ret ?: num;
 }
 
 static u32 exynos5_i2c_func(struct i2c_adapter *adap)
index 58abb3eced58cd39c2940632c366fb14dfd37ccf..005e6e0330c278276a0d602fcfebdc3429218cfd 100644 (file)
@@ -11,7 +11,7 @@
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
-#include <linux/i2c-gpio.h>
+#include <linux/platform_data/i2c-gpio.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/slab.h>
index bb68957d3da5e6846169ae1b26bfd37f9e6d1caa..061a4bfb03f4d3b1312d862514034ad7e42656ee 100644 (file)
@@ -73,7 +73,6 @@
 #define I2C_OVER_INTR          BIT(0)
 
 #define HIX5I2C_MAX_FREQ       400000          /* 400k */
-#define HIX5I2C_READ_OPERATION 0x01
 
 enum hix5hd2_i2c_state {
        HIX5I2C_STAT_RW_ERR = -1,
@@ -311,12 +310,8 @@ static void hix5hd2_i2c_message_start(struct hix5hd2_i2c_priv *priv, int stop)
        hix5hd2_i2c_clr_all_irq(priv);
        hix5hd2_i2c_enable_irq(priv);
 
-       if (priv->msg->flags & I2C_M_RD)
-               writel_relaxed((priv->msg->addr << 1) | HIX5I2C_READ_OPERATION,
-                              priv->regs + HIX5I2C_TXR);
-       else
-               writel_relaxed(priv->msg->addr << 1,
-                              priv->regs + HIX5I2C_TXR);
+       writel_relaxed(i2c_8bit_addr_from_msg(priv->msg),
+                      priv->regs + HIX5I2C_TXR);
 
        writel_relaxed(I2C_WRITE | I2C_START, priv->regs + HIX5I2C_COM);
        spin_unlock_irqrestore(&priv->lock, flags);
@@ -377,17 +372,7 @@ static int hix5hd2_i2c_xfer(struct i2c_adapter *adap,
                        goto out;
        }
 
-       if (i == num) {
-               ret = num;
-       } else {
-               /* Only one message, cannot access the device */
-               if (i == 1)
-                       ret = -EREMOTEIO;
-               else
-                       ret = i;
-
-               dev_warn(priv->dev, "xfer message failed\n");
-       }
+       ret = num;
 
 out:
        pm_runtime_mark_last_busy(priv->dev);
@@ -471,7 +456,6 @@ static int hix5hd2_i2c_probe(struct platform_device *pdev)
                goto err_clk;
        }
 
-       pm_suspend_ignore_children(&pdev->dev, true);
        pm_runtime_set_autosuspend_delay(priv->dev, MSEC_PER_SEC);
        pm_runtime_use_autosuspend(priv->dev);
        pm_runtime_set_active(priv->dev);
index e0d59e9ff3c6de53b5c94a54fbd21e88713ecd1b..aa726607645ee6c5cb2565d645a45da71982c306 100644 (file)
 
 #if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI
 #include <linux/gpio.h>
-#include <linux/i2c-mux-gpio.h>
+#include <linux/platform_data/i2c-mux-gpio.h>
 #endif
 
 /* I801 SMBus address offsets */
@@ -1710,7 +1710,7 @@ static void i801_shutdown(struct pci_dev *dev)
        pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int i801_suspend(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
@@ -1731,8 +1731,7 @@ static int i801_resume(struct device *dev)
 }
 #endif
 
-static UNIVERSAL_DEV_PM_OPS(i801_pm_ops, i801_suspend,
-                           i801_resume, NULL);
+static SIMPLE_DEV_PM_OPS(i801_pm_ops, i801_suspend, i801_resume);
 
 static struct pci_driver i801_driver = {
        .name           = "i801_smbus",
index 961c5f42d956f11fe1e87b95aaf50339959e7014..6f6e1dfe7ccee3982d4e824215b53ef2e48772ff 100644 (file)
@@ -561,9 +561,6 @@ static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 
        DBG2("%d: iic_xfer, %d msg(s)\n", dev->idx, num);
 
-       if (!num)
-               return 0;
-
        /* Check the sanity of the passed messages.
         * Uhh, generic i2c layer is more suitable place for such code...
         */
index e6da2c7a9a3e60841e7405738f6ea091cc0eea0f..6d975f5221ca0e37410c9d2e770f7d78bfe270b2 100644 (file)
@@ -1,18 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * This is i.MX low power i2c controller driver.
  *
  * Copyright 2016 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
  */
 
 #include <linux/clk.h>
@@ -180,15 +170,13 @@ static int lpi2c_imx_start(struct lpi2c_imx_struct *lpi2c_imx,
                           struct i2c_msg *msgs)
 {
        unsigned int temp;
-       u8 read;
 
        temp = readl(lpi2c_imx->base + LPI2C_MCR);
        temp |= MCR_RRF | MCR_RTF;
        writel(temp, lpi2c_imx->base + LPI2C_MCR);
        writel(0x7f00, lpi2c_imx->base + LPI2C_MSR);
 
-       read = msgs->flags & I2C_M_RD;
-       temp = (msgs->addr << 1 | read) | (GEN_START << 8);
+       temp = i2c_8bit_addr_from_msg(msgs) | (GEN_START << 8);
        writel(temp, lpi2c_imx->base + LPI2C_MTDR);
 
        return lpi2c_imx_bus_busy(lpi2c_imx);
index d7267dd9c7bf1da67c4c326ca53fffd6bc0e0c36..0207e194f84bb4e667d4ebec548987f40caffdd1 100644 (file)
@@ -1,16 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  *     Copyright (C) 2002 Motorola GSG-China
  *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License
- *     as published by the Free Software Foundation; either version 2
- *     of the License, or (at your option) any later version.
- *
- *     This program is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
  * Author:
  *     Darius Augulis, Teltonika Inc.
  *
@@ -630,7 +621,7 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx,
         * Write slave address.
         * The first byte must be transmitted by the CPU.
         */
-       imx_i2c_write_reg(msgs->addr << 1, i2c_imx, IMX_I2C_I2DR);
+       imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR);
        reinit_completion(&i2c_imx->dma->cmd_complete);
        time_left = wait_for_completion_timeout(
                                &i2c_imx->dma->cmd_complete,
@@ -760,10 +751,10 @@ static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs)
        int i, result;
 
        dev_dbg(&i2c_imx->adapter.dev, "<%s> write slave address: addr=0x%x\n",
-               __func__, msgs->addr << 1);
+               __func__, i2c_8bit_addr_from_msg(msgs));
 
        /* write slave address */
-       imx_i2c_write_reg(msgs->addr << 1, i2c_imx, IMX_I2C_I2DR);
+       imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR);
        result = i2c_imx_trx_complete(i2c_imx);
        if (result)
                return result;
@@ -796,10 +787,10 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo
 
        dev_dbg(&i2c_imx->adapter.dev,
                "<%s> write slave address: addr=0x%x\n",
-               __func__, (msgs->addr << 1) | 0x01);
+               __func__, i2c_8bit_addr_from_msg(msgs));
 
        /* write slave address */
-       imx_i2c_write_reg((msgs->addr << 1) | 0x01, i2c_imx, IMX_I2C_I2DR);
+       imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR);
        result = i2c_imx_trx_complete(i2c_imx);
        if (result)
                return result;
index e879190b5d1d899457ec6dd11b9cc7bd73e61f5b..1c874aaa0447ac891754a69a4cf5539f6ecae113 100644 (file)
@@ -124,15 +124,14 @@ static int kempld_i2c_process(struct kempld_i2c_data *i2c)
                /* 10 bit address? */
                if (i2c->msg->flags & I2C_M_TEN) {
                        addr = 0xf0 | ((i2c->msg->addr >> 7) & 0x6);
+                       /* Set read bit if necessary */
+                       addr |= (i2c->msg->flags & I2C_M_RD) ? 1 : 0;
                        i2c->state = STATE_ADDR10;
                } else {
-                       addr = (i2c->msg->addr << 1);
+                       addr = i2c_8bit_addr_from_msg(i2c->msg);
                        i2c->state = STATE_START;
                }
 
-               /* Set read bit if necessary */
-               addr |= (i2c->msg->flags & I2C_M_RD) ? 1 : 0;
-
                kempld_write8(pld, KEMPLD_I2C_DATA, addr);
                kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_START);
 
index 4c28fa28ce766f2c6e3045857a77588613268a66..745ed43a22d65cba3920aced8aa2f525d5e4e9a9 100644 (file)
 #define MLXCPLD_I2C_VALID_FLAG         (I2C_M_RECV_LEN | I2C_M_RD)
 #define MLXCPLD_I2C_BUS_NUM            1
 #define MLXCPLD_I2C_DATA_REG_SZ                36
+#define MLXCPLD_I2C_DATA_SZ_BIT                BIT(5)
+#define MLXCPLD_I2C_DATA_SZ_MASK       GENMASK(6, 5)
+#define MLXCPLD_I2C_SMBUS_BLK_BIT      BIT(7)
 #define MLXCPLD_I2C_MAX_ADDR_LEN       4
 #define MLXCPLD_I2C_RETR_NUM           2
 #define MLXCPLD_I2C_XFER_TO            500000 /* usec */
 #define MLXCPLD_I2C_POLL_TIME          2000   /* usec */
 
 /* LPC I2C registers */
-#define MLXCPLD_LPCI2C_LPF_REG         0x0
+#define MLXCPLD_LPCI2C_CPBLTY_REG      0x0
 #define MLXCPLD_LPCI2C_CTRL_REG                0x1
 #define MLXCPLD_LPCI2C_HALF_CYC_REG    0x4
 #define MLXCPLD_LPCI2C_I2C_HOLD_REG    0x5
@@ -83,6 +86,7 @@ struct mlxcpld_i2c_priv {
        struct mutex lock;
        struct  mlxcpld_i2c_curr_xfer xfer;
        struct device *dev;
+       bool smbus_block;
 };
 
 static void mlxcpld_i2c_lpc_write_buf(u8 *data, u8 len, u32 addr)
@@ -230,7 +234,7 @@ static void mlxcpld_i2c_set_transf_data(struct mlxcpld_i2c_priv *priv,
         * All upper layers currently are never use transfer with more than
         * 2 messages. Actually, it's also not so relevant in Mellanox systems
         * because of HW limitation. Max size of transfer is not more than 32
-        * bytes in the current x86 LPCI2C bridge.
+        * or 68 bytes in the current x86 LPCI2C bridge.
         */
        priv->xfer.cmd = msgs[num - 1].flags & I2C_M_RD;
 
@@ -295,7 +299,7 @@ static int mlxcpld_i2c_wait_for_free(struct mlxcpld_i2c_priv *priv)
 static int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv)
 {
        int status, i, timeout = 0;
-       u8 datalen;
+       u8 datalen, val;
 
        do {
                usleep_range(MLXCPLD_I2C_POLL_TIME / 2, MLXCPLD_I2C_POLL_TIME);
@@ -324,9 +328,22 @@ static int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv)
                 * Actual read data len will be always the same as
                 * requested len. 0xff (line pull-up) will be returned
                 * if slave has no data to return. Thus don't read
-                * MLXCPLD_LPCI2C_NUM_DAT_REG reg from CPLD.
+                * MLXCPLD_LPCI2C_NUM_DAT_REG reg from CPLD.  Only in case of
+                * SMBus block read transaction data len can be different,
+                * check this case.
                 */
-               datalen = priv->xfer.data_len;
+               mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_NUM_ADDR_REG, &val,
+                                     1);
+               if (priv->smbus_block && (val & MLXCPLD_I2C_SMBUS_BLK_BIT)) {
+                       mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_NUM_DAT_REG,
+                                             &datalen, 1);
+                       if (unlikely(datalen > (I2C_SMBUS_BLOCK_MAX + 1))) {
+                               dev_err(priv->dev, "Incorrect smbus block read message len\n");
+                               return -E2BIG;
+                       }
+               } else {
+                       datalen = priv->xfer.data_len;
+               }
 
                mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_DATA_REG,
                                      priv->xfer.msg[i].buf, datalen);
@@ -344,12 +361,20 @@ static int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv)
 static void mlxcpld_i2c_xfer_msg(struct mlxcpld_i2c_priv *priv)
 {
        int i, len = 0;
-       u8 cmd;
+       u8 cmd, val;
 
        mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_DAT_REG,
                               &priv->xfer.data_len, 1);
-       mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_ADDR_REG,
-                              &priv->xfer.addr_width, 1);
+
+       val = priv->xfer.addr_width;
+       /* Notify HW about SMBus block read transaction */
+       if (priv->smbus_block && priv->xfer.msg_num >= 2 &&
+           priv->xfer.msg[1].len == 1 &&
+           (priv->xfer.msg[1].flags & I2C_M_RECV_LEN) &&
+           (priv->xfer.msg[1].flags & I2C_M_RD))
+               val |= MLXCPLD_I2C_SMBUS_BLK_BIT;
+
+       mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_ADDR_REG, &val, 1);
 
        for (i = 0; i < priv->xfer.msg_num; i++) {
                if ((priv->xfer.msg[i].flags & I2C_M_RD) != I2C_M_RD) {
@@ -425,7 +450,14 @@ static int mlxcpld_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
 
 static u32 mlxcpld_i2c_func(struct i2c_adapter *adap)
 {
-       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA;
+       struct mlxcpld_i2c_priv *priv = i2c_get_adapdata(adap);
+
+       if (priv->smbus_block)
+               return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+                       I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_BLOCK_DATA;
+       else
+               return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+                       I2C_FUNC_SMBUS_I2C_BLOCK;
 }
 
 static const struct i2c_algorithm mlxcpld_i2c_algo = {
@@ -440,6 +472,13 @@ static const struct i2c_adapter_quirks mlxcpld_i2c_quirks = {
        .max_comb_1st_msg_len = 4,
 };
 
+static const struct i2c_adapter_quirks mlxcpld_i2c_quirks_ext = {
+       .flags = I2C_AQ_COMB_WRITE_THEN_READ,
+       .max_read_len = MLXCPLD_I2C_DATA_REG_SZ * 2 - MLXCPLD_I2C_MAX_ADDR_LEN,
+       .max_write_len = MLXCPLD_I2C_DATA_REG_SZ * 2,
+       .max_comb_1st_msg_len = 4,
+};
+
 static struct i2c_adapter mlxcpld_i2c_adapter = {
        .owner          = THIS_MODULE,
        .name           = "i2c-mlxcpld",
@@ -454,6 +493,7 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev)
 {
        struct mlxcpld_i2c_priv *priv;
        int err;
+       u8 val;
 
        priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
@@ -466,6 +506,16 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev)
 
        /* Register with i2c layer */
        mlxcpld_i2c_adapter.timeout = usecs_to_jiffies(MLXCPLD_I2C_XFER_TO);
+       /* Read capability register */
+       mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_CPBLTY_REG, &val, 1);
+       /* Check support for extended transaction length */
+       if ((val & MLXCPLD_I2C_DATA_SZ_MASK) == MLXCPLD_I2C_DATA_SZ_BIT)
+               mlxcpld_i2c_adapter.quirks = &mlxcpld_i2c_quirks_ext;
+       /* Check support for smbus block transaction */
+       if (val & MLXCPLD_I2C_SMBUS_BLK_BIT)
+               priv->smbus_block = true;
+       if (pdev->id >= -1)
+               mlxcpld_i2c_adapter.nr = pdev->id;
        priv->adap = mlxcpld_i2c_adapter;
        priv->adap.dev.parent = &pdev->dev;
        priv->base_addr = MLXPLAT_CPLD_LPC_I2C_BASE_ADDR;
index cf23a746cc17efeb2eaa98792b0587887c4152dc..1e57f58fcb00151e9ef274e25e3adf22f2c197b8 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/of_address.h>
+#include <linux/of_device.h>
 #include <linux/of_irq.h>
 #include <linux/platform_device.h>
 #include <linux/scatterlist.h>
@@ -734,7 +735,6 @@ static int mtk_i2c_parse_dt(struct device_node *np, struct mtk_i2c *i2c)
 
 static int mtk_i2c_probe(struct platform_device *pdev)
 {
-       const struct of_device_id *of_id;
        int ret = 0;
        struct mtk_i2c *i2c;
        struct clk *clk;
@@ -761,11 +761,7 @@ static int mtk_i2c_probe(struct platform_device *pdev)
 
        init_completion(&i2c->msg_complete);
 
-       of_id = of_match_node(mtk_i2c_of_match, pdev->dev.of_node);
-       if (!of_id)
-               return -EINVAL;
-
-       i2c->dev_comp = of_id->data;
+       i2c->dev_comp = of_device_get_match_data(&pdev->dev);
        i2c->adap.dev.of_node = pdev->dev.of_node;
        i2c->dev = &pdev->dev;
        i2c->adap.dev.parent = &pdev->dev;
index e617bd600794c235030c9f5d0ea0de4b4341f8e9..642c58946d8d261a48cd146ffe7bff65a90ef660 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Freescale MXS I2C bus driver
  *
@@ -7,12 +8,6 @@
  * based on a (non-working) driver which was:
  *
  * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
  */
 
 #include <linux/slab.h>
@@ -180,9 +175,10 @@ static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap,
        struct dma_async_tx_descriptor *desc;
        struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap);
 
+       i2c->addr_data = i2c_8bit_addr_from_msg(msg);
+
        if (msg->flags & I2C_M_RD) {
                i2c->dma_read = true;
-               i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_READ;
 
                /*
                 * SELECT command.
@@ -240,7 +236,6 @@ static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap,
                }
        } else {
                i2c->dma_read = false;
-               i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_WRITE;
 
                /*
                 * WRITE command.
@@ -371,7 +366,7 @@ static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap,
                        struct i2c_msg *msg, uint32_t flags)
 {
        struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap);
-       uint32_t addr_data = msg->addr << 1;
+       uint32_t addr_data = i2c_8bit_addr_from_msg(msg);
        uint32_t data = 0;
        int i, ret, xlen = 0, xmit = 0;
        uint32_t start;
@@ -411,8 +406,6 @@ static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap,
                 */
                BUG_ON(msg->len > 4);
 
-               addr_data |= I2C_SMBUS_READ;
-
                /* SELECT command. */
                mxs_i2c_pio_trigger_write_cmd(i2c, MXS_CMD_I2C_SELECT,
                                              addr_data);
@@ -450,7 +443,6 @@ static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap,
                 * fast enough. It is possible to transfer arbitrary amount
                 * of data using PIO write.
                 */
-               addr_data |= I2C_SMBUS_WRITE;
 
                /*
                 * The LSB of data buffer is the first byte blasted across
index 49c7c0c91486a48321b7711c04166b13dda97001..0ed5a41804dcf8d5d33d043a3d0f8e29b5430e4f 100644 (file)
@@ -1012,8 +1012,6 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
                goto err_no_mem;
        }
 
-       pm_suspend_ignore_children(&adev->dev, true);
-
        dev->clk = devm_clk_get(&adev->dev, NULL);
        if (IS_ERR(dev->clk)) {
                dev_err(&adev->dev, "could not get i2c clock\n");
index 45ae3c025bf68064e90923a1b4febfabf0b36e47..88444ef74943dcd64b7bdddff9c47a93e6a4093f 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/wait.h>
-#include <linux/i2c-ocores.h>
+#include <linux/platform_data/i2c-ocores.h>
 #include <linux/slab.h>
 #include <linux/io.h>
 #include <linux/log2.h>
@@ -222,10 +222,7 @@ static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
        i2c->nmsgs = num;
        i2c->state = STATE_START;
 
-       oc_setreg(i2c, OCI2C_DATA,
-                       (i2c->msg->addr << 1) |
-                       ((i2c->msg->flags & I2C_M_RD) ? 1:0));
-
+       oc_setreg(i2c, OCI2C_DATA, i2c_8bit_addr_from_msg(i2c->msg));
        oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);
 
        if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) ||
index b9172f08fd05fac32b2d4e40e87615c0691e50fe..65d06a8193074814cb18a0864eaea9cbc3c044de 100644 (file)
@@ -36,7 +36,7 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/slab.h>
-#include <linux/i2c-omap.h>
+#include <linux/platform_data/i2c-omap.h>
 #include <linux/pm_runtime.h>
 #include <linux/pinctrl/consumer.h>
 
index 0aabb7eca0c552968df67bd39aa81db9de009131..dc2a23f4fb52f354e8914dce6335e09a9d8383a9 100644 (file)
@@ -94,8 +94,6 @@ static int i2c_opal_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
         */
        memset(&req, 0, sizeof(req));
        switch(num) {
-       case 0:
-               return 0;
        case 1:
                req.type = (msgs[0].flags & I2C_M_RD) ?
                        OPAL_I2C_RAW_READ : OPAL_I2C_RAW_WRITE;
@@ -114,8 +112,6 @@ static int i2c_opal_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
                req.size = cpu_to_be32(msgs[1].len);
                req.buffer_ra = cpu_to_be64(__pa(msgs[1].buf));
                break;
-       default:
-               return -EOPNOTSUPP;
        }
 
        rc = i2c_opal_send_request(opal_id, &req);
index df1dbc92a0244c4eb989e88826c9f24235f35c7a..55fd5c6f3cca1523715f6f80f5fc061b79304728 100644 (file)
@@ -121,7 +121,7 @@ static int pasemi_i2c_xfer_msg(struct i2c_adapter *adapter,
 
        read = msg->flags & I2C_M_RD ? 1 : 0;
 
-       TXFIFO_WR(smbus, MTXFIFO_START | (msg->addr << 1) | read);
+       TXFIFO_WR(smbus, MTXFIFO_START | i2c_8bit_addr_from_msg(msg));
 
        if (read) {
                TXFIFO_WR(smbus, msg->len | MTXFIFO_READ |
index bc2707ffd4090289d3013f6b7f36f2d2a7b19c30..de3fe6e828cbdcf585aae98989ea418e6c8725fd 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/i2c-algo-pca.h>
-#include <linux/i2c-pca-platform.h>
+#include <linux/platform_data/i2c-pca-platform.h>
 #include <linux/gpio.h>
 #include <linux/gpio/consumer.h>
 #include <linux/io.h>
index a542041df0cd4c95ff8e25340a9c36742eedba8f..6e0e546ef83fcabe595f6591867850b8730b2e14 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/timer.h>
 #include <linux/completion.h>
 #include <linux/platform_device.h>
-#include <linux/i2c-pnx.h>
 #include <linux/io.h>
 #include <linux/err.h>
 #include <linux/clk.h>
 #define I2C_PNX_SPEED_KHZ_DEFAULT      100
 #define I2C_PNX_REGION_SIZE            0x100
 
+struct i2c_pnx_mif {
+       int                     ret;            /* Return value */
+       int                     mode;           /* Interface mode */
+       struct completion       complete;       /* I/O completion */
+       struct timer_list       timer;          /* Timeout */
+       u8 *                    buf;            /* Data buffer */
+       int                     len;            /* Length of data buffer */
+       int                     order;          /* RX Bytes to order via TX */
+};
+
+struct i2c_pnx_algo_data {
+       void __iomem            *ioaddr;
+       struct i2c_pnx_mif      mif;
+       int                     last;
+       struct clk              *clk;
+       struct i2c_adapter      adapter;
+       int                     irq;
+       u32                     timeout;
+};
+
 enum {
        mstatus_tdi = 0x00000001,
        mstatus_afi = 0x00000002,
index ebbf9cdec86b94c8bb75274fcd3469bd3f1ee837..c86c3ae1318f200696f909f7563c8a114ee30995 100644 (file)
  */
 #define TOUT_MIN                       2
 
+/* I2C Frequency Modes */
+#define I2C_STANDARD_FREQ              100000
+#define I2C_FAST_MODE_FREQ             400000
+#define I2C_FAST_MODE_PLUS_FREQ                1000000
+
 /* Default values. Use these if FW query fails */
-#define DEFAULT_CLK_FREQ 100000
+#define DEFAULT_CLK_FREQ I2C_STANDARD_FREQ
 #define DEFAULT_SRC_CLK 20000000
 
 /*
 /* TAG length for DATA READ in RX FIFO  */
 #define READ_RX_TAGS_LEN               2
 
+static unsigned int scl_freq;
+module_param_named(scl_freq, scl_freq, uint, 0444);
+MODULE_PARM_DESC(scl_freq, "SCL frequency override");
+
 /*
  * count: no of blocks
  * pos: current block number
@@ -453,7 +462,7 @@ static void qup_i2c_write_tx_fifo_v1(struct qup_i2c_dev *qup)
 {
        struct qup_i2c_block *blk = &qup->blk;
        struct i2c_msg *msg = qup->msg;
-       u32 addr = msg->addr << 1;
+       u32 addr = i2c_8bit_addr_from_msg(msg);
        u32 qup_tag;
        int idx;
        u32 val;
@@ -1648,6 +1657,12 @@ static void qup_i2c_disable_clocks(struct qup_i2c_dev *qup)
        clk_disable_unprepare(qup->pclk);
 }
 
+static const struct acpi_device_id qup_i2c_acpi_match[] = {
+       { "QCOM8010"},
+       { },
+};
+MODULE_DEVICE_TABLE(acpi, qup_i2c_acpi_match);
+
 static int qup_i2c_probe(struct platform_device *pdev)
 {
        static const int blk_sizes[] = {4, 16, 32};
@@ -1669,10 +1684,15 @@ static int qup_i2c_probe(struct platform_device *pdev)
        init_completion(&qup->xfer);
        platform_set_drvdata(pdev, qup);
 
-       ret = device_property_read_u32(qup->dev, "clock-frequency", &clk_freq);
-       if (ret) {
-               dev_notice(qup->dev, "using default clock-frequency %d",
-                       DEFAULT_CLK_FREQ);
+       if (scl_freq) {
+               dev_notice(qup->dev, "Using override frequency of %u\n", scl_freq);
+               clk_freq = scl_freq;
+       } else {
+               ret = device_property_read_u32(qup->dev, "clock-frequency", &clk_freq);
+               if (ret) {
+                       dev_notice(qup->dev, "using default clock-frequency %d",
+                               DEFAULT_CLK_FREQ);
+               }
        }
 
        if (of_device_is_compatible(pdev->dev.of_node, "qcom,i2c-qup-v1.1.1")) {
@@ -1682,7 +1702,10 @@ static int qup_i2c_probe(struct platform_device *pdev)
        } else {
                qup->adap.algo = &qup_i2c_algo_v2;
                is_qup_v1 = false;
-               ret = qup_i2c_req_dma(qup);
+               if (acpi_match_device(qup_i2c_acpi_match, qup->dev))
+                       goto nodma;
+               else
+                       ret = qup_i2c_req_dma(qup);
 
                if (ret == -EPROBE_DEFER)
                        goto fail_dma;
@@ -1734,8 +1757,8 @@ static int qup_i2c_probe(struct platform_device *pdev)
        }
 
 nodma:
-       /* We support frequencies up to FAST Mode (400KHz) */
-       if (!clk_freq || clk_freq > 400000) {
+       /* We support frequencies up to FAST Mode Plus (1MHz) */
+       if (!clk_freq || clk_freq > I2C_FAST_MODE_PLUS_FREQ) {
                dev_err(qup->dev, "clock frequency not supported %d\n",
                        clk_freq);
                return -EINVAL;
@@ -1839,9 +1862,15 @@ nodma:
        size = QUP_INPUT_FIFO_SIZE(io_mode);
        qup->in_fifo_sz = qup->in_blk_sz * (2 << size);
 
-       fs_div = ((src_clk_freq / clk_freq) / 2) - 3;
        hs_div = 3;
-       qup->clk_ctl = (hs_div << 8) | (fs_div & 0xff);
+       if (clk_freq <= I2C_STANDARD_FREQ) {
+               fs_div = ((src_clk_freq / clk_freq) / 2) - 3;
+               qup->clk_ctl = (hs_div << 8) | (fs_div & 0xff);
+       } else {
+               /* 33%/66% duty cycle */
+               fs_div = ((src_clk_freq / clk_freq) - 6) * 2 / 3;
+               qup->clk_ctl = ((fs_div / 2) << 16) | (hs_div << 8) | (fs_div & 0xff);
+       }
 
        /*
         * Time it takes for a byte to be clocked out on the bus.
@@ -1959,14 +1988,6 @@ static const struct of_device_id qup_i2c_dt_match[] = {
 };
 MODULE_DEVICE_TABLE(of, qup_i2c_dt_match);
 
-#if IS_ENABLED(CONFIG_ACPI)
-static const struct acpi_device_id qup_i2c_acpi_match[] = {
-       { "QCOM8010"},
-       { },
-};
-MODULE_DEVICE_TABLE(acpi, qup_i2c_acpi_match);
-#endif
-
 static struct platform_driver qup_i2c_driver = {
        .probe  = qup_i2c_probe,
        .remove = qup_i2c_remove,
index c6915b835396587d7d39682ef7743e85a191ee6b..5e310efd94464897d9db7becf89294a8b2adc4f6 100644 (file)
@@ -329,7 +329,7 @@ static void rcar_i2c_prepare_msg(struct rcar_i2c_priv *priv)
        if (priv->msgs_left == 1)
                priv->flags |= ID_LAST_MSG;
 
-       rcar_i2c_write(priv, ICMAR, (priv->msg->addr << 1) | read);
+       rcar_i2c_write(priv, ICMAR, i2c_8bit_addr_from_msg(priv->msg));
        /*
         * We don't have a test case but the HW engineers say that the write order
         * of ICMSR and ICMCR depends on whether we issue START or REP_START. Since
@@ -542,6 +542,8 @@ static void rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr)
         * If next received data is the _LAST_, go to STOP phase. Might be
         * overwritten by REP START when setting up a new msg. Not elegant
         * but the only stable sequence for REP START I have found so far.
+        * If you want to change this code, make sure sending one transfer with
+        * four messages (WR-RD-WR-RD) works!
         */
        if (priv->pos + 1 >= msg->len)
                rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP);
index 95c2f1ce3cad8b4a115f355609d92a9ae910c140..5f1fca7880b1b28d0c2387b9f7dc414527c23e81 100644 (file)
@@ -167,15 +167,14 @@ static irqreturn_t riic_tdre_isr(int irq, void *data)
                return IRQ_NONE;
 
        if (riic->bytes_left == RIIC_INIT_MSG) {
-               val = !!(riic->msg->flags & I2C_M_RD);
-               if (val)
+               if (riic->msg->flags & I2C_M_RD)
                        /* On read, switch over to receive interrupt */
                        riic_clear_set_bit(riic, ICIER_TIE, ICIER_RIE, RIIC_ICIER);
                else
                        /* On write, initialize length */
                        riic->bytes_left = riic->msg->len;
 
-               val |= (riic->msg->addr << 1);
+               val = i2c_8bit_addr_from_msg(riic->msg);
        } else {
                val = *riic->buf;
                riic->buf++;
index e1a18d989f830771f27614aba820ffc5da5356e6..b8a2728dd4b69cabca0314a70196176c0df12dde 100644 (file)
@@ -1326,8 +1326,6 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
        if (ret < 0)
                goto err_clk_notifier;
 
-       dev_info(&pdev->dev, "Initialized RK3xxx I2C bus at %p\n", i2c->regs);
-
        return 0;
 
 err_clk_notifier:
index 9c0f52b7ff7ec4a04660c4fe2b00d471463531a9..d848cf5152349dde7d828a0ccf2e4389bb49182e 100644 (file)
@@ -62,27 +62,24 @@ static int osif_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
 {
        struct osif_priv *priv = adapter->algo_data;
        struct i2c_msg *pmsg;
-       int ret = 0;
-       int i, cmd;
+       int ret;
+       int i;
 
-       for (i = 0; ret >= 0 && i < num; i++) {
+       for (i = 0; i < num; i++) {
                pmsg = &msgs[i];
 
                if (pmsg->flags & I2C_M_RD) {
-                       cmd = OSIFI2C_READ;
-
-                       ret = osif_usb_read(adapter, cmd, pmsg->flags,
-                                           pmsg->addr, pmsg->buf,
-                                           pmsg->len);
+                       ret = osif_usb_read(adapter, OSIFI2C_READ,
+                                           pmsg->flags, pmsg->addr,
+                                           pmsg->buf, pmsg->len);
                        if (ret != pmsg->len) {
                                dev_err(&adapter->dev, "failure reading data\n");
                                return -EREMOTEIO;
                        }
                } else {
-                       cmd = OSIFI2C_WRITE;
-
-                       ret = osif_usb_write(adapter, cmd, pmsg->flags,
-                                            pmsg->addr, pmsg->buf, pmsg->len);
+                       ret = osif_usb_write(adapter, OSIFI2C_WRITE,
+                                            pmsg->flags, pmsg->addr,
+                                            pmsg->buf, pmsg->len);
                        if (ret != pmsg->len) {
                                dev_err(&adapter->dev, "failure writing data\n");
                                return -EREMOTEIO;
index 5d97510ee48bf153cf8e407f1911156a79546d54..9fe2b6951895b6b27984eedeb82c8ec6c34604e7 100644 (file)
@@ -154,8 +154,6 @@ static const struct of_device_id s3c24xx_i2c_match[] = {
        { .compatible = "samsung,s3c2440-i2c", .data = (void *)QUIRK_S3C2440 },
        { .compatible = "samsung,s3c2440-hdmiphy-i2c",
          .data = (void *)(QUIRK_S3C2440 | QUIRK_HDMIPHY | QUIRK_NO_GPIO) },
-       { .compatible = "samsung,exynos5440-i2c",
-         .data = (void *)(QUIRK_S3C2440 | QUIRK_NO_GPIO) },
        { .compatible = "samsung,exynos5-sata-phy-i2c",
          .data = (void *)(QUIRK_S3C2440 | QUIRK_POLL | QUIRK_NO_GPIO) },
        {},
index d856bc211715e5ae466b715881494a1be0916bb5..5fda4188a9e51d6aa33613e0247e462913f7b2c4 100644 (file)
@@ -899,17 +899,6 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
        if (resource_size(res) > 0x17)
                pd->flags |= IIC_FLAG_HAS_ICIC67;
 
-       /* Enable Runtime PM for this device.
-        *
-        * Also tell the Runtime PM core to ignore children
-        * for this device since it is valid for us to suspend
-        * this I2C master driver even though the slave devices
-        * on the I2C bus may not be suspended.
-        *
-        * The state of the I2C hardware bus is unaffected by
-        * the Runtime PM state.
-        */
-       pm_suspend_ignore_children(&dev->dev, true);
        pm_runtime_enable(&dev->dev);
        pm_runtime_get_sync(&dev->dev);
 
diff --git a/drivers/i2c/busses/i2c-stm32.c b/drivers/i2c/busses/i2c-stm32.c
new file mode 100644 (file)
index 0000000..d75fbcb
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * i2c-stm32.c
+ *
+ * Copyright (C) M'boumba Cedric Madianga 2017
+ * Author: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
+ *
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include "i2c-stm32.h"
+
+/* Functions for DMA support */
+struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev,
+                                           dma_addr_t phy_addr,
+                                           u32 txdr_offset,
+                                           u32 rxdr_offset)
+{
+       struct stm32_i2c_dma *dma;
+       struct dma_slave_config dma_sconfig;
+       int ret;
+
+       dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
+       if (!dma)
+               return NULL;
+
+       /* Request and configure I2C TX dma channel */
+       dma->chan_tx = dma_request_slave_channel(dev, "tx");
+       if (!dma->chan_tx) {
+               dev_dbg(dev, "can't request DMA tx channel\n");
+               ret = -EINVAL;
+               goto fail_al;
+       }
+
+       memset(&dma_sconfig, 0, sizeof(dma_sconfig));
+       dma_sconfig.dst_addr = phy_addr + txdr_offset;
+       dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+       dma_sconfig.dst_maxburst = 1;
+       dma_sconfig.direction = DMA_MEM_TO_DEV;
+       ret = dmaengine_slave_config(dma->chan_tx, &dma_sconfig);
+       if (ret < 0) {
+               dev_err(dev, "can't configure tx channel\n");
+               goto fail_tx;
+       }
+
+       /* Request and configure I2C RX dma channel */
+       dma->chan_rx = dma_request_slave_channel(dev, "rx");
+       if (!dma->chan_rx) {
+               dev_err(dev, "can't request DMA rx channel\n");
+               ret = -EINVAL;
+               goto fail_tx;
+       }
+
+       memset(&dma_sconfig, 0, sizeof(dma_sconfig));
+       dma_sconfig.src_addr = phy_addr + rxdr_offset;
+       dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+       dma_sconfig.src_maxburst = 1;
+       dma_sconfig.direction = DMA_DEV_TO_MEM;
+       ret = dmaengine_slave_config(dma->chan_rx, &dma_sconfig);
+       if (ret < 0) {
+               dev_err(dev, "can't configure rx channel\n");
+               goto fail_rx;
+       }
+
+       init_completion(&dma->dma_complete);
+
+       dev_info(dev, "using %s (tx) and %s (rx) for DMA transfers\n",
+                dma_chan_name(dma->chan_tx), dma_chan_name(dma->chan_rx));
+
+       return dma;
+
+fail_rx:
+       dma_release_channel(dma->chan_rx);
+fail_tx:
+       dma_release_channel(dma->chan_tx);
+fail_al:
+       devm_kfree(dev, dma);
+       dev_info(dev, "can't use DMA\n");
+
+       return NULL;
+}
+
+void stm32_i2c_dma_free(struct stm32_i2c_dma *dma)
+{
+       dma->dma_buf = 0;
+       dma->dma_len = 0;
+
+       dma_release_channel(dma->chan_tx);
+       dma->chan_tx = NULL;
+
+       dma_release_channel(dma->chan_rx);
+       dma->chan_rx = NULL;
+
+       dma->chan_using = NULL;
+}
+
+int stm32_i2c_prep_dma_xfer(struct device *dev, struct stm32_i2c_dma *dma,
+                           bool rd_wr, u32 len, u8 *buf,
+                           dma_async_tx_callback callback,
+                           void *dma_async_param)
+{
+       struct dma_async_tx_descriptor *txdesc;
+       struct device *chan_dev;
+       int ret;
+
+       if (rd_wr) {
+               dma->chan_using = dma->chan_rx;
+               dma->dma_transfer_dir = DMA_DEV_TO_MEM;
+               dma->dma_data_dir = DMA_FROM_DEVICE;
+       } else {
+               dma->chan_using = dma->chan_tx;
+               dma->dma_transfer_dir = DMA_MEM_TO_DEV;
+               dma->dma_data_dir = DMA_TO_DEVICE;
+       }
+
+       dma->dma_len = len;
+       chan_dev = dma->chan_using->device->dev;
+
+       dma->dma_buf = dma_map_single(chan_dev, buf, dma->dma_len,
+                                     dma->dma_data_dir);
+       if (dma_mapping_error(chan_dev, dma->dma_buf)) {
+               dev_err(dev, "DMA mapping failed\n");
+               return -EINVAL;
+       }
+
+       txdesc = dmaengine_prep_slave_single(dma->chan_using, dma->dma_buf,
+                                            dma->dma_len,
+                                            dma->dma_transfer_dir,
+                                            DMA_PREP_INTERRUPT);
+       if (!txdesc) {
+               dev_err(dev, "Not able to get desc for DMA xfer\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       reinit_completion(&dma->dma_complete);
+
+       txdesc->callback = callback;
+       txdesc->callback_param = dma_async_param;
+       ret = dma_submit_error(dmaengine_submit(txdesc));
+       if (ret < 0) {
+               dev_err(dev, "DMA submit failed\n");
+               goto err;
+       }
+
+       dma_async_issue_pending(dma->chan_using);
+
+       return 0;
+
+err:
+       dma_unmap_single(chan_dev, dma->dma_buf, dma->dma_len,
+                        dma->dma_data_dir);
+       return ret;
+}
index d4f9cef251acf457f1dba743e141dadc7dc59d1b..868755f82f884be35c67aa30edcba5f16057f9f6 100644 (file)
 #ifndef _I2C_STM32_H
 #define _I2C_STM32_H
 
+#include <linux/dma-direction.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+
 enum stm32_i2c_speed {
        STM32_I2C_SPEED_STANDARD, /* 100 kHz */
        STM32_I2C_SPEED_FAST, /* 400 kHz */
@@ -18,4 +22,37 @@ enum stm32_i2c_speed {
        STM32_I2C_SPEED_END,
 };
 
+/**
+ * struct stm32_i2c_dma - DMA specific data
+ * @chan_tx: dma channel for TX transfer
+ * @chan_rx: dma channel for RX transfer
+ * @chan_using: dma channel used for the current transfer (TX or RX)
+ * @dma_buf: dma buffer
+ * @dma_len: dma buffer len
+ * @dma_transfer_dir: dma transfer direction indicator
+ * @dma_data_dir: dma transfer mode indicator
+ * @dma_complete: dma transfer completion
+ */
+struct stm32_i2c_dma {
+       struct dma_chan *chan_tx;
+       struct dma_chan *chan_rx;
+       struct dma_chan *chan_using;
+       dma_addr_t dma_buf;
+       unsigned int dma_len;
+       enum dma_transfer_direction dma_transfer_dir;
+       enum dma_data_direction dma_data_dir;
+       struct completion dma_complete;
+};
+
+struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev,
+                                           dma_addr_t phy_addr,
+                                           u32 txdr_offset, u32 rxdr_offset);
+
+void stm32_i2c_dma_free(struct stm32_i2c_dma *dma);
+
+int stm32_i2c_prep_dma_xfer(struct device *dev, struct stm32_i2c_dma *dma,
+                           bool rd_wr, u32 len, u8 *buf,
+                           dma_async_tx_callback callback,
+                           void *dma_async_param);
+
 #endif /* _I2C_STM32_H */
index f273e28c39db2ec5f667a6b4fd27d1377f8e31a4..62d023e737d9c2f60a26ea4174e78154dc10e877 100644 (file)
@@ -35,6 +35,9 @@
 /* STM32F7 I2C registers */
 #define STM32F7_I2C_CR1                                0x00
 #define STM32F7_I2C_CR2                                0x04
+#define STM32F7_I2C_OAR1                       0x08
+#define STM32F7_I2C_OAR2                       0x0C
+#define STM32F7_I2C_PECR                       0x20
 #define STM32F7_I2C_TIMINGR                    0x10
 #define STM32F7_I2C_ISR                                0x18
 #define STM32F7_I2C_ICR                                0x1C
 #define STM32F7_I2C_TXDR                       0x28
 
 /* STM32F7 I2C control 1 */
+#define STM32F7_I2C_CR1_PECEN                  BIT(23)
+#define STM32F7_I2C_CR1_SBC                    BIT(16)
+#define STM32F7_I2C_CR1_RXDMAEN                        BIT(15)
+#define STM32F7_I2C_CR1_TXDMAEN                        BIT(14)
 #define STM32F7_I2C_CR1_ANFOFF                 BIT(12)
 #define STM32F7_I2C_CR1_ERRIE                  BIT(7)
 #define STM32F7_I2C_CR1_TCIE                   BIT(6)
                                                | STM32F7_I2C_CR1_NACKIE \
                                                | STM32F7_I2C_CR1_RXIE \
                                                | STM32F7_I2C_CR1_TXIE)
+#define STM32F7_I2C_XFER_IRQ_MASK              (STM32F7_I2C_CR1_TCIE \
+                                               | STM32F7_I2C_CR1_STOPIE \
+                                               | STM32F7_I2C_CR1_NACKIE \
+                                               | STM32F7_I2C_CR1_RXIE \
+                                               | STM32F7_I2C_CR1_TXIE)
 
 /* STM32F7 I2C control 2 */
+#define STM32F7_I2C_CR2_PECBYTE                        BIT(26)
 #define STM32F7_I2C_CR2_RELOAD                 BIT(24)
 #define STM32F7_I2C_CR2_NBYTES_MASK            GENMASK(23, 16)
 #define STM32F7_I2C_CR2_NBYTES(n)              (((n) & 0xff) << 16)
 #define STM32F7_I2C_CR2_NACK                   BIT(15)
 #define STM32F7_I2C_CR2_STOP                   BIT(14)
 #define STM32F7_I2C_CR2_START                  BIT(13)
+#define STM32F7_I2C_CR2_HEAD10R                        BIT(12)
+#define STM32F7_I2C_CR2_ADD10                  BIT(11)
 #define STM32F7_I2C_CR2_RD_WRN                 BIT(10)
+#define STM32F7_I2C_CR2_SADD10_MASK            GENMASK(9, 0)
+#define STM32F7_I2C_CR2_SADD10(n)              (((n) & \
+                                               STM32F7_I2C_CR2_SADD10_MASK))
 #define STM32F7_I2C_CR2_SADD7_MASK             GENMASK(7, 1)
 #define STM32F7_I2C_CR2_SADD7(n)               (((n) & 0x7f) << 1)
 
+/* STM32F7 I2C Own Address 1 */
+#define STM32F7_I2C_OAR1_OA1EN                 BIT(15)
+#define STM32F7_I2C_OAR1_OA1MODE               BIT(10)
+#define STM32F7_I2C_OAR1_OA1_10_MASK           GENMASK(9, 0)
+#define STM32F7_I2C_OAR1_OA1_10(n)             (((n) & \
+                                               STM32F7_I2C_OAR1_OA1_10_MASK))
+#define STM32F7_I2C_OAR1_OA1_7_MASK            GENMASK(7, 1)
+#define STM32F7_I2C_OAR1_OA1_7(n)              (((n) & 0x7f) << 1)
+#define STM32F7_I2C_OAR1_MASK                  (STM32F7_I2C_OAR1_OA1_7_MASK \
+                                               | STM32F7_I2C_OAR1_OA1_10_MASK \
+                                               | STM32F7_I2C_OAR1_OA1EN \
+                                               | STM32F7_I2C_OAR1_OA1MODE)
+
+/* STM32F7 I2C Own Address 2 */
+#define STM32F7_I2C_OAR2_OA2EN                 BIT(15)
+#define STM32F7_I2C_OAR2_OA2MSK_MASK           GENMASK(10, 8)
+#define STM32F7_I2C_OAR2_OA2MSK(n)             (((n) & 0x7) << 8)
+#define STM32F7_I2C_OAR2_OA2_7_MASK            GENMASK(7, 1)
+#define STM32F7_I2C_OAR2_OA2_7(n)              (((n) & 0x7f) << 1)
+#define STM32F7_I2C_OAR2_MASK                  (STM32F7_I2C_OAR2_OA2MSK_MASK \
+                                               | STM32F7_I2C_OAR2_OA2_7_MASK \
+                                               | STM32F7_I2C_OAR2_OA2EN)
+
 /* STM32F7 I2C Interrupt Status */
+#define STM32F7_I2C_ISR_ADDCODE_MASK           GENMASK(23, 17)
+#define STM32F7_I2C_ISR_ADDCODE_GET(n) \
+                               (((n) & STM32F7_I2C_ISR_ADDCODE_MASK) >> 17)
+#define STM32F7_I2C_ISR_DIR                    BIT(16)
 #define STM32F7_I2C_ISR_BUSY                   BIT(15)
+#define STM32F7_I2C_ISR_PECERR                 BIT(11)
 #define STM32F7_I2C_ISR_ARLO                   BIT(9)
 #define STM32F7_I2C_ISR_BERR                   BIT(8)
 #define STM32F7_I2C_ISR_TCR                    BIT(7)
 #define STM32F7_I2C_ISR_TC                     BIT(6)
 #define STM32F7_I2C_ISR_STOPF                  BIT(5)
 #define STM32F7_I2C_ISR_NACKF                  BIT(4)
+#define STM32F7_I2C_ISR_ADDR                   BIT(3)
 #define STM32F7_I2C_ISR_RXNE                   BIT(2)
 #define STM32F7_I2C_ISR_TXIS                   BIT(1)
+#define STM32F7_I2C_ISR_TXE                    BIT(0)
 
 /* STM32F7 I2C Interrupt Clear */
+#define STM32F7_I2C_ICR_PECCF                  BIT(11)
 #define STM32F7_I2C_ICR_ARLOCF                 BIT(9)
 #define STM32F7_I2C_ICR_BERRCF                 BIT(8)
 #define STM32F7_I2C_ICR_STOPCF                 BIT(5)
 #define STM32F7_I2C_ICR_NACKCF                 BIT(4)
+#define STM32F7_I2C_ICR_ADDRCF                 BIT(3)
 
 /* STM32F7 I2C Timing */
 #define STM32F7_I2C_TIMINGR_PRESC(n)           (((n) & 0xf) << 28)
 #define STM32F7_I2C_TIMINGR_SCLL(n)            ((n) & 0xff)
 
 #define STM32F7_I2C_MAX_LEN                    0xff
+#define STM32F7_I2C_DMA_LEN_MIN                        0x16
+#define STM32F7_I2C_MAX_SLAVE                  0x2
 
 #define STM32F7_I2C_DNF_DEFAULT                        0
 #define STM32F7_I2C_DNF_MAX                    16
@@ -159,11 +211,12 @@ struct stm32f7_i2c_setup {
 
 /**
  * struct stm32f7_i2c_timings - private I2C output parameters
- * @prec: Prescaler value
+ * @node: List entry
+ * @presc: Prescaler value
  * @scldel: Data setup time
  * @sdadel: Data hold time
  * @sclh: SCL high period (master mode)
- * @sclh: SCL low period (master mode)
+ * @scll: SCL low period (master mode)
  */
 struct stm32f7_i2c_timings {
        struct list_head node;
@@ -176,18 +229,30 @@ struct stm32f7_i2c_timings {
 
 /**
  * struct stm32f7_i2c_msg - client specific data
- * @addr: 8-bit slave addr, including r/w bit
+ * @addr: 8-bit or 10-bit slave addr, including r/w bit
  * @count: number of bytes to be transferred
  * @buf: data buffer
  * @result: result of the transfer
  * @stop: last I2C msg to be sent, i.e. STOP to be generated
+ * @smbus: boolean to know if the I2C IP is used in SMBus mode
+ * @size: type of SMBus protocol
+ * @read_write: direction of SMBus protocol
+ * SMBus block read and SMBus block write - block read process call protocols
+ * @smbus_buf: buffer to be used for SMBus protocol transfer. It will
+ * contain a maximum of 32 bytes of data + byte command + byte count + PEC
+ * This buffer has to be 32-bit aligned to be compliant with memory address
+ * register in DMA mode.
  */
 struct stm32f7_i2c_msg {
-       u8 addr;
+       u16 addr;
        u32 count;
        u8 *buf;
        int result;
        bool stop;
+       bool smbus;
+       int size;
+       char read_write;
+       u8 smbus_buf[I2C_SMBUS_BLOCK_MAX + 3] __aligned(4);
 };
 
 /**
@@ -204,6 +269,13 @@ struct stm32f7_i2c_msg {
  * @f7_msg: customized i2c msg for driver usage
  * @setup: I2C timing input setup
  * @timing: I2C computed timings
+ * @slave: list of slave devices registered on the I2C bus
+ * @slave_running: slave device currently used
+ * @slave_dir: transfer direction for the current slave device
+ * @master_mode: boolean to know in which mode the I2C is running (master or
+ * slave)
+ * @dma: dma data
+ * @use_dma: boolean to know if dma is used in the current transfer
  */
 struct stm32f7_i2c_dev {
        struct i2c_adapter adap;
@@ -218,6 +290,12 @@ struct stm32f7_i2c_dev {
        struct stm32f7_i2c_msg f7_msg;
        struct stm32f7_i2c_setup setup;
        struct stm32f7_i2c_timings timing;
+       struct i2c_client *slave[STM32F7_I2C_MAX_SLAVE];
+       struct i2c_client *slave_running;
+       u32 slave_dir;
+       bool master_mode;
+       struct stm32_i2c_dma *dma;
+       bool use_dma;
 };
 
 /**
@@ -283,6 +361,11 @@ static inline void stm32f7_i2c_clr_bits(void __iomem *reg, u32 mask)
        writel_relaxed(readl_relaxed(reg) & ~mask, reg);
 }
 
+static void stm32f7_i2c_disable_irq(struct stm32f7_i2c_dev *i2c_dev, u32 mask)
+{
+       stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, mask);
+}
+
 static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev,
                                      struct stm32f7_i2c_setup *setup,
                                      struct stm32f7_i2c_timings *output)
@@ -524,6 +607,25 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev,
        return 0;
 }
 
+static void stm32f7_i2c_disable_dma_req(struct stm32f7_i2c_dev *i2c_dev)
+{
+       void __iomem *base = i2c_dev->base;
+       u32 mask = STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN;
+
+       stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1, mask);
+}
+
+static void stm32f7_i2c_dma_callback(void *arg)
+{
+       struct stm32f7_i2c_dev *i2c_dev = (struct stm32f7_i2c_dev *)arg;
+       struct stm32_i2c_dma *dma = i2c_dev->dma;
+       struct device *dev = dma->chan_using->device->dev;
+
+       stm32f7_i2c_disable_dma_req(i2c_dev);
+       dma_unmap_single(dev, dma->dma_buf, dma->dma_len, dma->dma_data_dir);
+       complete(&dma->dma_complete);
+}
+
 static void stm32f7_i2c_hw_config(struct stm32f7_i2c_dev *i2c_dev)
 {
        struct stm32f7_i2c_timings *t = &i2c_dev->timing;
@@ -567,6 +669,9 @@ static void stm32f7_i2c_read_rx_data(struct stm32f7_i2c_dev *i2c_dev)
        if (f7_msg->count) {
                *f7_msg->buf++ = readb_relaxed(base + STM32F7_I2C_RXDR);
                f7_msg->count--;
+       } else {
+               /* Flush RX buffer has no data is expected */
+               readb_relaxed(base + STM32F7_I2C_RXDR);
        }
 }
 
@@ -575,6 +680,9 @@ static void stm32f7_i2c_reload(struct stm32f7_i2c_dev *i2c_dev)
        struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
        u32 cr2;
 
+       if (i2c_dev->use_dma)
+               f7_msg->count -= STM32F7_I2C_MAX_LEN;
+
        cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2);
 
        cr2 &= ~STM32F7_I2C_CR2_NBYTES_MASK;
@@ -588,6 +696,43 @@ static void stm32f7_i2c_reload(struct stm32f7_i2c_dev *i2c_dev)
        writel_relaxed(cr2, i2c_dev->base + STM32F7_I2C_CR2);
 }
 
+static void stm32f7_i2c_smbus_reload(struct stm32f7_i2c_dev *i2c_dev)
+{
+       struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
+       u32 cr2;
+       u8 *val;
+
+       /*
+        * For I2C_SMBUS_BLOCK_DATA && I2C_SMBUS_BLOCK_PROC_CALL, the first
+        * data received inform us how many data will follow.
+        */
+       stm32f7_i2c_read_rx_data(i2c_dev);
+
+       /*
+        * Update NBYTES with the value read to continue the transfer
+        */
+       val = f7_msg->buf - sizeof(u8);
+       f7_msg->count = *val;
+       cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2);
+       cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK | STM32F7_I2C_CR2_RELOAD);
+       cr2 |= STM32F7_I2C_CR2_NBYTES(f7_msg->count);
+       writel_relaxed(cr2, i2c_dev->base + STM32F7_I2C_CR2);
+}
+
+static int stm32f7_i2c_release_bus(struct i2c_adapter *i2c_adap)
+{
+       struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap);
+
+       dev_info(i2c_dev->dev, "Trying to recover bus\n");
+
+       stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1,
+                            STM32F7_I2C_CR1_PE);
+
+       stm32f7_i2c_hw_config(i2c_dev);
+
+       return 0;
+}
+
 static int stm32f7_i2c_wait_free_bus(struct stm32f7_i2c_dev *i2c_dev)
 {
        u32 status;
@@ -597,12 +742,18 @@ static int stm32f7_i2c_wait_free_bus(struct stm32f7_i2c_dev *i2c_dev)
                                         status,
                                         !(status & STM32F7_I2C_ISR_BUSY),
                                         10, 1000);
+       if (!ret)
+               return 0;
+
+       dev_info(i2c_dev->dev, "bus busy\n");
+
+       ret = stm32f7_i2c_release_bus(&i2c_dev->adap);
        if (ret) {
-               dev_dbg(i2c_dev->dev, "bus busy\n");
-               ret = -EBUSY;
+               dev_err(i2c_dev->dev, "Failed to recover the bus (%d)\n", ret);
+               return ret;
        }
 
-       return ret;
+       return -EBUSY;
 }
 
 static void stm32f7_i2c_xfer_msg(struct stm32f7_i2c_dev *i2c_dev,
@@ -611,6 +762,7 @@ static void stm32f7_i2c_xfer_msg(struct stm32f7_i2c_dev *i2c_dev,
        struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
        void __iomem *base = i2c_dev->base;
        u32 cr1, cr2;
+       int ret;
 
        f7_msg->addr = msg->addr;
        f7_msg->buf = msg->buf;
@@ -629,8 +781,15 @@ static void stm32f7_i2c_xfer_msg(struct stm32f7_i2c_dev *i2c_dev,
                cr2 |= STM32F7_I2C_CR2_RD_WRN;
 
        /* Set slave address */
-       cr2 &= ~STM32F7_I2C_CR2_SADD7_MASK;
-       cr2 |= STM32F7_I2C_CR2_SADD7(f7_msg->addr);
+       cr2 &= ~(STM32F7_I2C_CR2_HEAD10R | STM32F7_I2C_CR2_ADD10);
+       if (msg->flags & I2C_M_TEN) {
+               cr2 &= ~STM32F7_I2C_CR2_SADD10_MASK;
+               cr2 |= STM32F7_I2C_CR2_SADD10(f7_msg->addr);
+               cr2 |= STM32F7_I2C_CR2_ADD10;
+       } else {
+               cr2 &= ~STM32F7_I2C_CR2_SADD7_MASK;
+               cr2 |= STM32F7_I2C_CR2_SADD7(f7_msg->addr);
+       }
 
        /* Set nb bytes to transfer and reload if needed */
        cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK | STM32F7_I2C_CR2_RELOAD);
@@ -645,16 +804,286 @@ static void stm32f7_i2c_xfer_msg(struct stm32f7_i2c_dev *i2c_dev,
        cr1 |= STM32F7_I2C_CR1_ERRIE | STM32F7_I2C_CR1_TCIE |
                STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE;
 
-       /* Clear TX/RX interrupt */
+       /* Clear DMA req and TX/RX interrupt */
+       cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE |
+                       STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN);
+
+       /* Configure DMA or enable RX/TX interrupt */
+       i2c_dev->use_dma = false;
+       if (i2c_dev->dma && f7_msg->count >= STM32F7_I2C_DMA_LEN_MIN) {
+               ret = stm32_i2c_prep_dma_xfer(i2c_dev->dev, i2c_dev->dma,
+                                             msg->flags & I2C_M_RD,
+                                             f7_msg->count, f7_msg->buf,
+                                             stm32f7_i2c_dma_callback,
+                                             i2c_dev);
+               if (!ret)
+                       i2c_dev->use_dma = true;
+               else
+                       dev_warn(i2c_dev->dev, "can't use DMA\n");
+       }
+
+       if (!i2c_dev->use_dma) {
+               if (msg->flags & I2C_M_RD)
+                       cr1 |= STM32F7_I2C_CR1_RXIE;
+               else
+                       cr1 |= STM32F7_I2C_CR1_TXIE;
+       } else {
+               if (msg->flags & I2C_M_RD)
+                       cr1 |= STM32F7_I2C_CR1_RXDMAEN;
+               else
+                       cr1 |= STM32F7_I2C_CR1_TXDMAEN;
+       }
+
+       /* Configure Start/Repeated Start */
+       cr2 |= STM32F7_I2C_CR2_START;
+
+       i2c_dev->master_mode = true;
+
+       /* Write configurations registers */
+       writel_relaxed(cr1, base + STM32F7_I2C_CR1);
+       writel_relaxed(cr2, base + STM32F7_I2C_CR2);
+}
+
+static int stm32f7_i2c_smbus_xfer_msg(struct stm32f7_i2c_dev *i2c_dev,
+                                     unsigned short flags, u8 command,
+                                     union i2c_smbus_data *data)
+{
+       struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
+       struct device *dev = i2c_dev->dev;
+       void __iomem *base = i2c_dev->base;
+       u32 cr1, cr2;
+       int i, ret;
+
+       f7_msg->result = 0;
+       reinit_completion(&i2c_dev->complete);
+
+       cr2 = readl_relaxed(base + STM32F7_I2C_CR2);
+       cr1 = readl_relaxed(base + STM32F7_I2C_CR1);
+
+       /* Set transfer direction */
+       cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
+       if (f7_msg->read_write)
+               cr2 |= STM32F7_I2C_CR2_RD_WRN;
+
+       /* Set slave address */
+       cr2 &= ~(STM32F7_I2C_CR2_ADD10 | STM32F7_I2C_CR2_SADD7_MASK);
+       cr2 |= STM32F7_I2C_CR2_SADD7(f7_msg->addr);
+
+       f7_msg->smbus_buf[0] = command;
+       switch (f7_msg->size) {
+       case I2C_SMBUS_QUICK:
+               f7_msg->stop = true;
+               f7_msg->count = 0;
+               break;
+       case I2C_SMBUS_BYTE:
+               f7_msg->stop = true;
+               f7_msg->count = 1;
+               break;
+       case I2C_SMBUS_BYTE_DATA:
+               if (f7_msg->read_write) {
+                       f7_msg->stop = false;
+                       f7_msg->count = 1;
+                       cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
+               } else {
+                       f7_msg->stop = true;
+                       f7_msg->count = 2;
+                       f7_msg->smbus_buf[1] = data->byte;
+               }
+               break;
+       case I2C_SMBUS_WORD_DATA:
+               if (f7_msg->read_write) {
+                       f7_msg->stop = false;
+                       f7_msg->count = 1;
+                       cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
+               } else {
+                       f7_msg->stop = true;
+                       f7_msg->count = 3;
+                       f7_msg->smbus_buf[1] = data->word & 0xff;
+                       f7_msg->smbus_buf[2] = data->word >> 8;
+               }
+               break;
+       case I2C_SMBUS_BLOCK_DATA:
+               if (f7_msg->read_write) {
+                       f7_msg->stop = false;
+                       f7_msg->count = 1;
+                       cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
+               } else {
+                       f7_msg->stop = true;
+                       if (data->block[0] > I2C_SMBUS_BLOCK_MAX ||
+                           !data->block[0]) {
+                               dev_err(dev, "Invalid block write size %d\n",
+                                       data->block[0]);
+                               return -EINVAL;
+                       }
+                       f7_msg->count = data->block[0] + 2;
+                       for (i = 1; i < f7_msg->count; i++)
+                               f7_msg->smbus_buf[i] = data->block[i - 1];
+               }
+               break;
+       case I2C_SMBUS_PROC_CALL:
+               f7_msg->stop = false;
+               f7_msg->count = 3;
+               f7_msg->smbus_buf[1] = data->word & 0xff;
+               f7_msg->smbus_buf[2] = data->word >> 8;
+               cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
+               f7_msg->read_write = I2C_SMBUS_READ;
+               break;
+       case I2C_SMBUS_BLOCK_PROC_CALL:
+               f7_msg->stop = false;
+               if (data->block[0] > I2C_SMBUS_BLOCK_MAX - 1) {
+                       dev_err(dev, "Invalid block write size %d\n",
+                               data->block[0]);
+                       return -EINVAL;
+               }
+               f7_msg->count = data->block[0] + 2;
+               for (i = 1; i < f7_msg->count; i++)
+                       f7_msg->smbus_buf[i] = data->block[i - 1];
+               cr2 &= ~STM32F7_I2C_CR2_RD_WRN;
+               f7_msg->read_write = I2C_SMBUS_READ;
+               break;
+       default:
+               dev_err(dev, "Unsupported smbus protocol %d\n", f7_msg->size);
+               return -EOPNOTSUPP;
+       }
+
+       f7_msg->buf = f7_msg->smbus_buf;
+
+       /* Configure PEC */
+       if ((flags & I2C_CLIENT_PEC) && f7_msg->size != I2C_SMBUS_QUICK) {
+               cr1 |= STM32F7_I2C_CR1_PECEN;
+               cr2 |= STM32F7_I2C_CR2_PECBYTE;
+               if (!f7_msg->read_write)
+                       f7_msg->count++;
+       } else {
+               cr1 &= ~STM32F7_I2C_CR1_PECEN;
+               cr2 &= ~STM32F7_I2C_CR2_PECBYTE;
+       }
+
+       /* Set number of bytes to be transferred */
+       cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK | STM32F7_I2C_CR2_RELOAD);
+       cr2 |= STM32F7_I2C_CR2_NBYTES(f7_msg->count);
+
+       /* Enable NACK, STOP, error and transfer complete interrupts */
+       cr1 |= STM32F7_I2C_CR1_ERRIE | STM32F7_I2C_CR1_TCIE |
+               STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE;
+
+       /* Clear DMA req and TX/RX interrupt */
+       cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE |
+                       STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN);
+
+       /* Configure DMA or enable RX/TX interrupt */
+       i2c_dev->use_dma = false;
+       if (i2c_dev->dma && f7_msg->count >= STM32F7_I2C_DMA_LEN_MIN) {
+               ret = stm32_i2c_prep_dma_xfer(i2c_dev->dev, i2c_dev->dma,
+                                             cr2 & STM32F7_I2C_CR2_RD_WRN,
+                                             f7_msg->count, f7_msg->buf,
+                                             stm32f7_i2c_dma_callback,
+                                             i2c_dev);
+               if (!ret)
+                       i2c_dev->use_dma = true;
+               else
+                       dev_warn(i2c_dev->dev, "can't use DMA\n");
+       }
+
+       if (!i2c_dev->use_dma) {
+               if (cr2 & STM32F7_I2C_CR2_RD_WRN)
+                       cr1 |= STM32F7_I2C_CR1_RXIE;
+               else
+                       cr1 |= STM32F7_I2C_CR1_TXIE;
+       } else {
+               if (cr2 & STM32F7_I2C_CR2_RD_WRN)
+                       cr1 |= STM32F7_I2C_CR1_RXDMAEN;
+               else
+                       cr1 |= STM32F7_I2C_CR1_TXDMAEN;
+       }
+
+       /* Set Start bit */
+       cr2 |= STM32F7_I2C_CR2_START;
+
+       i2c_dev->master_mode = true;
+
+       /* Write configurations registers */
+       writel_relaxed(cr1, base + STM32F7_I2C_CR1);
+       writel_relaxed(cr2, base + STM32F7_I2C_CR2);
+
+       return 0;
+}
+
+static void stm32f7_i2c_smbus_rep_start(struct stm32f7_i2c_dev *i2c_dev)
+{
+       struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
+       void __iomem *base = i2c_dev->base;
+       u32 cr1, cr2;
+       int ret;
+
+       cr2 = readl_relaxed(base + STM32F7_I2C_CR2);
+       cr1 = readl_relaxed(base + STM32F7_I2C_CR1);
+
+       /* Set transfer direction */
+       cr2 |= STM32F7_I2C_CR2_RD_WRN;
+
+       switch (f7_msg->size) {
+       case I2C_SMBUS_BYTE_DATA:
+               f7_msg->count = 1;
+               break;
+       case I2C_SMBUS_WORD_DATA:
+       case I2C_SMBUS_PROC_CALL:
+               f7_msg->count = 2;
+               break;
+       case I2C_SMBUS_BLOCK_DATA:
+       case I2C_SMBUS_BLOCK_PROC_CALL:
+               f7_msg->count = 1;
+               cr2 |= STM32F7_I2C_CR2_RELOAD;
+               break;
+       }
+
+       f7_msg->buf = f7_msg->smbus_buf;
+       f7_msg->stop = true;
+
+       /* Add one byte for PEC if needed */
+       if (cr1 & STM32F7_I2C_CR1_PECEN)
+               f7_msg->count++;
+
+       /* Set number of bytes to be transferred */
+       cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK);
+       cr2 |= STM32F7_I2C_CR2_NBYTES(f7_msg->count);
+
+       /*
+        * Configure RX/TX interrupt:
+        */
        cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE);
+       cr1 |= STM32F7_I2C_CR1_RXIE;
 
-       /* Enable RX/TX interrupt according to msg direction */
-       if (msg->flags & I2C_M_RD)
+       /*
+        * Configure DMA or enable RX/TX interrupt:
+        * For I2C_SMBUS_BLOCK_DATA and I2C_SMBUS_BLOCK_PROC_CALL we don't use
+        * dma as we don't know in advance how many data will be received
+        */
+       cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE |
+                STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN);
+
+       i2c_dev->use_dma = false;
+       if (i2c_dev->dma && f7_msg->count >= STM32F7_I2C_DMA_LEN_MIN &&
+           f7_msg->size != I2C_SMBUS_BLOCK_DATA &&
+           f7_msg->size != I2C_SMBUS_BLOCK_PROC_CALL) {
+               ret = stm32_i2c_prep_dma_xfer(i2c_dev->dev, i2c_dev->dma,
+                                             cr2 & STM32F7_I2C_CR2_RD_WRN,
+                                             f7_msg->count, f7_msg->buf,
+                                             stm32f7_i2c_dma_callback,
+                                             i2c_dev);
+
+               if (!ret)
+                       i2c_dev->use_dma = true;
+               else
+                       dev_warn(i2c_dev->dev, "can't use DMA\n");
+       }
+
+       if (!i2c_dev->use_dma)
                cr1 |= STM32F7_I2C_CR1_RXIE;
        else
-               cr1 |= STM32F7_I2C_CR1_TXIE;
+               cr1 |= STM32F7_I2C_CR1_RXDMAEN;
 
-       /* Configure Start/Repeated Start */
+       /* Configure Repeated Start */
        cr2 |= STM32F7_I2C_CR2_START;
 
        /* Write configurations registers */
@@ -662,9 +1091,278 @@ static void stm32f7_i2c_xfer_msg(struct stm32f7_i2c_dev *i2c_dev,
        writel_relaxed(cr2, base + STM32F7_I2C_CR2);
 }
 
-static void stm32f7_i2c_disable_irq(struct stm32f7_i2c_dev *i2c_dev, u32 mask)
+static int stm32f7_i2c_smbus_check_pec(struct stm32f7_i2c_dev *i2c_dev)
 {
-       stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, mask);
+       struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
+       u8 count, internal_pec, received_pec;
+
+       internal_pec = readl_relaxed(i2c_dev->base + STM32F7_I2C_PECR);
+
+       switch (f7_msg->size) {
+       case I2C_SMBUS_BYTE:
+       case I2C_SMBUS_BYTE_DATA:
+               received_pec = f7_msg->smbus_buf[1];
+               break;
+       case I2C_SMBUS_WORD_DATA:
+       case I2C_SMBUS_PROC_CALL:
+               received_pec = f7_msg->smbus_buf[2];
+               break;
+       case I2C_SMBUS_BLOCK_DATA:
+       case I2C_SMBUS_BLOCK_PROC_CALL:
+               count = f7_msg->smbus_buf[0];
+               received_pec = f7_msg->smbus_buf[count];
+               break;
+       default:
+               dev_err(i2c_dev->dev, "Unsupported smbus protocol for PEC\n");
+               return -EINVAL;
+       }
+
+       if (internal_pec != received_pec) {
+               dev_err(i2c_dev->dev, "Bad PEC 0x%02x vs. 0x%02x\n",
+                       internal_pec, received_pec);
+               return -EBADMSG;
+       }
+
+       return 0;
+}
+
+static bool stm32f7_i2c_is_addr_match(struct i2c_client *slave, u32 addcode)
+{
+       u32 addr;
+
+       if (!slave)
+               return false;
+
+       if (slave->flags & I2C_CLIENT_TEN) {
+               /*
+                * For 10-bit addr, addcode = 11110XY with
+                * X = Bit 9 of slave address
+                * Y = Bit 8 of slave address
+                */
+               addr = slave->addr >> 8;
+               addr |= 0x78;
+               if (addr == addcode)
+                       return true;
+       } else {
+               addr = slave->addr & 0x7f;
+               if (addr == addcode)
+                       return true;
+       }
+
+       return false;
+}
+
+static void stm32f7_i2c_slave_start(struct stm32f7_i2c_dev *i2c_dev)
+{
+       struct i2c_client *slave = i2c_dev->slave_running;
+       void __iomem *base = i2c_dev->base;
+       u32 mask;
+       u8 value = 0;
+
+       if (i2c_dev->slave_dir) {
+               /* Notify i2c slave that new read transfer is starting */
+               i2c_slave_event(slave, I2C_SLAVE_READ_REQUESTED, &value);
+
+               /*
+                * Disable slave TX config in case of I2C combined message
+                * (I2C Write followed by I2C Read)
+                */
+               mask = STM32F7_I2C_CR2_RELOAD;
+               stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR2, mask);
+               mask = STM32F7_I2C_CR1_SBC | STM32F7_I2C_CR1_RXIE |
+                      STM32F7_I2C_CR1_TCIE;
+               stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1, mask);
+
+               /* Enable TX empty, STOP, NACK interrupts */
+               mask =  STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE |
+                       STM32F7_I2C_CR1_TXIE;
+               stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask);
+
+       } else {
+               /* Notify i2c slave that new write transfer is starting */
+               i2c_slave_event(slave, I2C_SLAVE_WRITE_REQUESTED, &value);
+
+               /* Set reload mode to be able to ACK/NACK each received byte */
+               mask = STM32F7_I2C_CR2_RELOAD;
+               stm32f7_i2c_set_bits(base + STM32F7_I2C_CR2, mask);
+
+               /*
+                * Set STOP, NACK, RX empty and transfer complete interrupts.*
+                * Set Slave Byte Control to be able to ACK/NACK each data
+                * byte received
+                */
+               mask =  STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE |
+                       STM32F7_I2C_CR1_SBC | STM32F7_I2C_CR1_RXIE |
+                       STM32F7_I2C_CR1_TCIE;
+               stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask);
+       }
+}
+
+static void stm32f7_i2c_slave_addr(struct stm32f7_i2c_dev *i2c_dev)
+{
+       void __iomem *base = i2c_dev->base;
+       u32 isr, addcode, dir, mask;
+       int i;
+
+       isr = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR);
+       addcode = STM32F7_I2C_ISR_ADDCODE_GET(isr);
+       dir = isr & STM32F7_I2C_ISR_DIR;
+
+       for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) {
+               if (stm32f7_i2c_is_addr_match(i2c_dev->slave[i], addcode)) {
+                       i2c_dev->slave_running = i2c_dev->slave[i];
+                       i2c_dev->slave_dir = dir;
+
+                       /* Start I2C slave processing */
+                       stm32f7_i2c_slave_start(i2c_dev);
+
+                       /* Clear ADDR flag */
+                       mask = STM32F7_I2C_ICR_ADDRCF;
+                       writel_relaxed(mask, base + STM32F7_I2C_ICR);
+                       break;
+               }
+       }
+}
+
+static int stm32f7_i2c_get_slave_id(struct stm32f7_i2c_dev *i2c_dev,
+                                   struct i2c_client *slave, int *id)
+{
+       int i;
+
+       for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) {
+               if (i2c_dev->slave[i] == slave) {
+                       *id = i;
+                       return 0;
+               }
+       }
+
+       dev_err(i2c_dev->dev, "Slave 0x%x not registered\n", slave->addr);
+
+       return -ENODEV;
+}
+
+static int stm32f7_i2c_get_free_slave_id(struct stm32f7_i2c_dev *i2c_dev,
+                                        struct i2c_client *slave, int *id)
+{
+       struct device *dev = i2c_dev->dev;
+       int i;
+
+       /*
+        * slave[0] supports 7-bit and 10-bit slave address
+        * slave[1] supports 7-bit slave address only
+        */
+       for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) {
+               if (i == 1 && (slave->flags & I2C_CLIENT_PEC))
+                       continue;
+               if (!i2c_dev->slave[i]) {
+                       *id = i;
+                       return 0;
+               }
+       }
+
+       dev_err(dev, "Slave 0x%x could not be registered\n", slave->addr);
+
+       return -EINVAL;
+}
+
+static bool stm32f7_i2c_is_slave_registered(struct stm32f7_i2c_dev *i2c_dev)
+{
+       int i;
+
+       for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) {
+               if (i2c_dev->slave[i])
+                       return true;
+       }
+
+       return false;
+}
+
+static bool stm32f7_i2c_is_slave_busy(struct stm32f7_i2c_dev *i2c_dev)
+{
+       int i, busy;
+
+       busy = 0;
+       for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) {
+               if (i2c_dev->slave[i])
+                       busy++;
+       }
+
+       return i == busy;
+}
+
+static irqreturn_t stm32f7_i2c_slave_isr_event(struct stm32f7_i2c_dev *i2c_dev)
+{
+       void __iomem *base = i2c_dev->base;
+       u32 cr2, status, mask;
+       u8 val;
+       int ret;
+
+       status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR);
+
+       /* Slave transmitter mode */
+       if (status & STM32F7_I2C_ISR_TXIS) {
+               i2c_slave_event(i2c_dev->slave_running,
+                               I2C_SLAVE_READ_PROCESSED,
+                               &val);
+
+               /* Write data byte */
+               writel_relaxed(val, base + STM32F7_I2C_TXDR);
+       }
+
+       /* Transfer Complete Reload for Slave receiver mode */
+       if (status & STM32F7_I2C_ISR_TCR || status & STM32F7_I2C_ISR_RXNE) {
+               /*
+                * Read data byte then set NBYTES to receive next byte or NACK
+                * the current received byte
+                */
+               val = readb_relaxed(i2c_dev->base + STM32F7_I2C_RXDR);
+               ret = i2c_slave_event(i2c_dev->slave_running,
+                                     I2C_SLAVE_WRITE_RECEIVED,
+                                     &val);
+               if (!ret) {
+                       cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2);
+                       cr2 |= STM32F7_I2C_CR2_NBYTES(1);
+                       writel_relaxed(cr2, i2c_dev->base + STM32F7_I2C_CR2);
+               } else {
+                       mask = STM32F7_I2C_CR2_NACK;
+                       stm32f7_i2c_set_bits(base + STM32F7_I2C_CR2, mask);
+               }
+       }
+
+       /* NACK received */
+       if (status & STM32F7_I2C_ISR_NACKF) {
+               dev_dbg(i2c_dev->dev, "<%s>: Receive NACK\n", __func__);
+               writel_relaxed(STM32F7_I2C_ICR_NACKCF, base + STM32F7_I2C_ICR);
+       }
+
+       /* STOP received */
+       if (status & STM32F7_I2C_ISR_STOPF) {
+               /* Disable interrupts */
+               stm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_XFER_IRQ_MASK);
+
+               if (i2c_dev->slave_dir) {
+                       /*
+                        * Flush TX buffer in order to not used the byte in
+                        * TXDR for the next transfer
+                        */
+                       mask = STM32F7_I2C_ISR_TXE;
+                       stm32f7_i2c_set_bits(base + STM32F7_I2C_ISR, mask);
+               }
+
+               /* Clear STOP flag */
+               writel_relaxed(STM32F7_I2C_ICR_STOPCF, base + STM32F7_I2C_ICR);
+
+               /* Notify i2c slave that a STOP flag has been detected */
+               i2c_slave_event(i2c_dev->slave_running, I2C_SLAVE_STOP, &val);
+
+               i2c_dev->slave_running = NULL;
+       }
+
+       /* Address match received */
+       if (status & STM32F7_I2C_ISR_ADDR)
+               stm32f7_i2c_slave_addr(i2c_dev);
+
+       return IRQ_HANDLED;
 }
 
 static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data)
@@ -673,6 +1371,13 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data)
        struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
        void __iomem *base = i2c_dev->base;
        u32 status, mask;
+       int ret = IRQ_HANDLED;
+
+       /* Check if the interrupt if for a slave device */
+       if (!i2c_dev->master_mode) {
+               ret = stm32f7_i2c_slave_isr_event(i2c_dev);
+               return ret;
+       }
 
        status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR);
 
@@ -694,12 +1399,21 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data)
        /* STOP detection flag */
        if (status & STM32F7_I2C_ISR_STOPF) {
                /* Disable interrupts */
-               stm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_ALL_IRQ_MASK);
+               if (stm32f7_i2c_is_slave_registered(i2c_dev))
+                       mask = STM32F7_I2C_XFER_IRQ_MASK;
+               else
+                       mask = STM32F7_I2C_ALL_IRQ_MASK;
+               stm32f7_i2c_disable_irq(i2c_dev, mask);
 
                /* Clear STOP flag */
                writel_relaxed(STM32F7_I2C_ICR_STOPCF, base + STM32F7_I2C_ICR);
 
-               complete(&i2c_dev->complete);
+               if (i2c_dev->use_dma) {
+                       ret = IRQ_WAKE_THREAD;
+               } else {
+                       i2c_dev->master_mode = false;
+                       complete(&i2c_dev->complete);
+               }
        }
 
        /* Transfer complete */
@@ -707,6 +1421,10 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data)
                if (f7_msg->stop) {
                        mask = STM32F7_I2C_CR2_STOP;
                        stm32f7_i2c_set_bits(base + STM32F7_I2C_CR2, mask);
+               } else if (i2c_dev->use_dma) {
+                       ret = IRQ_WAKE_THREAD;
+               } else if (f7_msg->smbus) {
+                       stm32f7_i2c_smbus_rep_start(i2c_dev);
                } else {
                        i2c_dev->msg_id++;
                        i2c_dev->msg++;
@@ -714,13 +1432,50 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data)
                }
        }
 
+       if (status & STM32F7_I2C_ISR_TCR) {
+               if (f7_msg->smbus)
+                       stm32f7_i2c_smbus_reload(i2c_dev);
+               else
+                       stm32f7_i2c_reload(i2c_dev);
+       }
+
+       return ret;
+}
+
+static irqreturn_t stm32f7_i2c_isr_event_thread(int irq, void *data)
+{
+       struct stm32f7_i2c_dev *i2c_dev = data;
+       struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
+       struct stm32_i2c_dma *dma = i2c_dev->dma;
+       u32 status;
+       int ret;
+
        /*
-        * Transfer Complete Reload: 255 data bytes have been transferred
-        * We have to prepare the I2C controller to transfer the remaining
-        * data.
+        * Wait for dma transfer completion before sending next message or
+        * notity the end of xfer to the client
         */
-       if (status & STM32F7_I2C_ISR_TCR)
-               stm32f7_i2c_reload(i2c_dev);
+       ret = wait_for_completion_timeout(&i2c_dev->dma->dma_complete, HZ);
+       if (!ret) {
+               dev_dbg(i2c_dev->dev, "<%s>: Timed out\n", __func__);
+               stm32f7_i2c_disable_dma_req(i2c_dev);
+               dmaengine_terminate_all(dma->chan_using);
+               f7_msg->result = -ETIMEDOUT;
+       }
+
+       status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR);
+
+       if (status & STM32F7_I2C_ISR_TC) {
+               if (f7_msg->smbus) {
+                       stm32f7_i2c_smbus_rep_start(i2c_dev);
+               } else {
+                       i2c_dev->msg_id++;
+                       i2c_dev->msg++;
+                       stm32f7_i2c_xfer_msg(i2c_dev, i2c_dev->msg);
+               }
+       } else {
+               i2c_dev->master_mode = false;
+               complete(&i2c_dev->complete);
+       }
 
        return IRQ_HANDLED;
 }
@@ -731,7 +1486,8 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data)
        struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
        void __iomem *base = i2c_dev->base;
        struct device *dev = i2c_dev->dev;
-       u32 status;
+       struct stm32_i2c_dma *dma = i2c_dev->dma;
+       u32 mask, status;
 
        status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR);
 
@@ -739,6 +1495,7 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data)
        if (status & STM32F7_I2C_ISR_BERR) {
                dev_err(dev, "<%s>: Bus error\n", __func__);
                writel_relaxed(STM32F7_I2C_ICR_BERRCF, base + STM32F7_I2C_ICR);
+               stm32f7_i2c_release_bus(&i2c_dev->adap);
                f7_msg->result = -EIO;
        }
 
@@ -749,8 +1506,26 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data)
                f7_msg->result = -EAGAIN;
        }
 
-       stm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_ALL_IRQ_MASK);
+       if (status & STM32F7_I2C_ISR_PECERR) {
+               dev_err(dev, "<%s>: PEC error in reception\n", __func__);
+               writel_relaxed(STM32F7_I2C_ICR_PECCF, base + STM32F7_I2C_ICR);
+               f7_msg->result = -EINVAL;
+       }
+
+       /* Disable interrupts */
+       if (stm32f7_i2c_is_slave_registered(i2c_dev))
+               mask = STM32F7_I2C_XFER_IRQ_MASK;
+       else
+               mask = STM32F7_I2C_ALL_IRQ_MASK;
+       stm32f7_i2c_disable_irq(i2c_dev, mask);
+
+       /* Disable dma */
+       if (i2c_dev->use_dma) {
+               stm32f7_i2c_disable_dma_req(i2c_dev);
+               dmaengine_terminate_all(dma->chan_using);
+       }
 
+       i2c_dev->master_mode = false;
        complete(&i2c_dev->complete);
 
        return IRQ_HANDLED;
@@ -761,12 +1536,14 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap,
 {
        struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap);
        struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
+       struct stm32_i2c_dma *dma = i2c_dev->dma;
        unsigned long time_left;
        int ret;
 
        i2c_dev->msg = msgs;
        i2c_dev->msg_num = num;
        i2c_dev->msg_id = 0;
+       f7_msg->smbus = false;
 
        ret = clk_enable(i2c_dev->clk);
        if (ret) {
@@ -787,6 +1564,8 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap,
        if (!time_left) {
                dev_dbg(i2c_dev->dev, "Access to slave 0x%x timed out\n",
                        i2c_dev->msg->addr);
+               if (i2c_dev->use_dma)
+                       dmaengine_terminate_all(dma->chan_using);
                ret = -ETIMEDOUT;
        }
 
@@ -796,14 +1575,209 @@ clk_free:
        return (ret < 0) ? ret : num;
 }
 
+static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
+                                 unsigned short flags, char read_write,
+                                 u8 command, int size,
+                                 union i2c_smbus_data *data)
+{
+       struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(adapter);
+       struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
+       struct stm32_i2c_dma *dma = i2c_dev->dma;
+       struct device *dev = i2c_dev->dev;
+       unsigned long timeout;
+       int i, ret;
+
+       f7_msg->addr = addr;
+       f7_msg->size = size;
+       f7_msg->read_write = read_write;
+       f7_msg->smbus = true;
+
+       ret = clk_enable(i2c_dev->clk);
+       if (ret) {
+               dev_err(i2c_dev->dev, "Failed to enable clock\n");
+               return ret;
+       }
+
+       ret = stm32f7_i2c_wait_free_bus(i2c_dev);
+       if (ret)
+               goto clk_free;
+
+       ret = stm32f7_i2c_smbus_xfer_msg(i2c_dev, flags, command, data);
+       if (ret)
+               goto clk_free;
+
+       timeout = wait_for_completion_timeout(&i2c_dev->complete,
+                                             i2c_dev->adap.timeout);
+       ret = f7_msg->result;
+       if (ret)
+               goto clk_free;
+
+       if (!timeout) {
+               dev_dbg(dev, "Access to slave 0x%x timed out\n", f7_msg->addr);
+               if (i2c_dev->use_dma)
+                       dmaengine_terminate_all(dma->chan_using);
+               ret = -ETIMEDOUT;
+               goto clk_free;
+       }
+
+       /* Check PEC */
+       if ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK && read_write) {
+               ret = stm32f7_i2c_smbus_check_pec(i2c_dev);
+               if (ret)
+                       goto clk_free;
+       }
+
+       if (read_write && size != I2C_SMBUS_QUICK) {
+               switch (size) {
+               case I2C_SMBUS_BYTE:
+               case I2C_SMBUS_BYTE_DATA:
+                       data->byte = f7_msg->smbus_buf[0];
+               break;
+               case I2C_SMBUS_WORD_DATA:
+               case I2C_SMBUS_PROC_CALL:
+                       data->word = f7_msg->smbus_buf[0] |
+                               (f7_msg->smbus_buf[1] << 8);
+               break;
+               case I2C_SMBUS_BLOCK_DATA:
+               case I2C_SMBUS_BLOCK_PROC_CALL:
+               for (i = 0; i <= f7_msg->smbus_buf[0]; i++)
+                       data->block[i] = f7_msg->smbus_buf[i];
+               break;
+               default:
+                       dev_err(dev, "Unsupported smbus transaction\n");
+                       ret = -EINVAL;
+               }
+       }
+
+clk_free:
+       clk_disable(i2c_dev->clk);
+       return ret;
+}
+
+static int stm32f7_i2c_reg_slave(struct i2c_client *slave)
+{
+       struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(slave->adapter);
+       void __iomem *base = i2c_dev->base;
+       struct device *dev = i2c_dev->dev;
+       u32 oar1, oar2, mask;
+       int id, ret;
+
+       if (slave->flags & I2C_CLIENT_PEC) {
+               dev_err(dev, "SMBus PEC not supported in slave mode\n");
+               return -EINVAL;
+       }
+
+       if (stm32f7_i2c_is_slave_busy(i2c_dev)) {
+               dev_err(dev, "Too much slave registered\n");
+               return -EBUSY;
+       }
+
+       ret = stm32f7_i2c_get_free_slave_id(i2c_dev, slave, &id);
+       if (ret)
+               return ret;
+
+       if (!(stm32f7_i2c_is_slave_registered(i2c_dev))) {
+               ret = clk_enable(i2c_dev->clk);
+               if (ret) {
+                       dev_err(dev, "Failed to enable clock\n");
+                       return ret;
+               }
+       }
+
+       if (id == 0) {
+               /* Configure Own Address 1 */
+               oar1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR1);
+               oar1 &= ~STM32F7_I2C_OAR1_MASK;
+               if (slave->flags & I2C_CLIENT_TEN) {
+                       oar1 |= STM32F7_I2C_OAR1_OA1_10(slave->addr);
+                       oar1 |= STM32F7_I2C_OAR1_OA1MODE;
+               } else {
+                       oar1 |= STM32F7_I2C_OAR1_OA1_7(slave->addr);
+               }
+               oar1 |= STM32F7_I2C_OAR1_OA1EN;
+               i2c_dev->slave[id] = slave;
+               writel_relaxed(oar1, i2c_dev->base + STM32F7_I2C_OAR1);
+       } else if (id == 1) {
+               /* Configure Own Address 2 */
+               oar2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR2);
+               oar2 &= ~STM32F7_I2C_OAR2_MASK;
+               if (slave->flags & I2C_CLIENT_TEN) {
+                       ret = -EOPNOTSUPP;
+                       goto exit;
+               }
+
+               oar2 |= STM32F7_I2C_OAR2_OA2_7(slave->addr);
+               oar2 |= STM32F7_I2C_OAR2_OA2EN;
+               i2c_dev->slave[id] = slave;
+               writel_relaxed(oar2, i2c_dev->base + STM32F7_I2C_OAR2);
+       } else {
+               ret = -ENODEV;
+               goto exit;
+       }
+
+       /* Enable ACK */
+       stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR2, STM32F7_I2C_CR2_NACK);
+
+       /* Enable Address match interrupt, error interrupt and enable I2C  */
+       mask = STM32F7_I2C_CR1_ADDRIE | STM32F7_I2C_CR1_ERRIE |
+               STM32F7_I2C_CR1_PE;
+       stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask);
+
+       return 0;
+
+exit:
+       if (!(stm32f7_i2c_is_slave_registered(i2c_dev)))
+               clk_disable(i2c_dev->clk);
+
+       return ret;
+}
+
+static int stm32f7_i2c_unreg_slave(struct i2c_client *slave)
+{
+       struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(slave->adapter);
+       void __iomem *base = i2c_dev->base;
+       u32 mask;
+       int id, ret;
+
+       ret = stm32f7_i2c_get_slave_id(i2c_dev, slave, &id);
+       if (ret)
+               return ret;
+
+       WARN_ON(!i2c_dev->slave[id]);
+
+       if (id == 0) {
+               mask = STM32F7_I2C_OAR1_OA1EN;
+               stm32f7_i2c_clr_bits(base + STM32F7_I2C_OAR1, mask);
+       } else {
+               mask = STM32F7_I2C_OAR2_OA2EN;
+               stm32f7_i2c_clr_bits(base + STM32F7_I2C_OAR2, mask);
+       }
+
+       i2c_dev->slave[id] = NULL;
+
+       if (!(stm32f7_i2c_is_slave_registered(i2c_dev))) {
+               stm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_ALL_IRQ_MASK);
+               clk_disable(i2c_dev->clk);
+       }
+
+       return 0;
+}
+
 static u32 stm32f7_i2c_func(struct i2c_adapter *adap)
 {
-       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+       return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SLAVE |
+               I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+               I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+               I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
+               I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_PEC;
 }
 
 static struct i2c_algorithm stm32f7_i2c_algo = {
        .master_xfer = stm32f7_i2c_xfer,
+       .smbus_xfer = stm32f7_i2c_smbus_xfer,
        .functionality = stm32f7_i2c_func,
+       .reg_slave = stm32f7_i2c_reg_slave,
+       .unreg_slave = stm32f7_i2c_unreg_slave,
 };
 
 static int stm32f7_i2c_probe(struct platform_device *pdev)
@@ -815,6 +1789,7 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
        u32 irq_error, irq_event, clk_rate, rise_time, fall_time;
        struct i2c_adapter *adap;
        struct reset_control *rst;
+       dma_addr_t phy_addr;
        int ret;
 
        i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
@@ -825,6 +1800,7 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
        i2c_dev->base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(i2c_dev->base))
                return PTR_ERR(i2c_dev->base);
+       phy_addr = (dma_addr_t)res->start;
 
        irq_event = irq_of_parse_and_map(np, 0);
        if (!irq_event) {
@@ -871,8 +1847,11 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
 
        i2c_dev->dev = &pdev->dev;
 
-       ret = devm_request_irq(&pdev->dev, irq_event, stm32f7_i2c_isr_event, 0,
-                              pdev->name, i2c_dev);
+       ret = devm_request_threaded_irq(&pdev->dev, irq_event,
+                                       stm32f7_i2c_isr_event,
+                                       stm32f7_i2c_isr_event_thread,
+                                       IRQF_ONESHOT,
+                                       pdev->name, i2c_dev);
        if (ret) {
                dev_err(&pdev->dev, "Failed to request irq event %i\n",
                        irq_event);
@@ -924,6 +1903,11 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
 
        init_completion(&i2c_dev->complete);
 
+       /* Init DMA config if supported */
+       i2c_dev->dma = stm32_i2c_dma_request(i2c_dev->dev, phy_addr,
+                                            STM32F7_I2C_TXDR,
+                                            STM32F7_I2C_RXDR);
+
        ret = i2c_add_adapter(adap);
        if (ret)
                goto clk_free;
@@ -946,6 +1930,11 @@ static int stm32f7_i2c_remove(struct platform_device *pdev)
 {
        struct stm32f7_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
 
+       if (i2c_dev->dma) {
+               stm32_i2c_dma_free(i2c_dev->dma);
+               i2c_dev->dma = NULL;
+       }
+
        i2c_del_adapter(&i2c_dev->adap);
 
        clk_unprepare(i2c_dev->clk);
index dc63236b45b21669922a77155bd2c244ec456dde..e866c481bfc325d3c42e733faa88d133b3388f0d 100644 (file)
@@ -602,20 +602,24 @@ static int stu300_send_address(struct stu300_dev *dev,
        u32 val;
        int ret;
 
-       if (msg->flags & I2C_M_TEN)
+       if (msg->flags & I2C_M_TEN) {
                /* This is probably how 10 bit addresses look */
                val = (0xf0 | (((u32) msg->addr & 0x300) >> 7)) &
                        I2C_DR_D_MASK;
-       else
-               val = ((msg->addr << 1) & I2C_DR_D_MASK);
+               if (msg->flags & I2C_M_RD)
+                       /* This is the direction bit */
+                       val |= 0x01;
+       } else {
+               val = i2c_8bit_addr_from_msg(msg);
+       }
 
-       if (msg->flags & I2C_M_RD) {
-               /* This is the direction bit */
-               val |= 0x01;
-               if (resend)
+       if (resend) {
+               if (msg->flags & I2C_M_RD)
                        dev_dbg(&dev->pdev->dev, "read resend\n");
-       } else if (resend)
-               dev_dbg(&dev->pdev->dev, "write resend\n");
+               else
+                       dev_dbg(&dev->pdev->dev, "write resend\n");
+       }
+
        stu300_wr8(val, dev->virtbase + I2C_DR);
 
        /* For 10bit addressing, await 10bit request (EVENT 9) */
index a021f866d8c24e2e6849db042ee64ef0bd44177d..915f5edbab3319212c1e22ae3274ce63de468d18 100644 (file)
@@ -509,7 +509,7 @@ static int synquacer_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
 
        dev_dbg(i2c->dev, "calculated timeout %d ms\n", i2c->timeout_ms);
 
-       for (retry = 0; retry < adap->retries; retry++) {
+       for (retry = 0; retry <= adap->retries; retry++) {
                ret = synquacer_i2c_doxfer(i2c, msgs, num);
                if (ret != -EAGAIN)
                        return ret;
index 60292d243e249c60fbc8ef89b0d4714fe6c21772..5fccd1f1bca85d28bcc249fa6b76f4297bf504bb 100644 (file)
@@ -173,7 +173,6 @@ struct tegra_i2c_hw_feature {
  * @msg_buf_remaining: size of unsent data in the message buffer
  * @msg_read: identifies read transfers
  * @bus_clk_rate: current i2c bus clock rate
- * @is_suspended: prevents i2c controller accesses after suspend is called
  */
 struct tegra_i2c_dev {
        struct device *dev;
@@ -194,7 +193,6 @@ struct tegra_i2c_dev {
        int msg_read;
        u32 bus_clk_rate;
        u16 clk_divisor_non_hs_mode;
-       bool is_suspended;
        bool is_multimaster_mode;
        spinlock_t xfer_lock;
 };
@@ -734,9 +732,6 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
        int i;
        int ret = 0;
 
-       if (i2c_dev->is_suspended)
-               return -EBUSY;
-
        ret = pm_runtime_get_sync(i2c_dev->dev);
        if (ret < 0) {
                dev_err(i2c_dev->dev, "runtime resume failed %d\n", ret);
@@ -1051,37 +1046,9 @@ static int tegra_i2c_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM_SLEEP
-static int tegra_i2c_suspend(struct device *dev)
-{
-       struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
-
-       i2c_lock_adapter(&i2c_dev->adapter);
-       i2c_dev->is_suspended = true;
-       i2c_unlock_adapter(&i2c_dev->adapter);
-
-       return 0;
-}
-
-static int tegra_i2c_resume(struct device *dev)
-{
-       struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
-       int ret;
-
-       i2c_lock_adapter(&i2c_dev->adapter);
-
-       ret = tegra_i2c_init(i2c_dev);
-       if (!ret)
-               i2c_dev->is_suspended = false;
-
-       i2c_unlock_adapter(&i2c_dev->adapter);
-
-       return ret;
-}
-
 static const struct dev_pm_ops tegra_i2c_pm = {
        SET_RUNTIME_PM_OPS(tegra_i2c_runtime_suspend, tegra_i2c_runtime_resume,
                           NULL)
-       SET_SYSTEM_SLEEP_PM_OPS(tegra_i2c_suspend, tegra_i2c_resume)
 };
 #define TEGRA_I2C_PM   (&tegra_i2c_pm)
 #else
index c80527816ad0ab99b52b92b36d1f70bcf867a33f..9a71e50d21f1fbae53ebdb2b1831e7f6067a67b9 100644 (file)
@@ -33,7 +33,7 @@
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/wait.h>
-#include <linux/i2c-xiic.h>
+#include <linux/platform_data/i2c-xiic.h>
 #include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/of.h>
@@ -143,12 +143,6 @@ struct xiic_i2c {
 
 #define XIIC_TX_RX_INTERRUPTS (XIIC_INTR_RX_FULL_MASK | XIIC_TX_INTERRUPTS)
 
-/* The following constants are used with the following macros to specify the
- * operation, a read or write operation.
- */
-#define XIIC_READ_OPERATION  1
-#define XIIC_WRITE_OPERATION 0
-
 /*
  * Tx Fifo upper bit masks.
  */
@@ -415,7 +409,7 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
                clr |= XIIC_INTR_RX_FULL_MASK;
                if (!i2c->rx_msg) {
                        dev_dbg(i2c->adap.dev.parent,
-                               "%s unexpexted RX IRQ\n", __func__);
+                               "%s unexpected RX IRQ\n", __func__);
                        xiic_clear_rx_fifo(i2c);
                        goto out;
                }
@@ -470,7 +464,7 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
 
                if (!i2c->tx_msg) {
                        dev_dbg(i2c->adap.dev.parent,
-                               "%s unexpexted TX IRQ\n", __func__);
+                               "%s unexpected TX IRQ\n", __func__);
                        goto out;
                }
 
@@ -556,8 +550,7 @@ static void xiic_start_recv(struct xiic_i2c *i2c)
        if (!(msg->flags & I2C_M_NOSTART))
                /* write the address */
                xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET,
-                       (msg->addr << 1) | XIIC_READ_OPERATION |
-                       XIIC_TX_DYN_START_MASK);
+                       i2c_8bit_addr_from_msg(msg) | XIIC_TX_DYN_START_MASK);
 
        xiic_irq_clr_en(i2c, XIIC_INTR_BNB_MASK);
 
@@ -585,7 +578,7 @@ static void xiic_start_send(struct xiic_i2c *i2c)
 
        if (!(msg->flags & I2C_M_NOSTART)) {
                /* write the address */
-               u16 data = ((msg->addr << 1) & 0xfe) | XIIC_WRITE_OPERATION |
+               u16 data = i2c_8bit_addr_from_msg(msg) |
                        XIIC_TX_DYN_START_MASK;
                if ((i2c->nmsgs == 1) && msg->len == 0)
                        /* no data and last message -> add STOP */
index eb8913eba0c5c144c7d1b0986f51862bac1887f7..1f41a4f89c08f4c4b2da8cf3f0feb2bd643e9b5e 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/clk.h>
 #include <linux/completion.h>
 #include <linux/i2c.h>
+#include <linux/i2c-smbus.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
@@ -84,6 +85,8 @@ struct xlp9xx_i2c_dev {
        struct device *dev;
        struct i2c_adapter adapter;
        struct completion msg_complete;
+       struct i2c_smbus_alert_setup alert_data;
+       struct i2c_client *ara;
        int irq;
        bool msg_read;
        bool len_recv;
@@ -155,9 +158,30 @@ static void xlp9xx_i2c_fill_tx_fifo(struct xlp9xx_i2c_dev *priv)
        priv->msg_buf += len;
 }
 
+static void xlp9xx_i2c_update_rlen(struct xlp9xx_i2c_dev *priv)
+{
+       u32 val, len;
+
+       /*
+        * Update receive length. Re-read len to get the latest value,
+        * and then add 4 to have a minimum value that can be safely
+        * written. This is to account for the byte read above, the
+        * transfer in progress and any delays in the register I/O
+        */
+       val = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_CTRL);
+       len = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_FIFOWCNT) &
+                                 XLP9XX_I2C_FIFO_WCNT_MASK;
+       len = max_t(u32, priv->msg_len, len + 4);
+       if (len >= I2C_SMBUS_BLOCK_MAX + 2)
+               return;
+       val = (val & ~XLP9XX_I2C_CTRL_MCTLEN_MASK) |
+                       (len << XLP9XX_I2C_CTRL_MCTLEN_SHIFT);
+       xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, val);
+}
+
 static void xlp9xx_i2c_drain_rx_fifo(struct xlp9xx_i2c_dev *priv)
 {
-       u32 len, i, val;
+       u32 len, i;
        u8 rlen, *buf = priv->msg_buf;
 
        len = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_FIFOWCNT) &
@@ -167,21 +191,20 @@ static void xlp9xx_i2c_drain_rx_fifo(struct xlp9xx_i2c_dev *priv)
        if (priv->len_recv) {
                /* read length byte */
                rlen = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO);
-               *buf++ = rlen;
-               len--;
-
-               if (priv->client_pec)
-                       ++rlen;
-               /* update remaining bytes and message length */
-               priv->msg_buf_remaining = rlen;
-               priv->msg_len = rlen + 1;
+               if (rlen > I2C_SMBUS_BLOCK_MAX || rlen == 0) {
+                       rlen = 0;       /*abort transfer */
+                       priv->msg_buf_remaining = 0;
+                       priv->msg_len = 0;
+               } else {
+                       *buf++ = rlen;
+                       if (priv->client_pec)
+                               ++rlen; /* account for error check byte */
+                       /* update remaining bytes and message length */
+                       priv->msg_buf_remaining = rlen;
+                       priv->msg_len = rlen + 1;
+               }
+               xlp9xx_i2c_update_rlen(priv);
                priv->len_recv = false;
-
-               /* Update transfer length to read only actual data */
-               val = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_CTRL);
-               val = (val & ~XLP9XX_I2C_CTRL_MCTLEN_MASK) |
-                       ((rlen + 1) << XLP9XX_I2C_CTRL_MCTLEN_SHIFT);
-               xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, val);
        } else {
                len = min(priv->msg_buf_remaining, len);
                for (i = 0; i < len; i++, buf++)
@@ -300,10 +323,6 @@ static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg,
        xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MFIFOCTRL,
                             XLP9XX_I2C_MFIFOCTRL_RST);
 
-       /* set FIFO threshold if reading */
-       if (priv->msg_read)
-               xlp9xx_i2c_update_rx_fifo_thres(priv);
-
        /* set slave addr */
        xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_SLAVEADDR,
                             (msg->addr << XLP9XX_I2C_SLAVEADDR_ADDR_SHIFT) |
@@ -322,9 +341,13 @@ static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg,
                val &= ~XLP9XX_I2C_CTRL_ADDMODE;
 
        priv->len_recv = msg->flags & I2C_M_RECV_LEN;
-       len = priv->len_recv ? XLP9XX_I2C_FIFO_SIZE : msg->len;
+       len = priv->len_recv ? I2C_SMBUS_BLOCK_MAX + 2 : msg->len;
        priv->client_pec = msg->flags & I2C_CLIENT_PEC;
 
+       /* set FIFO threshold if reading */
+       if (priv->msg_read)
+               xlp9xx_i2c_update_rx_fifo_thres(priv);
+
        /* set data length to be transferred */
        val = (val & ~XLP9XX_I2C_CTRL_MCTLEN_MASK) |
              (len << XLP9XX_I2C_CTRL_MCTLEN_SHIFT);
@@ -378,8 +401,11 @@ static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg,
        }
 
        /* update msg->len with actual received length */
-       if (msg->flags & I2C_M_RECV_LEN)
+       if (msg->flags & I2C_M_RECV_LEN) {
+               if (!priv->msg_len)
+                       return -EPROTO;
                msg->len = priv->msg_len;
+       }
        return 0;
 }
 
@@ -447,6 +473,19 @@ static int xlp9xx_i2c_get_frequency(struct platform_device *pdev,
        return 0;
 }
 
+static int xlp9xx_i2c_smbus_setup(struct xlp9xx_i2c_dev *priv,
+                                 struct platform_device *pdev)
+{
+       if (!priv->alert_data.irq)
+               return -EINVAL;
+
+       priv->ara = i2c_setup_smbus_alert(&priv->adapter, &priv->alert_data);
+       if (!priv->ara)
+               return -ENODEV;
+
+       return 0;
+}
+
 static int xlp9xx_i2c_probe(struct platform_device *pdev)
 {
        struct xlp9xx_i2c_dev *priv;
@@ -467,6 +506,10 @@ static int xlp9xx_i2c_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "invalid irq!\n");
                return priv->irq;
        }
+       /* SMBAlert irq */
+       priv->alert_data.irq = platform_get_irq(pdev, 1);
+       if (priv->alert_data.irq <= 0)
+               priv->alert_data.irq = 0;
 
        xlp9xx_i2c_get_frequency(pdev, priv);
        xlp9xx_i2c_init(priv);
@@ -493,6 +536,10 @@ static int xlp9xx_i2c_probe(struct platform_device *pdev)
        if (err)
                return err;
 
+       err = xlp9xx_i2c_smbus_setup(priv, pdev);
+       if (err)
+               dev_dbg(&pdev->dev, "No active SMBus alert %d\n", err);
+
        platform_set_drvdata(pdev, priv);
        dev_dbg(&pdev->dev, "I2C bus:%d added\n", priv->adapter.nr);
 
index a17f46a95f73d63e0d2a854304994da6e6722afa..31d16ada6e7d9a789240cc62f50a7fcde840bb2e 100644 (file)
@@ -717,10 +717,6 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
        client->adapter = adap;
 
        client->dev.platform_data = info->platform_data;
-
-       if (info->archdata)
-               client->dev.archdata = *info->archdata;
-
        client->flags = info->flags;
        client->addr = info->addr;
 
@@ -746,7 +742,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
        client->dev.parent = &client->adapter->dev;
        client->dev.bus = &i2c_bus_type;
        client->dev.type = &i2c_client_type;
-       client->dev.of_node = info->of_node;
+       client->dev.of_node = of_node_get(info->of_node);
        client->dev.fwnode = info->fwnode;
 
        i2c_dev_set_name(adap, client, info);
@@ -757,7 +753,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
                        dev_err(&adap->dev,
                                "Failed to add properties to client %s: %d\n",
                                client->name, status);
-                       goto out_err;
+                       goto out_err_put_of_node;
                }
        }
 
@@ -773,6 +769,8 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
 out_free_props:
        if (info->properties)
                device_remove_properties(&client->dev);
+out_err_put_of_node:
+       of_node_put(info->of_node);
 out_err:
        dev_err(&adap->dev,
                "Failed to register i2c client %s at 0x%02x (%d)\n",
index c405270a98b4f01c89944e91f9dc4bba3b4620c4..6cb7ad608bcd53d9c966752a342562208aa7617e 100644 (file)
 
 #include "i2c-core.h"
 
-static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap,
-                                                struct device_node *node)
+int of_i2c_get_board_info(struct device *dev, struct device_node *node,
+                         struct i2c_board_info *info)
 {
-       struct i2c_client *client;
-       struct i2c_board_info info = {};
-       struct dev_archdata dev_ad = {};
        u32 addr;
        int ret;
 
-       dev_dbg(&adap->dev, "of_i2c: register %pOF\n", node);
+       memset(info, 0, sizeof(*info));
 
-       if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) {
-               dev_err(&adap->dev, "of_i2c: modalias failure on %pOF\n",
-                       node);
-               return ERR_PTR(-EINVAL);
+       if (of_modalias_node(node, info->type, sizeof(info->type)) < 0) {
+               dev_err(dev, "of_i2c: modalias failure on %pOF\n", node);
+               return -EINVAL;
        }
 
        ret = of_property_read_u32(node, "reg", &addr);
        if (ret) {
-               dev_err(&adap->dev, "of_i2c: invalid reg on %pOF\n", node);
-               return ERR_PTR(ret);
+               dev_err(dev, "of_i2c: invalid reg on %pOF\n", node);
+               return ret;
        }
 
        if (addr & I2C_TEN_BIT_ADDRESS) {
                addr &= ~I2C_TEN_BIT_ADDRESS;
-               info.flags |= I2C_CLIENT_TEN;
+               info->flags |= I2C_CLIENT_TEN;
        }
 
        if (addr & I2C_OWN_SLAVE_ADDRESS) {
                addr &= ~I2C_OWN_SLAVE_ADDRESS;
-               info.flags |= I2C_CLIENT_SLAVE;
+               info->flags |= I2C_CLIENT_SLAVE;
        }
 
-       info.addr = addr;
-       info.archdata = &dev_ad;
-       info.of_node = of_node_get(node);
+       info->addr = addr;
+       info->of_node = node;
 
        if (of_property_read_bool(node, "host-notify"))
-               info.flags |= I2C_CLIENT_HOST_NOTIFY;
+               info->flags |= I2C_CLIENT_HOST_NOTIFY;
 
        if (of_get_property(node, "wakeup-source", NULL))
-               info.flags |= I2C_CLIENT_WAKE;
+               info->flags |= I2C_CLIENT_WAKE;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(of_i2c_get_board_info);
+
+static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap,
+                                                struct device_node *node)
+{
+       struct i2c_client *client;
+       struct i2c_board_info info;
+       int ret;
+
+       dev_dbg(&adap->dev, "of_i2c: register %pOF\n", node);
+
+       ret = of_i2c_get_board_info(&adap->dev, node, &info);
+       if (ret)
+               return ERR_PTR(ret);
 
        client = i2c_new_device(adap, &info);
        if (!client) {
                dev_err(&adap->dev, "of_i2c: Failure registering %pOF\n", node);
-               of_node_put(node);
                return ERR_PTR(-EINVAL);
        }
        return client;
index b5aec33002c3a66eb6339077e512516d5460b59e..f3f683041e7f9199ad5799ef5c8fd83f59fc9856 100644 (file)
@@ -466,6 +466,8 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
        status = i2c_transfer(adapter, msg, num);
        if (status < 0)
                return status;
+       if (status != num)
+               return -EIO;
 
        /* Check PEC if last message is a read */
        if (i && (msg[num-1].flags & I2C_M_RD)) {
index 9669ca4937b891063d4cd63e552344d818f5eefa..300ab4b672e4992921b164a40d77d9e426fda305 100644 (file)
@@ -418,7 +418,7 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc,
        snprintf(symlink_name, sizeof(symlink_name), "channel-%u", chan_id);
        WARN(sysfs_create_link(&muxc->dev->kobj, &priv->adap.dev.kobj,
                               symlink_name),
-            "can't create symlink for channel %u\n", chan_id);
+            "can't create symlink to channel %u\n", chan_id);
        dev_info(&parent->dev, "Added multiplexed i2c bus %d\n",
                 i2c_adapter_id(&priv->adap));
 
index 33ce032cb70112e9a3304f789198fbb75602a47c..035032e203276e96b27dd57770f47af98ee5146f 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/of.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <linux/sysfs.h>
 
@@ -105,7 +106,7 @@ static int i2c_demux_activate_master(struct i2c_demux_pinctrl_priv *priv, u32 ne
        priv->cur_adap.owner = THIS_MODULE;
        priv->cur_adap.algo = &priv->algo;
        priv->cur_adap.algo_data = priv;
-       priv->cur_adap.dev.parent = priv->dev;
+       priv->cur_adap.dev.parent = &adap->dev;
        priv->cur_adap.class = adap->class;
        priv->cur_adap.retries = adap->retries;
        priv->cur_adap.timeout = adap->timeout;
@@ -254,6 +255,8 @@ static int i2c_demux_pinctrl_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, priv);
 
+       pm_runtime_no_callbacks(&pdev->dev);
+
        /* switch to first parent as active master */
        i2c_demux_activate_master(priv, 0);
 
index ddc4bd4ca13b3be4b170f395441223d9dc520adb..401308e3d036fe54ad172690d9ba5ac0ee54b7e3 100644 (file)
@@ -10,7 +10,7 @@
 
 #include <linux/i2c.h>
 #include <linux/i2c-mux.h>
-#include <linux/i2c-mux-gpio.h>
+#include <linux/platform_data/i2c-mux-gpio.h>
 #include <linux/platform_device.h>
 #include <linux/module.h>
 #include <linux/slab.h>
index 311b1cced0c041b6bb019c8b281192de1169479c..a9af93259b19df97c4a60da563ffb2174125b42c 100644 (file)
@@ -206,8 +206,7 @@ static const struct of_device_id ltc4306_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, ltc4306_of_match);
 
-static int ltc4306_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
+static int ltc4306_probe(struct i2c_client *client)
 {
        struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
        const struct chip_desc *chip;
@@ -221,7 +220,7 @@ static int ltc4306_probe(struct i2c_client *client,
        chip = of_device_get_match_data(&client->dev);
 
        if (!chip)
-               chip = &chips[id->driver_data];
+               chip = &chips[i2c_match_id(ltc4306_id, client)->driver_data];
 
        idle_disc = device_property_read_bool(&client->dev,
                                              "i2c-mux-idle-disconnect");
@@ -310,7 +309,7 @@ static struct i2c_driver ltc4306_driver = {
                .name   = "ltc4306",
                .of_match_table = of_match_ptr(ltc4306_of_match),
        },
-       .probe          = ltc4306_probe,
+       .probe_new      = ltc4306_probe,
        .remove         = ltc4306_remove,
        .id_table       = ltc4306_id,
 };
index 09bafd3e68faf8a5bd600cb0a8fd6464443985f3..fbc748027087dbfd9783a459ccc74a7834d1a480 100644 (file)
@@ -36,6 +36,7 @@
  */
 
 #include <linux/device.h>
+#include <linux/delay.h>
 #include <linux/gpio/consumer.h>
 #include <linux/i2c.h>
 #include <linux/i2c-mux.h>
@@ -373,7 +374,6 @@ static int pca954x_probe(struct i2c_client *client,
        int num, force, class;
        struct i2c_mux_core *muxc;
        struct pca954x *data;
-       const struct of_device_id *match;
        int ret;
 
        if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE))
@@ -389,15 +389,19 @@ static int pca954x_probe(struct i2c_client *client,
        i2c_set_clientdata(client, muxc);
        data->client = client;
 
-       /* Get the mux out of reset if a reset GPIO is specified. */
-       gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_LOW);
+       /* Reset the mux if a reset GPIO is specified. */
+       gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_HIGH);
        if (IS_ERR(gpio))
                return PTR_ERR(gpio);
+       if (gpio) {
+               udelay(1);
+               gpiod_set_value_cansleep(gpio, 0);
+               /* Give the chip some time to recover. */
+               udelay(1);
+       }
 
-       match = of_match_device(of_match_ptr(pca954x_of_match), &client->dev);
-       if (match)
-               data->chip = of_device_get_match_data(&client->dev);
-       else
+       data->chip = of_device_get_match_data(&client->dev);
+       if (!data->chip)
                data->chip = &chips[id->driver_data];
 
        if (data->chip->id.manufacturer_id != I2C_DEVICE_ID_NONE) {
index f583f805fee9e5f7c96912a79eb67fdf24b3a3da..5653295b01cd35c2a701335f976641fb9946f260 100644 (file)
@@ -127,10 +127,8 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux,
        values = devm_kcalloc(&pdev->dev,
                              mux->data.n_values, sizeof(*mux->data.values),
                              GFP_KERNEL);
-       if (!values) {
-               dev_err(&pdev->dev, "Cannot allocate values array");
+       if (!values)
                return -ENOMEM;
-       }
 
        for_each_child_of_node(np, child) {
                of_property_read_u32(child, "reg", values + i);
index ff80377987795df3bdd3755e55806499ea54d6d2..c5992cd195a118fdcec03944d9f326bb487bfd42 100644 (file)
@@ -16,7 +16,7 @@ config INPUT
 
          Say N here if you have a headless (no monitor, no keyboard) system.
 
-         More information is available: <file:Documentation/input/input.txt>
+         More information is available: <file:Documentation/input/input.rst>
 
          If unsure, say Y.
 
@@ -144,7 +144,7 @@ config INPUT_JOYDEV
 
          If unsure, say Y.
 
-         More information is available: <file:Documentation/input/joystick.txt>
+         More information is available: <file:Documentation/input/joydev/joystick.rst>
 
          To compile this driver as a module, choose M here: the
          module will be called joydev.
index 9591fc04a8ab203a0b514834c09f40697d0ccc7f..d8f9c6e1fc08b58f8a1dfb75e8d79e27301ed5a6 100644 (file)
@@ -9,7 +9,7 @@ menuconfig INPUT_JOYSTICK
          and the list of supported devices will be displayed. This option
          doesn't affect the kernel.
 
-         Please read the file <file:Documentation/input/joystick.txt> which
+         Please read the file <file:Documentation/input/joydev/joystick.rst> which
          contains more information.
 
 if INPUT_JOYSTICK
@@ -25,7 +25,7 @@ config JOYSTICK_ANALOG
          Flightstick Pro, ThrustMaster FCS, 6 and 8 button gamepads, or
          Saitek Cyborg joysticks.
 
-         Please read the file <file:Documentation/input/joystick.txt> which
+         Please read the file <file:Documentation/input/joydev/joystick.rst> which
          contains more information.
 
          To compile this driver as a module, choose M here: the
@@ -214,7 +214,7 @@ config JOYSTICK_DB9
          gamepad, Sega Saturn gamepad, or a Multisystem -- Atari, Amiga,
          Commodore, Amstrad CPC joystick connected to your parallel port.
          For more information on how to use the driver please read
-         <file:Documentation/input/joystick-parport.txt>.
+         <file:Documentation/input/devices/joystick-parport.rst>.
 
          To compile this driver as a module, choose M here: the
          module will be called db9.
@@ -229,7 +229,7 @@ config JOYSTICK_GAMECON
          Sony PlayStation gamepad or a Multisystem -- Atari, Amiga,
          Commodore, Amstrad CPC joystick connected to your parallel port.
          For more information on how to use the driver please read
-         <file:Documentation/input/joystick-parport.txt>.
+         <file:Documentation/input/devices/joystick-parport.rst>.
 
          To compile this driver as a module, choose M here: the
          module will be called gamecon.
@@ -241,7 +241,7 @@ config JOYSTICK_TURBOGRAFX
          Say Y here if you have the TurboGraFX interface by Steffen Schwenke,
          and want to use it with Multisystem -- Atari, Amiga, Commodore,
          Amstrad CPC joystick. For more information on how to use the driver
-         please read <file:Documentation/input/joystick-parport.txt>.
+         please read <file:Documentation/input/devices/joystick-parport.rst>.
 
          To compile this driver as a module, choose M here: the
          module will be called turbografx.
@@ -287,7 +287,7 @@ config JOYSTICK_XPAD
          and/or "Event interface support" (CONFIG_INPUT_EVDEV) as well.
 
          For information about how to connect the X-Box pad to USB, see
-         <file:Documentation/input/xpad.txt>.
+         <file:Documentation/input/devices/xpad.rst>.
 
          To compile this driver as a module, choose M here: the
          module will be called xpad.
@@ -313,7 +313,7 @@ config JOYSTICK_WALKERA0701
          Say Y or M here if you have a Walkera WK-0701 transmitter which is
          supplied with a ready to fly Walkera helicopters such as HM36,
          HM37, HM60 and want to use it via parport as a joystick. More
-         information is available: <file:Documentation/input/walkera0701.txt>
+         information is available: <file:Documentation/input/devices/walkera0701.rst>
 
          To compile this driver as a module, choose M here: the
          module will be called walkera0701.
index 8fde22a021b31351d6d6dc5498b62a86b6e0c537..ab4dbcbcbf50b4ef42450df75446f6d2e35e512d 100644 (file)
@@ -27,6 +27,6 @@ config JOYSTICK_IFORCE_232
          connected to your serial (COM) port.
 
          You will need an additional utility called inputattach, see
-         <file:Documentation/input/joystick.txt>
-         and <file:Documentation/input/ff.txt>.
+         <file:Documentation/input/joydev/joystick.rst>
+         and <file:Documentation/input/ff.rst>.
 
index 36a5b93156ed88b048159f4bc02ddc9d4242b9ef..dce313dc260a13a011aa108d044dc1d0a45252e7 100644 (file)
@@ -3,7 +3,7 @@
  *
  *  Copyright (c) 2008 Peter Popovec
  *
- *  More about driver:  <file:Documentation/input/walkera0701.txt>
+ *  More about driver:  <file:Documentation/input/devices/walkera0701.rst>
  */
 
 /*
index 572b15fa18c22be816704236882255df3e30c967..c25606e006938743d64498429cf3d0b69768d7fb 100644 (file)
@@ -411,7 +411,7 @@ config INPUT_YEALINK
          usb sound driver, so you might want to enable that as well.
 
          For information about how to use these additional functions, see
-         <file:Documentation/input/yealink.txt>.
+         <file:Documentation/input/devices/yealink.rst>.
 
          To compile this driver as a module, choose M here: the module will be
          called yealink.
@@ -595,7 +595,7 @@ config INPUT_GPIO_ROTARY_ENCODER
        depends on GPIOLIB || COMPILE_TEST
        help
          Say Y here to add support for rotary encoders connected to GPIO lines.
-         Check file:Documentation/input/rotary-encoder.txt for more
+         Check file:Documentation/input/devices/rotary-encoder.rst for more
          information.
 
          To compile this driver as a module, choose M here: the
index 6d304381fc30641c4626bf498a9a74fe16fdf548..30ec77ad32c6efa6a56637246e342bad5b7e93b1 100644 (file)
@@ -7,7 +7,7 @@
  * state machine code inspired by code from Tim Ruetz
  *
  * A generic driver for rotary encoders connected to GPIO lines.
- * See file:Documentation/input/rotary-encoder.txt for more information
+ * See file:Documentation/input/devices/rotary-encoder.rst for more information
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
index f27f23f2d99a4bdd42d5ab3f6405a0d14ce52292..566a1e3aa50433fe8d736e81864aa2f98aa0e364 100644 (file)
@@ -129,7 +129,7 @@ config MOUSE_PS2_ELANTECH
 
          This driver exposes some configuration registers via sysfs
          entries. For further information,
-         see <file:Documentation/input/elantech.txt>.
+         see <file:Documentation/input/devices/elantech.rst>.
 
          If unsure, say N.
 
@@ -228,7 +228,7 @@ config MOUSE_APPLETOUCH
          scrolling in X11.
 
          For further information, see
-         <file:Documentation/input/appletouch.txt>.
+         <file:Documentation/input/devices/appletouch.rst>.
 
          To compile this driver as a module, choose M here: the
          module will be called appletouch.
@@ -251,7 +251,7 @@ config MOUSE_BCM5974
 
          The interface is currently identical to the appletouch interface,
          for further information, see
-         <file:Documentation/input/appletouch.txt>.
+         <file:Documentation/input/devices/appletouch.rst>.
 
          To compile this driver as a module, choose M here: the
          module will be called bcm5974.
index cb5579716dba69e0c85d9556505eff97c7d62fd4..0a6f7ca883e7fe816a82d0dae915ab120e6681e9 100644 (file)
@@ -212,7 +212,7 @@ static void alps_set_abs_params_v7(struct alps_data *priv,
 static void alps_set_abs_params_ss4_v2(struct alps_data *priv,
                                       struct input_dev *dev1);
 
-/* Packet formats are described in Documentation/input/alps.txt */
+/* Packet formats are described in Documentation/input/devices/alps.rst */
 
 static bool alps_is_valid_first_byte(struct alps_data *priv,
                                     unsigned char data)
index ca4530eb3378684492cf08a4db631626be104c3d..d90d9f1098ff8ccba4c35d032812f6a62019baa3 100644 (file)
@@ -47,7 +47,7 @@ config SERIO_SERPORT
          Say Y here if you plan to use an input device (mouse, joystick,
          tablet, 6dof) that communicates over the RS232 serial (COM) port.
 
-         More information is available: <file:Documentation/input/input.txt>
+         More information is available: <file:Documentation/input/input.rst>
 
          If unsure, say Y.
 
@@ -78,7 +78,7 @@ config SERIO_PARKBD
          Say Y here if you built a simple parallel port adapter to attach
          an additional AT keyboard, XT keyboard or PS/2 mouse.
 
-         More information is available: <file:Documentation/input/input.txt>
+         More information is available: <file:Documentation/input/input.rst>
 
          If unsure, say N.
 
index fd714ee881f73d897b6d9150697f355bc4dd7f6a..2566b4d8b3428286adb1cc6c4988ffe09d271f34 100644 (file)
@@ -68,7 +68,7 @@
  * The default values correspond to Mainstone II in QVGA mode
  *
  * Please read
- * Documentation/input/input-programming.txt for more details.
+ * Documentation/input/input-programming.rst for more details.
  */
 
 static int abs_x[3] = {150, 4000, 5};
index 00cd1f20a1962f74c7c5e8abec6b9fec53a61af1..55e9442a99e2bfd664932d50a7a5b5ece9b9c9a8 100644 (file)
@@ -38,7 +38,7 @@ void pblk_rb_data_free(struct pblk_rb *rb)
 /*
  * Initialize ring buffer. The data and metadata buffers must be previously
  * allocated and their size must be a power of two
- * (Documentation/circular-buffers.txt)
+ * (Documentation/core-api/circular-buffers.rst)
  */
 int pblk_rb_init(struct pblk_rb *rb, struct pblk_rb_entry *rb_entry_base,
                 unsigned int power_size, unsigned int power_seg_sz)
index 4d200883c505b1162d9c3527ddfe5692a37ae8fb..17bf109c58e9e4206dd055e81a571bfb79236fd4 100644 (file)
@@ -5,7 +5,7 @@ config BCACHE
        Allows a block device to be used as cache for other devices; uses
        a btree for indexing and the layout is optimized for SSDs.
 
-       See Documentation/bcache.txt for details.
+       See Documentation/admin-guide/bcache.rst for details.
 
 config BCACHE_DEBUG
        bool "Bcache debugging"
index 2a0968c04e21f84572089d89c863645db239aa36..547c9eedc2f4fa3e90cde0149e4be4b48fd93fbf 100644 (file)
@@ -18,7 +18,7 @@
  * as keys are inserted we only sort the pages that have not yet been written.
  * When garbage collection is run, we resort the entire node.
  *
- * All configuration is done via sysfs; see Documentation/bcache.txt.
+ * All configuration is done via sysfs; see Documentation/admin-guide/bcache.rst.
  */
 
 #include "bcache.h"
index c334e6666461750e6e2dfe09ec7e9139c22b0da0..1d096742eb41a01444e7c6412951af5440a6fd28 100644 (file)
@@ -18,7 +18,7 @@
  * as keys are inserted we only sort the pages that have not yet been written.
  * When garbage collection is run, we resort the entire node.
  *
- * All configuration is done via sysfs; see Documentation/bcache.txt.
+ * All configuration is done via sysfs; see Documentation/admin-guide/bcache.rst.
  */
 
 #include "bcache.h"
index 4330b6fa4af244062743d088aa042cb12e54510c..d1d471af0636da07da17a59d8fa74e2dcb657857 100644 (file)
@@ -55,7 +55,7 @@ int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf)
         * this pairs with smp_store_release() in dvb_ringbuffer_write(),
         * dvb_ringbuffer_write_user(), or dvb_ringbuffer_reset()
         *
-        * for memory barriers also see Documentation/circular-buffers.txt
+        * for memory barriers also see Documentation/core-api/circular-buffers.rst
         */
        return (rbuf->pread == smp_load_acquire(&rbuf->pwrite));
 }
index 55e36a4f521546dadd5c5917b27c61703daa9abc..9ecaa9d0744a48fddb631aa01f5ec5c15993f6d8 100644 (file)
@@ -324,7 +324,7 @@ config DVB_SP8870
          A DVB-T tuner module. Say Y when you want to support this frontend.
 
          This driver needs external firmware. Please use the command
-         "<kerneldir>/Documentation/dvb/get_dvb_firmware sp8870" to
+         "<kerneldir>/scripts/get_dvb_firmware sp8870" to
          download/extract it, and then copy it to /usr/lib/hotplug/firmware
          or /lib/firmware (depending on configuration of firmware hotplug).
 
@@ -336,7 +336,7 @@ config DVB_SP887X
          A DVB-T tuner module. Say Y when you want to support this frontend.
 
          This driver needs external firmware. Please use the command
-         "<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to
+         "<kerneldir>/scripts/get_dvb_firmware sp887x" to
          download/extract it, and then copy it to /usr/lib/hotplug/firmware
          or /lib/firmware (depending on configuration of firmware hotplug).
 
@@ -387,8 +387,8 @@ config DVB_TDA1004X
          A DVB-T tuner module. Say Y when you want to support this frontend.
 
          This driver needs external firmware. Please use the commands
-         "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045",
-         "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
+         "<kerneldir>/scripts/get_dvb_firmware tda10045",
+         "<kerneldir>/scripts/get_dvb_firmware tda10046" to
          download/extract them, and then copy them to /usr/lib/hotplug/firmware
          or /lib/firmware (depending on configuration of firmware hotplug).
 
@@ -591,8 +591,8 @@ config DVB_NXT200X
          to support this frontend.
 
          This driver needs external firmware. Please use the commands
-         "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" and
-         "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2004" to
+         "<kerneldir>/scripts/get_dvb_firmware nxt2002" and
+         "<kerneldir>/scripts/get_dvb_firmware nxt2004" to
          download/extract them, and then copy them to /usr/lib/hotplug/firmware
          or /lib/firmware (depending on configuration of firmware hotplug).
 
@@ -604,7 +604,7 @@ config DVB_OR51211
          An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
 
          This driver needs external firmware. Please use the command
-         "<kerneldir>/Documentation/dvb/get_dvb_firmware or51211" to
+         "<kerneldir>/scripts/get_dvb_firmware or51211" to
          download it, and then copy it to /usr/lib/hotplug/firmware
          or /lib/firmware (depending on configuration of firmware hotplug).
 
@@ -617,8 +617,8 @@ config DVB_OR51132
          to support this frontend.
 
          This driver needs external firmware. Please use the commands
-         "<kerneldir>/Documentation/dvb/get_dvb_firmware or51132_vsb" and/or
-         "<kerneldir>/Documentation/dvb/get_dvb_firmware or51132_qam" to
+         "<kerneldir>/scripts/get_dvb_firmware or51132_vsb" and/or
+         "<kerneldir>/scripts/get_dvb_firmware or51132_qam" to
          download firmwares for 8VSB and QAM64/256, respectively. Copy them to
          /usr/lib/hotplug/firmware or /lib/firmware (depending on
          configuration of firmware hotplug).
index d5dfafb4ef13b665a5439c9a68ce72eb69452486..d2b7523a22b5ae74cc2a6f294dfd364002f16650 100644 (file)
@@ -17,7 +17,7 @@
  *  Amaury Demol from DiBcom for providing specs and driver
  *  sources, on which this driver (and the dvb-dibusb) are based.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  *
  */
 
index de3ce2786c7248a061a54ac38bc975b9e59d1bd9..5861f346db49b7833601fb725e266e572bb0ad6f 100644 (file)
@@ -17,7 +17,7 @@
  *  Amaury Demol from DiBcom for providing specs and driver
  *  sources, on which this driver (and the dvb-dibusb) are based.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  *
  */
 
index c983f2f85802a0361eb1b36a5e85c3792b8b28c1..30f067fc1f568e2b005a856e13d7fadc488e9cd1 100644 (file)
@@ -6,7 +6,7 @@
 *      under the terms of the GNU General Public License as published by the
 *      Free Software Foundation, version 2.
 *
-* see Documentation/dvb/README.dvb-usb for more information
+* see Documentation/media/dvb-drivers/dvb-usb.rst for more information
 */
 
 #ifndef EDS1547
index 7aa74403648e3a8d6dc94ce18abeac37dee46239..a6cc4952eb744b1b3f6ee6b96f5f2dfcc097c54e 100644 (file)
@@ -27,8 +27,8 @@
  *   ATI HDTV Wonder (NXT2004)
  *
  * This driver needs external firmware. Please use the command
- * "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" or
- * "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2004" to
+ * "<kerneldir>/scripts/get_dvb_firmware nxt2002" or
+ * "<kerneldir>/scripts/get_dvb_firmware nxt2004" to
  * download/extract the appropriate firmware, and then copy it to
  * /usr/lib/hotplug/firmware/ or /lib/firmware/
  * (depending on configuration of firmware hotplug).
index a1b7c301828ffe1f8c8d20ff628ea14d2e8ccef2..b65ba34fd00a9d1e5dc9d4fd7373d97d03c4236a 100644 (file)
@@ -22,7 +22,7 @@
 
 /*
  * This driver needs external firmware. Please use the command
- * "<kerneldir>/Documentation/dvb/get_dvb_firmware or51211" to
+ * "<kerneldir>/scripts/get_dvb_firmware or51211" to
  * download/extract it, and then copy it to /usr/lib/hotplug/firmware
  * or /lib/firmware (depending on configuration of firmware hotplug).
  */
index 9a726f3a4896a2c2403894a0d0ecb6a4b05706d1..1d57a20093fc1157505aa90c8959c2852b31021b 100644 (file)
@@ -21,7 +21,7 @@
 */
 /*
  * This driver needs external firmware. Please use the command
- * "<kerneldir>/Documentation/dvb/get_dvb_firmware alps_tdlb7" to
+ * "<kerneldir>/scripts/get_dvb_firmware alps_tdlb7" to
  * download/extract it, and then copy it to /usr/lib/hotplug/firmware
  * or /lib/firmware (depending on configuration of firmware hotplug).
  */
index f39d566d7d1dfb4733dfa780c97ab6e4a0db06df..57a0d0ae2b48f16429c042b45c34c1a8b78a932e 100644 (file)
@@ -4,7 +4,7 @@
 
 /*
  * This driver needs external firmware. Please use the command
- * "<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to
+ * "<kerneldir>/scripts/get_dvb_firmware sp887x" to
  * download/extract it, and then copy it to /usr/lib/hotplug/firmware
  * or /lib/firmware (depending on configuration of firmware hotplug).
  */
index 58e3beff5adcb8a0658c3af8dbff62e190743123..7dcfb4a4b2d0258b81f4223b7b91be74b4c1d7a6 100644 (file)
@@ -21,8 +21,8 @@
    */
 /*
  * This driver needs external firmware. Please use the commands
- * "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045",
- * "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to
+ * "<kerneldir>/scripts/get_dvb_firmware tda10045",
+ * "<kerneldir>/scripts/get_dvb_firmware tda10046" to
  * download/extract them, and then copy them to /usr/lib/hotplug/firmware
  * or /lib/firmware (depending on configuration of firmware hotplug).
  */
index a59f4fd09df605d3568fea54706da363a6ea92bf..1ed67c08e6991372139285946702e30faf657dae 100644 (file)
@@ -852,7 +852,7 @@ static int tda10071_init(struct dvb_frontend *fe)
                ret = request_firmware(&fw, fw_file, &client->dev);
                if (ret) {
                        dev_err(&client->dev,
-                               "did not find the firmware file. (%s) Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)\n",
+                               "did not find the firmware file '%s' (status %d). You can use <kernel_dir>/scripts/get_dvb_firmware to get the firmware\n",
                                fw_file, ret);
                        goto error;
                }
index 96d86d6eb4735915850eefde50e26494d9a49ff8..0871c1ade94c82ed69b5e3eacef23940487ad443 100644 (file)
@@ -6,7 +6,7 @@
 *      under the terms of the GNU General Public License as published by the
 *      Free Software Foundation, version 2.
 *
-* see Documentation/dvb/README.dvb-usb for more information
+* see Documentation/media/dvb-drivers/dvb-usb.rst for more information
 */
 
 #ifndef Z0194A
index 87cba15b2977b7711c710e23da0523702b37b453..008a082cb8ad73f2d433f268013694c5f7f86740 100644 (file)
@@ -1202,7 +1202,7 @@ static const struct v4l2_ctrl_ops max2175_ctrl_ops = {
 
 /*
  * I2S output enable/disable configuration. This is a private control.
- * Refer to Documentation/media/v4l-drivers/max2175 for more details.
+ * Refer to Documentation/media/v4l-drivers/max2175.rst for more details.
  */
 static const struct v4l2_ctrl_config max2175_i2s_en = {
        .ops = &max2175_ctrl_ops,
@@ -1218,7 +1218,7 @@ static const struct v4l2_ctrl_config max2175_i2s_en = {
 
 /*
  * HSLS value control LO freq adjacent location configuration.
- * Refer to Documentation/media/v4l-drivers/max2175 for more details.
+ * Refer to Documentation/media/v4l-drivers/max2175.rst for more details.
  */
 static const struct v4l2_ctrl_config max2175_hsls = {
        .ops = &max2175_ctrl_ops,
@@ -1234,7 +1234,7 @@ static const struct v4l2_ctrl_config max2175_hsls = {
 /*
  * Rx modes below are a set of preset configurations that decides the tuner's
  * sck and sample rate of transmission. They are separate for EU & NA regions.
- * Refer to Documentation/media/v4l-drivers/max2175 for more details.
+ * Refer to Documentation/media/v4l-drivers/max2175.rst for more details.
  */
 static const char * const max2175_ctrl_eu_rx_modes[] = {
        [MAX2175_EU_FM_1_2]     = "EU FM 1.2",
index 4a93f6ded100247ee58d565bb5931b30e647ef8b..bc89e37608cdd7199a8ce8f20427eef1b97ebc1a 100644 (file)
@@ -16,7 +16,7 @@ config VIDEO_BT848
        ---help---
          Support for BT848 based frame grabber/overlay boards. This includes
          the Miro, Hauppauge and STB boards. Please read the material in
-         <file:Documentation/video4linux/bttv/> for more information.
+         <file:Documentation/media/v4l-drivers/bttv.rst> for more information.
 
          To compile this driver as a module, choose M here: the
          module will be called bttv.
index 010f39eafce1b3d9834d5f74dc9799ae0c7b2bcd..a3a7f7065349ce0637705831c9d36ba54c310773 100644 (file)
@@ -152,7 +152,7 @@ static int yuan_mpc718_mt352_reqfw(struct cx18_stream *stream,
 
        if (ret) {
                CX18_ERR("The MPC718 board variant with the MT352 DVB-T demodulator will not work without it\n");
-               CX18_ERR("Run 'linux/Documentation/dvb/get_dvb_firmware mpc718' if you need the firmware\n");
+               CX18_ERR("Run 'linux/scripts/get_dvb_firmware mpc718' if you need the firmware\n");
        }
        return ret;
 }
index a594cfdeca200079337ae198a82a987999f8bcdd..b36f4ce25d22dbe2bde1ada588e5b9a8c517d6bb 100644 (file)
@@ -853,7 +853,7 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
 
                /*
                 * Audio related reset according to
-                * Documentation/video4linux/cx2341x/fw-encoder-api.txt
+                * Documentation/media/v4l-drivers/cx2341x.rst
                 */
                if (atomic_read(&cx->ana_capturing) == 0)
                        cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2,
@@ -861,7 +861,7 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
 
                /*
                 * Number of lines for Field 1 & Field 2 according to
-                * Documentation/video4linux/cx2341x/fw-encoder-api.txt
+                * Documentation/media/v4l-drivers/cx2341x.rst
                 * Field 1 is 312 for 625 line systems in BT.656
                 * Field 2 is 313 for 625 line systems in BT.656
                 */
index 3a1c55187b2ab7d55af97ebd3226b6d7b1259e79..9f50748fdf56101ccedc918709dc0b3384acd1de 100644 (file)
@@ -2426,7 +2426,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
 
                ret = request_firmware(&fw, filename, &dev->pci->dev);
                if (ret != 0)
-                       pr_err("did not find the firmware file. (%s) Please see linux/Documentation/dvb/ for more details on firmware-problems.",
+                       pr_err("did not find the firmware file '%s'. You can use <kernel_dir>/scripts/get_dvb_firmware to get the firmware.",
                               filename);
                else
                        altera_init(&netup_config, fw);
index 2e60334ffef57447fff51327e394f22fc640f912..9a50f54231adfcf89197715df7a31e6928b2711e 100644 (file)
@@ -5,7 +5,7 @@ config VIDEO_MEYE
        ---help---
          This is the video4linux driver for the Motion Eye camera found
          in the Vaio Picturebook laptops. Please read the material in
-         <file:Documentation/video4linux/meye.txt> for more information.
+         <file:Documentation/media/v4l-drivers/meye.rst> for more information.
 
          If you say Y or M here, you need to say Y or M to "Sony Laptop
          Extras" in the misc device section.
index 7b83151ed6c48dd665a021c43438e61b453f2cce..dfba74dd65212e31cbc7d7f7e6c5873582e62489 100644 (file)
@@ -24,7 +24,7 @@ config DVB_AV7110
          onboard MPEG2 decoder.
 
          This driver needs an external firmware. Please use the script
-         "<kerneldir>/Documentation/dvb/get_dvb_firmware av7110" to
+         "<kerneldir>/scripts/get_dvb_firmware av7110" to
          download/extract it, and then copy it to /usr/lib/hotplug/firmware
          or /lib/firmware (depending on configuration of firmware hotplug).
 
index 3cf30007234890f63ac3c63c5a5c27e4dea892cb..6d9f0abb26600534ad29ab83ac5c15686a650e6d 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/i2c.h>
-#include <linux/i2c-gpio.h>
+#include <linux/platform_data/i2c-gpio.h>
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
index 4d5a26b4cdda6d851b7b9e3b31178d81a4ea0576..d85ffbfb7c1fde9271f1e42ec28a31b205206a78 100644 (file)
@@ -1021,7 +1021,7 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev,
  *  - a videobuffer is queued on the pcdev->capture list
  *
  * Please check the "DMA hot chaining timeslice issue" in
- *   Documentation/video4linux/pxa_camera.txt
+ *   Documentation/media/v4l-drivers/pxa_camera.rst
  *
  * Context: should only be called within the dma irq handler
  */
@@ -1443,7 +1443,7 @@ static void pxac_vb2_queue(struct vb2_buffer *vb)
 
 /*
  * Please check the DMA prepared buffer structure in :
- *   Documentation/video4linux/pxa_camera.txt
+ *   Documentation/media/v4l-drivers/pxa_camera.rst
  * Please check also in pxa_camera_check_link_miss() to understand why DMA chain
  * modification while DMA chain is running will work anyway.
  */
index 242342fd7eded0a030a01a12ecf5fdea88faa0ef..9897213f261841857b76cd50f94cb83ae6504276 100644 (file)
@@ -1111,7 +1111,7 @@ static void sh_mobile_ceu_put_formats(struct soc_camera_device *icd)
 /*
  * CEU can scale and crop, but we don't want to waste bandwidth and kill the
  * framerate by always requesting the maximum image from the client. See
- * Documentation/video4linux/sh_mobile_ceu_camera.txt for a description of
+ * Documentation/media/v4l-drivers/sh_mobile_ceu_camera.rst for a description of
  * scaling and cropping algorithms and for the meaning of referenced here steps.
  */
 static int sh_mobile_ceu_set_selection(struct soc_camera_device *icd,
index f01c3e81324757f2e85c58b14e842cdd5304d1f2..c8bb82fe0b9df628ff11b086bb1e5d54fb582068 100644 (file)
 #include <linux/via-core.h>
 #include <linux/via-gpio.h>
 #include <linux/via_i2c.h>
+
+#ifdef CONFIG_X86
 #include <asm/olpc.h>
+#else
+#define machine_is_olpc(x) 0
+#endif
 
 #include "via-camera.h"
 
index 39b04ad924c0ca4e5b82e37ed829172dde36b848..9b99dfb2d0c6419c0af4c7a1eb284905af612410 100644 (file)
@@ -35,7 +35,7 @@ config RADIO_SI476X
          In order to control your radio card, you will need to use programs
          that are compatible with the Video For Linux 2 API.  Information on
          this API and pointers to "v4l2" programs may be found at
-         <file:Documentation/video4linux/API.html>.
+         <file:Documentation/media/media_uapi.rst>.
 
          To compile this driver as a module, choose M here: the
          module will be called radio-si476x.
@@ -75,7 +75,7 @@ config RADIO_MAXIRADIO
          In order to control your radio card, you will need to use programs
          that are compatible with the Video For Linux API.  Information on
          this API and pointers to "v4l" programs may be found at
-         <file:Documentation/video4linux/API.html>.
+         <file:Documentation/media/media_uapi.rst>.
 
          To compile this driver as a module, choose M here: the
          module will be called radio-maxiradio.
@@ -93,7 +93,7 @@ config RADIO_SHARK
          In order to control your radio card, you will need to use programs
          that are compatible with the Video For Linux API.  Information on
          this API and pointers to "v4l" programs may be found at
-         <file:Documentation/video4linux/API.html>.
+         <file:Documentation/media/media_uapi.rst>.
 
          To compile this driver as a module, choose M here: the
          module will be called radio-shark.
@@ -110,7 +110,7 @@ config RADIO_SHARK2
          In order to control your radio card, you will need to use programs
          that are compatible with the Video For Linux API.  Information on
          this API and pointers to "v4l" programs may be found at
-         <file:Documentation/video4linux/API.html>.
+         <file:Documentation/media/media_uapi.rst>.
 
          To compile this driver as a module, choose M here: the
          module will be called radio-shark2.
@@ -217,7 +217,7 @@ config RADIO_WL1273
          In order to control your radio card, you will need to use programs
          that are compatible with the Video For Linux 2 API.  Information on
          this API and pointers to "v4l2" programs may be found at
-         <file:Documentation/video4linux/API.html>.
+         <file:Documentation/media/media_uapi.rst>.
 
          To compile this driver as a module, choose M here: the
          module will be called radio-wl1273.
@@ -272,7 +272,7 @@ config RADIO_RTRACK
          been reported to be used by these cards.
 
          More information is contained in the file
-         <file:Documentation/video4linux/radiotrack.txt>.
+         <file:Documentation/media/v4l-drivers/radiotrack.rst>.
 
          To compile this driver as a module, choose M here: the
          module will be called radio-aimslab.
index a21172e413a94945de72b08fad35ccae033472d3..6dbb158cd2a0bd99f8f5d2d6a236e7038a09b21c 100644 (file)
@@ -29,7 +29,7 @@ config USB_SI470X
 
          Please have a look at the documentation, especially on how
          to redirect the audio stream from the radio to your sound device:
-         Documentation/video4linux/si470x.txt
+         Documentation/media/v4l-drivers/si470x.rst
 
          Say Y here if you want to connect this type of radio to your
          computer's USB port.
index 2add222ea346de2b41243f68275531fb39a3c986..64b66bbdae7225b225e1463386bc58b8a21c1716 100644 (file)
@@ -12,6 +12,6 @@ config RADIO_WL128X
          In order to control your radio card, you will need to use programs
          that are compatible with the Video For Linux 2 API.  Information on
          this API and pointers to "v4l2" programs may be found at
-         <file:Documentation/video4linux/API.html>.
+         <file:Documentation/media/media_uapi.rst>.
 
 endmenu
index 37053477b84d31787e4575762992066ae83fb4e7..082b8d67244bf2c221b1dcdd77434382e868b01b 100644 (file)
@@ -6,7 +6,7 @@ config DVB_USB_V2
          USB1.1 and USB2.0 DVB devices.
 
          Almost every USB device needs a firmware, please look into
-         <file:Documentation/dvb/README.dvb-usb>.
+         <file:Documentation/media/dvb-drivers/dvb-usb.rst>.
 
          For a complete list of supported USB devices see the LinuxTV DVB Wiki:
          <https://linuxtv.org/wiki/index.php/DVB_USB>
index afdcdbf005e9f7193a27021ae7f03c6dcf78de82..955318ab7f5e31c65b698a68b0a1f3581686966e 100644 (file)
@@ -47,7 +47,7 @@ static int dvb_usbv2_download_firmware(struct dvb_usb_device *d,
        ret = request_firmware(&fw, name, &d->udev->dev);
        if (ret < 0) {
                dev_err(&d->udev->dev,
-                               "%s: Did not find the firmware file '%s'. Please see linux/Documentation/dvb/ for more details on firmware-problems. Status %d\n",
+                               "%s: Did not find the firmware file '%s' (status %d). You can use <kernel_dir>/scripts/get_dvb_firmware to get the firmware\n",
                                KBUILD_MODNAME, name, ret);
                goto err;
        }
index 4817dfd3e659baf3be495022c3650d2e8afd123d..9d154fdae45be040218d6bb7497fc81fdd5e5914 100644 (file)
@@ -4,7 +4,7 @@
  *     under the terms of the GNU General Public License as published by the
  *     Free Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 #include "gl861.h"
 
index be26c029546bd3f145ee09f9aa3ceb5ff948b977..0750a975bcb899a4744ebf5229c0ced0dcd00fe9 100644 (file)
@@ -21,7 +21,7 @@
  *
  * LME2510C + M88RS2000
  *
- * For firmware see Documentation/dvb/lmedm04.txt
+ * For firmware see Documentation/media/dvb-drivers/lmedm04.rst
  *
  * I2C addresses:
  * 0xd0 - STV0288      - Demodulator
@@ -49,7 +49,7 @@
  * GNU General Public License for more details.
  *
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  *
  * Known Issues :
  *     LME2510: Non Intel USB chipsets fail to maintain High Speed on
index e9c207205c2fd6faa17c3122bb411841214fd16b..c4ae37c19512ea90035781ca216ccae09fb11670 100644 (file)
@@ -16,7 +16,7 @@
  * under the terms of the GNU General Public License as published by the Free
  * Software Foundation,  version 2.
  * *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 #ifndef _DVB_USB_LME2510_H_
 #define _DVB_USB_LME2510_H_
index 67953360fda586db9c1e9d904fc87d48f00df45f..4713ba65e1c228b71c1a4c51ecc015cb58a610ad 100644 (file)
@@ -5,7 +5,7 @@
  *   under the terms of the GNU General Public License as published by the Free
  *   Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 
 #include <linux/vmalloc.h>
index 3e6f5880bd1e39494d626d662382e2353513ad5b..22253d4908eb48c8b8c69341abbe46c4ac867c73 100644 (file)
@@ -5,7 +5,7 @@
  *   under the terms of the GNU General Public License as published by the Free
  *   Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 
 #ifndef _DVB_USB_MXL111SF_H_
index 2651ae277347968204a07bd86b306ecf50e89760..b8a1c62a06826256c981ae841e8f6d273368c85b 100644 (file)
@@ -6,7 +6,7 @@ config DVB_USB
          USB1.1 and USB2.0 DVB devices.
 
          Almost every USB device needs a firmware, please look into
-         <file:Documentation/dvb/README.dvb-usb>.
+         <file:Documentation/media/dvb-drivers/dvb-usb.rst>.
 
          For a complete list of supported USB devices see the LinuxTV DVB Wiki:
          <https://linuxtv.org/wiki/index.php/DVB_USB>
index 540886b3bb29aabb24c68b7d75c33822fa01b6d6..198bd5eadb3f04acc8cd4f9a33d93dfb30c05956 100644 (file)
@@ -11,7 +11,7 @@
  *     under the terms of the GNU General Public License as published by the Free
  *     Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 #include "dibusb.h"
 
index 544bdf18fb2fe4d4d41dfa67f5e9eeac5b7cc1a1..7fbbc954da16564fff762dfe992d8d6dc381bfc7 100644 (file)
@@ -15,7 +15,7 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 #include "af9005.h"
 #include "af9005-script.h"
index 9b29ffa9307502431c9c4ce79bb3d759ee1e18bc..f7cdcc8424a821aa872318bc4c423158d0d27441 100644 (file)
@@ -17,7 +17,7 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 #include "af9005.h"
 /* debug */
index 986763b1b2b32a2688a2f9a75db4392bf2bc2d5e..16e946e01d2caab9eaf68546067b3fb92f18731d 100644 (file)
@@ -15,7 +15,7 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 #include "af9005.h"
 
index a1eae0fa02edda2e70304bf8016a97632e86a65a..7ae4dc3a968b879cd88f71c516e16ad2e09e99b3 100644 (file)
@@ -15,7 +15,7 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 #ifndef _DVB_USB_AF9005_H_
 #define _DVB_USB_AF9005_H_
index f0d10ac03a374408a33b9f75cc29735902d38447..6321b8e302612080d2e93352975198e6a1430ad4 100644 (file)
@@ -7,7 +7,7 @@
  *     under the terms of the GNU General Public License as published by the Free
  *     Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 #include "az6027.h"
 
index b70d289dc7389029d194a58d231916d40a45d611..5b51ed7d6243fe8572b126e45fba6cee83587f3e 100644 (file)
@@ -21,7 +21,7 @@
  *   under the terms of the GNU General Public License as published by the Free
  *   Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 #include <media/tuner.h>
 #include <linux/vmalloc.h>
index bcacb0f220282d9c3537e8847b178d7f0ec71727..fb1b4f2d5f9de6ea0ae53cd922727749390a834d 100644 (file)
@@ -6,7 +6,7 @@
  *     under the terms of the GNU General Public License as published by the Free
  *     Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 
 #include "dibusb.h"
index a0057641cc86838d80d694ca9511e8547a37e480..408920577716119919e7fc268afbf7de750991cc 100644 (file)
@@ -10,7 +10,7 @@
  *     under the terms of the GNU General Public License as published by the Free
  *     Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 #include "dibusb.h"
 
index 0c2bc97436d555a1d1c2448998558594f20a4ca1..ec3a20a95b04f7f2cd343dda5dbc9dcf0bc7db70 100644 (file)
@@ -6,7 +6,7 @@
  *     under the terms of the GNU General Public License as published by the Free
  *     Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 
 #include "dibusb.h"
index 08fb8a3f6e0cc23e87ff150c747361fd5259b1f6..bce8ffe640ca3a953b745a297b17acb098147e27 100644 (file)
@@ -10,7 +10,7 @@
  *     under the terms of the GNU General Public License as published by the Free
  *     Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 #include "dibusb.h"
 
index 697be2a17adef131b68a2f34a2401b2108174b68..943df579b98bd98a9f506578c13fbb4c855f0ebd 100644 (file)
@@ -6,7 +6,7 @@
  *     under the terms of the GNU General Public License as published by the Free
  *     Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 #ifndef _DVB_USB_DIBUSB_H_
 #define _DVB_USB_DIBUSB_H_
index 475a3c0cdee7f88a9630f337cd9d0aaf59f2e177..49b9d63e5885ab5cc1f2100e96df607d9d428a26 100644 (file)
@@ -9,7 +9,7 @@
  *     under the terms of the GNU General Public License as published by the Free
  *     Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 #include "digitv.h"
 
index 00f565fe7cc2c0b86f3c4b1b91234a57dd0df331..7e75aae34fb8f351ddfb2ae92820dc0bb68fcc8b 100644 (file)
@@ -7,7 +7,7 @@
  *     under the terms of the GNU General Public License as published by the Free
  *     Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 #include "dtt200u.h"
 
index 5123707866968222a52f73c5d0f94274f761cdd0..f03d26954517e7563fd78d5c9b21bc5ab8c85110 100644 (file)
@@ -9,7 +9,7 @@
  *     under the terms of the GNU General Public License as published by the Free
  *     Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 #include "dtt200u.h"
 
index efccc399b1cba7cdb92f59b48b7033fa1619b7d1..ea2a096c1650b6d7c0528eed2a71867bdf1c101e 100644 (file)
@@ -7,7 +7,7 @@
  *     under the terms of the GNU General Public License as published by the Free
  *     Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 #ifndef _DVB_USB_DTT200U_H_
 #define _DVB_USB_DTT200U_H_
index 15c153e49382d0c878e76d53cdd35789672ccdd3..42c207aacbb12ce90e0ea9d4cfce46996dcd93f8 100644 (file)
@@ -90,7 +90,7 @@ int dvb_usb_download_firmware(struct usb_device *udev, struct dvb_usb_device_pro
        const struct firmware *fw = NULL;
 
        if ((ret = request_firmware(&fw, props->firmware, &udev->dev)) != 0) {
-               err("did not find the firmware file. (%s) Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)",
+               err("did not find the firmware file '%s' (status %d). You can use <kernel_dir>/scripts/get_dvb_firmware to get the firmware",
                        props->firmware,ret);
                return ret;
        }
index 84308569e7dc12a7911304fc4c8c2abb72b49082..40ca4eafb137412edd1bb58f24868da5069e017c 100644 (file)
@@ -9,7 +9,7 @@
  *     under the terms of the GNU General Public License as published by the Free
  *     Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 #include "dvb-usb-common.h"
 
index 346946f35b1a5141dfe4c372747872cfb3d04fee..0d4fdd34a7102790a21d3a1cffcadad165106339 100644 (file)
@@ -11,7 +11,7 @@
  *     under the terms of the GNU General Public License as published by the
  *     Free Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 #include <media/dvb-usb-ids.h>
 #include "dw2102.h"
@@ -61,9 +61,7 @@
 #define P1100_FIRMWARE  "dvb-usb-p1100.fw"
 #define P7500_FIRMWARE  "dvb-usb-p7500.fw"
 
-#define        err_str "did not find the firmware file. (%s) " \
-               "Please see linux/Documentation/dvb/ for more details " \
-               "on firmware-problems."
+#define        err_str "did not find the firmware file '%s'. You can use <kernel_dir>/scripts/get_dvb_firmware to get the firmware"
 
 struct dw2102_state {
        u8 initialized;
index b2830c1575485084ecf8ea0f6c6a83992760f3b9..932f262452ebeedbc7d3abc8c40c9a440b2248a8 100644 (file)
@@ -8,7 +8,7 @@
  * under the terms of the GNU General Public License as published by the Free
  * Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 #include <linux/init.h>
 #include <linux/string.h>
index 16875945e662d0f303930e9993706564bb75485a..fe799a7ad44bacc66df1fe4a1d5e0f7b33392f06 100644 (file)
@@ -8,7 +8,7 @@
  * under the terms of the GNU General Public License as published by the Free
  * Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 #include "friio.h"
 
index 0f461ca10cb941dc255126bfa5b2ef54bd7f5245..a53af56d035c1037023c0d9ee5241438384a3164 100644 (file)
@@ -8,7 +8,7 @@
  * under the terms of the GNU General Public License as published by the Free
  * Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 #ifndef _DVB_USB_FRIIO_H_
 #define _DVB_USB_FRIIO_H_
index 334b9fb981120f7a45898d80897b819bbe6875db..13e96b0aeb0fc400869a0baecc13184b07acdd29 100644 (file)
@@ -12,7 +12,7 @@
  *     under the terms of the GNU General Public License as published by the Free
  *     Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 #include "gp8psk.h"
 #include "gp8psk-fe.h"
@@ -135,7 +135,7 @@ static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d)
        u8 *buf;
        if ((ret = request_firmware(&fw, bcm4500_firmware,
                                        &d->udev->dev)) != 0) {
-               err("did not find the bcm4500 firmware file. (%s) Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)",
+               err("did not find the bcm4500 firmware file '%s' (status %d). You can use <kernel_dir>/scripts/get_dvb_firmware to get the firmware",
                        bcm4500_firmware,ret);
                return ret;
        }
index d8975b866deeceda0e3820a7810f5cfc2b7205d6..fd063e385eafae87c1c9f17917529439556f00f6 100644 (file)
@@ -12,7 +12,7 @@
  *     under the terms of the GNU General Public License as published by the Free
  *     Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 #ifndef _DVB_USB_GP8PSK_H_
 #define _DVB_USB_GP8PSK_H_
index 32081c2ce0da8560ab2a6e25ed22d21ce5344e22..51b026fa6bfbde4ff54a5651e3be77608dad786e 100644 (file)
@@ -6,7 +6,7 @@
  *     under the terms of the GNU General Public License as published by the
  *     Free Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 
 #include "m920x.h"
index 1babd334191069d30419e2c07fc25fd04e0931d4..43e0e0fd715b966e9ec44d49542a3e14e913d537 100644 (file)
@@ -7,7 +7,7 @@
  *     under the terms of the GNU General Public License as published by the Free
  *     Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 #include "dibusb.h"
 
index 946a5ccc8f1a97e8117292810b5d9146bec96d79..61a377e2373d8dfbd5c5e8a50561fff563ed76d1 100644 (file)
@@ -7,7 +7,7 @@
 *      under the terms of the GNU General Public License as published by the Free
 *      Software Foundation, version 2.
 *
-* see Documentation/dvb/README.dvb-usb for more information
+* see Documentation/media/dvb-drivers/dvb-usb.rst for more information
 */
 
 #define DVB_USB_LOG_PREFIX "opera"
@@ -453,7 +453,7 @@ static int opera1_xilinx_load_firmware(struct usb_device *dev,
        info("start downloading fpga firmware %s",filename);
 
        if ((ret = request_firmware(&fw, filename, &dev->dev)) != 0) {
-               err("did not find the firmware file. (%s) Please see linux/Documentation/dvb/ for more details on firmware-problems.",
+               err("did not find the firmware file '%s'. You can use <kernel_dir>/scripts/get_dvb_firmware to get the firmware",
                        filename);
                return ret;
        } else {
index 12de89665d6053a834542c46f9ca1926eba926ab..b4d681151599b3009baad7f5915ac4955205c7ca 100644 (file)
@@ -20,7 +20,7 @@
  *     under the terms of the GNU General Public License as published by the Free
  *     Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 #define DVB_USB_LOG_PREFIX "ttusb2"
 #include "dvb-usb.h"
index 52a63af4089677fe12a787ae1901170df0c6d67f..8b6525e5fb2457af7efbd722f6de9e8a9992e2f2 100644 (file)
@@ -9,7 +9,7 @@
  *     under the terms of the GNU General Public License as published by the Free
  *     Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 #ifndef _DVB_USB_TTUSB2_H_
 #define _DVB_USB_TTUSB2_H_
index 58ad5b4f856c5dd5e1ba0d2a824026dc10cc5e97..920bc67c3bcb5a91eb67ef78e64017cfd42ee84e 100644 (file)
@@ -7,7 +7,7 @@
  *     under the terms of the GNU General Public License as published by the Free
  *     Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 #include "dibusb.h"
 
index 7ff31baa36825885ca4f600874d9ece5613ba08b..ae48146e005ca27c8412dd2d5cdc577460b39ed4 100644 (file)
@@ -15,7 +15,7 @@
  *     under the terms of the GNU General Public License as published by the Free
  *     Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  *
  */
 #include "vp702x.h"
index 40de33de90a7aef04ae6cf95153c8177596a16ba..c3529ea59da958ae7e1923656700e00b222c57a4 100644 (file)
@@ -12,7 +12,7 @@
  *     under the terms of the GNU General Public License as published by the Free
  *     Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 #include "vp702x.h"
 #include <linux/mutex.h>
index 4520ad9c2014a1ed2509646b4a1d71d064a05639..f86040173b8de8b5c7f68fedf1a223660a0e9819 100644 (file)
@@ -9,7 +9,7 @@
  *     under the terms of the GNU General Public License as published by the Free
  *     Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  *
  */
 #include "vp7045.h"
index 2527b88beb872daf49b82bd42be6d4300d75dec2..e2c8a853055443be76e3eb599abb2dd9be64663e 100644 (file)
@@ -10,7 +10,7 @@
  *     under the terms of the GNU General Public License as published by the Free
  *     Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 #include "vp7045.h"
 
index 66499932ca767f97156bb9bce08e82a0dfc9d8ef..2fdafd8f8cd6272fcb90f9d19d440c14369c7481 100644 (file)
@@ -9,7 +9,7 @@
  *     under the terms of the GNU General Public License as published by the Free
  *     Software Foundation, version 2.
  *
- * see Documentation/dvb/README.dvb-usb for more information
+ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information
  */
 #ifndef _DVB_USB_VP7045_H_
 #define _DVB_USB_VP7045_H_
index 5a69016ed75fbb2e9356e9bec2e4b14bb57d1a74..13a00399ced9f21ab26a593aef50401f13b80b6d 100644 (file)
@@ -5,7 +5,5 @@ config USB_M5602
          Say Y here if you want support for cameras based on the
          ALi m5602 connected to various image sensors.
 
-         See <file:Documentation/video4linux/m5602.txt> for more info.
-
          To compile this driver as a module, choose M here: the
          module will be called gspca_m5602.
index 290254ab06dbb01edac5ddc362b3d89eebf1662d..b205903a3c61ada0ae830f46461fc5ac00d97f22 100644 (file)
@@ -12,9 +12,9 @@ config DVB_TTUSB_DEC
          an external software decoder to watch TV on your computer.
 
          This driver needs external firmware. Please use the commands
-         "<kerneldir>/Documentation/dvb/get_dvb_firmware dec2000t",
-         "<kerneldir>/Documentation/dvb/get_dvb_firmware dec2540t",
-         "<kerneldir>/Documentation/dvb/get_dvb_firmware dec3000s",
+         "<kerneldir>/scripts/get_dvb_firmware dec2000t",
+         "<kerneldir>/scripts/get_dvb_firmware dec2540t",
+         "<kerneldir>/scripts/get_dvb_firmware dec3000s",
          download/extract them, and then copy them to /usr/lib/hotplug/firmware
          or /lib/firmware (depending on configuration of firmware hotplug).
 
index 0f585662881dbb94ca7af8e69b66599eaf57e172..ac429bca70e8a671476224c1575b70b097629ed0 100644 (file)
@@ -6,7 +6,7 @@ config USB_ZR364XX
        ---help---
          Say Y here if you want to connect this type of camera to your
          computer's USB port.
-         See <file:Documentation/video4linux/zr364xx.txt> for more info
+         See <file:Documentation/media/v4l-drivers/zr364xx.rst> for more info
          and list of supported cameras.
 
          To compile this driver as a module, choose M here: the
index 55d19fd0994eaeb9d777c38a11bfb5c03bffad5e..2a87b0d2f21ff034ee8f1f7ddd4684b1bb1c300e 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/pci.h>
-#include <linux/i2c-gpio.h>
+#include <linux/platform_data/i2c-gpio.h>
 #include <linux/gpio/machine.h>
 #include <linux/slab.h>
 
index 05ecf828b2ab241331a926186747a2c1005567b0..436e34705af1a1b9e7fb6af8a267f9e674208b26 100644 (file)
@@ -30,8 +30,8 @@
 #include <linux/timb_gpio.h>
 
 #include <linux/i2c.h>
-#include <linux/i2c-ocores.h>
-#include <linux/i2c-xiic.h>
+#include <linux/platform_data/i2c-ocores.h>
+#include <linux/platform_data/i2c-xiic.h>
 
 #include <linux/spi/spi.h>
 #include <linux/spi/xilinx_spi.h>
index 33053b0d1fdf65c2d590598cd361b7869e663522..f5cc517d113154106e7cef474782eacaf47b3952 100644 (file)
@@ -532,6 +532,45 @@ static int at24_get_pdata(struct device *dev, struct at24_platform_data *pdata)
        return 0;
 }
 
+static void at24_remove_dummy_clients(struct at24_data *at24)
+{
+       int i;
+
+       for (i = 1; i < at24->num_addresses; i++)
+               i2c_unregister_device(at24->client[i].client);
+}
+
+static int at24_make_dummy_client(struct at24_data *at24, unsigned int index,
+                                 struct regmap_config *regmap_config)
+{
+       struct i2c_client *base_client, *dummy_client;
+       unsigned short int addr;
+       struct regmap *regmap;
+       struct device *dev;
+
+       base_client = at24->client[0].client;
+       dev = &base_client->dev;
+       addr = base_client->addr + index;
+
+       dummy_client = i2c_new_dummy(base_client->adapter,
+                                    base_client->addr + index);
+       if (!dummy_client) {
+               dev_err(dev, "address 0x%02x unavailable\n", addr);
+               return -EADDRINUSE;
+       }
+
+       regmap = devm_regmap_init_i2c(dummy_client, regmap_config);
+       if (IS_ERR(regmap)) {
+               i2c_unregister_device(dummy_client);
+               return PTR_ERR(regmap);
+       }
+
+       at24->client[index].client = dummy_client;
+       at24->client[index].regmap = regmap;
+
+       return 0;
+}
+
 static unsigned int at24_get_offset_adj(u8 flags, unsigned int byte_len)
 {
        if (flags & AT24_FLAG_MAC) {
@@ -637,20 +676,10 @@ static int at24_probe(struct i2c_client *client)
 
        /* use dummy devices for multiple-address chips */
        for (i = 1; i < num_addresses; i++) {
-               at24->client[i].client = i2c_new_dummy(client->adapter,
-                                                      client->addr + i);
-               if (!at24->client[i].client) {
-                       dev_err(dev, "address 0x%02x unavailable\n",
-                               client->addr + i);
-                       err = -EADDRINUSE;
-                       goto err_clients;
-               }
-               at24->client[i].regmap = devm_regmap_init_i2c(
-                                               at24->client[i].client,
-                                               &regmap_config);
-               if (IS_ERR(at24->client[i].regmap)) {
-                       err = PTR_ERR(at24->client[i].regmap);
-                       goto err_clients;
+               err = at24_make_dummy_client(at24, i, &regmap_config);
+               if (err) {
+                       at24_remove_dummy_clients(at24);
+                       return err;
                }
        }
 
@@ -685,7 +714,7 @@ static int at24_probe(struct i2c_client *client)
        nvmem_config.word_size = 1;
        nvmem_config.size = pdata.byte_len;
 
-       at24->nvmem = nvmem_register(&nvmem_config);
+       at24->nvmem = devm_nvmem_register(dev, &nvmem_config);
        if (IS_ERR(at24->nvmem)) {
                err = PTR_ERR(at24->nvmem);
                goto err_clients;
@@ -702,10 +731,7 @@ static int at24_probe(struct i2c_client *client)
        return 0;
 
 err_clients:
-       for (i = 1; i < num_addresses; i++)
-               if (at24->client[i].client)
-                       i2c_unregister_device(at24->client[i].client);
-
+       at24_remove_dummy_clients(at24);
        pm_runtime_disable(dev);
 
        return err;
@@ -714,15 +740,10 @@ err_clients:
 static int at24_remove(struct i2c_client *client)
 {
        struct at24_data *at24;
-       int i;
 
        at24 = i2c_get_clientdata(client);
 
-       nvmem_unregister(at24->nvmem);
-
-       for (i = 1; i < at24->num_addresses; i++)
-               i2c_unregister_device(at24->client[i].client);
-
+       at24_remove_dummy_clients(at24);
        pm_runtime_disable(&client->dev);
        pm_runtime_set_suspended(&client->dev);
 
index 448d1fafc8270eeb8fe0ef37bd0f0cb7530abc96..f4d81765221ea583b327f97879bc8ae3c705259a 100644 (file)
@@ -325,6 +325,8 @@ struct nicvf {
        struct tasklet_struct   qs_err_task;
        struct work_struct      reset_task;
        struct nicvf_work       rx_mode_work;
+       /* spinlock to protect workqueue arguments from concurrent access */
+       spinlock_t              rx_mode_wq_lock;
 
        /* PTP timestamp */
        struct cavium_ptp       *ptp_clock;
index 7135db45927e59a56e231f172544ce10d76665d5..135766c4296b737c7ffbf34026d61e3f0cf9d13d 100644 (file)
@@ -1923,17 +1923,12 @@ static int nicvf_ioctl(struct net_device *netdev, struct ifreq *req, int cmd)
        }
 }
 
-static void nicvf_set_rx_mode_task(struct work_struct *work_arg)
+static void __nicvf_set_rx_mode_task(u8 mode, struct xcast_addr_list *mc_addrs,
+                                    struct nicvf *nic)
 {
-       struct nicvf_work *vf_work = container_of(work_arg, struct nicvf_work,
-                                                 work.work);
-       struct nicvf *nic = container_of(vf_work, struct nicvf, rx_mode_work);
        union nic_mbx mbx = {};
        int idx;
 
-       if (!vf_work)
-               return;
-
        /* From the inside of VM code flow we have only 128 bits memory
         * available to send message to host's PF, so send all mc addrs
         * one by one, starting from flush command in case if kernel
@@ -1944,7 +1939,7 @@ static void nicvf_set_rx_mode_task(struct work_struct *work_arg)
        mbx.xcast.msg = NIC_MBOX_MSG_RESET_XCAST;
        nicvf_send_msg_to_pf(nic, &mbx);
 
-       if (vf_work->mode & BGX_XCAST_MCAST_FILTER) {
+       if (mode & BGX_XCAST_MCAST_FILTER) {
                /* once enabling filtering, we need to signal to PF to add
                 * its' own LMAC to the filter to accept packets for it.
                 */
@@ -1954,23 +1949,46 @@ static void nicvf_set_rx_mode_task(struct work_struct *work_arg)
        }
 
        /* check if we have any specific MACs to be added to PF DMAC filter */
-       if (vf_work->mc) {
+       if (mc_addrs) {
                /* now go through kernel list of MACs and add them one by one */
-               for (idx = 0; idx < vf_work->mc->count; idx++) {
+               for (idx = 0; idx < mc_addrs->count; idx++) {
                        mbx.xcast.msg = NIC_MBOX_MSG_ADD_MCAST;
-                       mbx.xcast.data.mac = vf_work->mc->mc[idx];
+                       mbx.xcast.data.mac = mc_addrs->mc[idx];
                        nicvf_send_msg_to_pf(nic, &mbx);
                }
-               kfree(vf_work->mc);
+               kfree(mc_addrs);
        }
 
        /* and finally set rx mode for PF accordingly */
        mbx.xcast.msg = NIC_MBOX_MSG_SET_XCAST;
-       mbx.xcast.data.mode = vf_work->mode;
+       mbx.xcast.data.mode = mode;
 
        nicvf_send_msg_to_pf(nic, &mbx);
 }
 
+static void nicvf_set_rx_mode_task(struct work_struct *work_arg)
+{
+       struct nicvf_work *vf_work = container_of(work_arg, struct nicvf_work,
+                                                 work.work);
+       struct nicvf *nic = container_of(vf_work, struct nicvf, rx_mode_work);
+       u8 mode;
+       struct xcast_addr_list *mc;
+
+       if (!vf_work)
+               return;
+
+       /* Save message data locally to prevent them from
+        * being overwritten by next ndo_set_rx_mode call().
+        */
+       spin_lock(&nic->rx_mode_wq_lock);
+       mode = vf_work->mode;
+       mc = vf_work->mc;
+       vf_work->mc = NULL;
+       spin_unlock(&nic->rx_mode_wq_lock);
+
+       __nicvf_set_rx_mode_task(mode, mc, nic);
+}
+
 static void nicvf_set_rx_mode(struct net_device *netdev)
 {
        struct nicvf *nic = netdev_priv(netdev);
@@ -2004,9 +2022,12 @@ static void nicvf_set_rx_mode(struct net_device *netdev)
                        }
                }
        }
+       spin_lock(&nic->rx_mode_wq_lock);
+       kfree(nic->rx_mode_work.mc);
        nic->rx_mode_work.mc = mc_list;
        nic->rx_mode_work.mode = mode;
-       queue_delayed_work(nicvf_rx_mode_wq, &nic->rx_mode_work.work, 2 * HZ);
+       queue_delayed_work(nicvf_rx_mode_wq, &nic->rx_mode_work.work, 0);
+       spin_unlock(&nic->rx_mode_wq_lock);
 }
 
 static const struct net_device_ops nicvf_netdev_ops = {
@@ -2163,6 +2184,7 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        INIT_WORK(&nic->reset_task, nicvf_reset_task);
 
        INIT_DELAYED_WORK(&nic->rx_mode_work.work, nicvf_set_rx_mode_task);
+       spin_lock_init(&nic->rx_mode_wq_lock);
 
        err = register_netdev(netdev);
        if (err) {
index 2edfdbdaae4849a4007f0904d63ca612c100dcf9..7b795edd9d3a9543271d29acf0cc35d760a6b065 100644 (file)
@@ -3362,10 +3362,17 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        err = sysfs_create_group(&adapter->port[0]->dev.kobj,
                                 &cxgb3_attr_group);
+       if (err) {
+               dev_err(&pdev->dev, "cannot create sysfs group\n");
+               goto out_close_led;
+       }
 
        print_port_info(adapter, ai);
        return 0;
 
+out_close_led:
+       t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL, 0);
+
 out_free_dev:
        iounmap(adapter->regs);
        for (i = ai->nports0 + ai->nports1 - 1; i >= 0; --i)
index 14d287bed33c4e65100d04458af127cdc6bfa0d5..1ab613eb5796420c217d66287f72592c5875a55d 100644 (file)
@@ -33,7 +33,7 @@ config E100
          to identify the adapter.
 
          More specific information on configuring the driver is in
-         <file:Documentation/networking/e100.txt>.
+         <file:Documentation/networking/e100.rst>.
 
          To compile this driver as a module, choose M here. The module
          will be called e100.
@@ -49,7 +49,7 @@ config E1000
          <http://support.intel.com>
 
          More specific information on configuring the driver is in
-         <file:Documentation/networking/e1000.txt>.
+         <file:Documentation/networking/e1000.rst>.
 
          To compile this driver as a module, choose M here. The module
          will be called e1000.
@@ -94,7 +94,7 @@ config IGB
          <http://support.intel.com>
 
          More specific information on configuring the driver is in
-         <file:Documentation/networking/e1000.txt>.
+         <file:Documentation/networking/e1000.rst>.
 
          To compile this driver as a module, choose M here. The module
          will be called igb.
@@ -130,7 +130,7 @@ config IGBVF
          <http://support.intel.com>
 
          More specific information on configuring the driver is in
-         <file:Documentation/networking/e1000.txt>.
+         <file:Documentation/networking/e1000.rst>.
 
          To compile this driver as a module, choose M here. The module
          will be called igbvf.
index fc534e91c6b247ebc79c47c470445eebe20d3b48..144d5fe6b94477def970671ab94cd1fb77711bdb 100644 (file)
@@ -760,9 +760,9 @@ struct ixgbe_adapter {
 #define IXGBE_RSS_KEY_SIZE     40  /* size of RSS Hash Key in bytes */
        u32 *rss_key;
 
-#ifdef CONFIG_XFRM
+#ifdef CONFIG_XFRM_OFFLOAD
        struct ixgbe_ipsec *ipsec;
-#endif /* CONFIG_XFRM */
+#endif /* CONFIG_XFRM_OFFLOAD */
 };
 
 static inline u8 ixgbe_max_rss_indices(struct ixgbe_adapter *adapter)
index 344a1f213a5f5e150c86777a343cc96cc641c58e..c116f459945d62455843d4e9262971630dd45099 100644 (file)
@@ -158,7 +158,16 @@ static void ixgbe_ipsec_stop_data(struct ixgbe_adapter *adapter)
        reg |= IXGBE_SECRXCTRL_RX_DIS;
        IXGBE_WRITE_REG(hw, IXGBE_SECRXCTRL, reg);
 
-       IXGBE_WRITE_FLUSH(hw);
+       /* If both Tx and Rx are ready there are no packets
+        * that we need to flush so the loopback configuration
+        * below is not necessary.
+        */
+       t_rdy = IXGBE_READ_REG(hw, IXGBE_SECTXSTAT) &
+               IXGBE_SECTXSTAT_SECTX_RDY;
+       r_rdy = IXGBE_READ_REG(hw, IXGBE_SECRXSTAT) &
+               IXGBE_SECRXSTAT_SECRX_RDY;
+       if (t_rdy && r_rdy)
+               return;
 
        /* If the tx fifo doesn't have link, but still has data,
         * we can't clear the tx sec block.  Set the MAC loopback
@@ -185,7 +194,7 @@ static void ixgbe_ipsec_stop_data(struct ixgbe_adapter *adapter)
                        IXGBE_SECTXSTAT_SECTX_RDY;
                r_rdy = IXGBE_READ_REG(hw, IXGBE_SECRXSTAT) &
                        IXGBE_SECRXSTAT_SECRX_RDY;
-       } while (!t_rdy && !r_rdy && limit--);
+       } while (!(t_rdy && r_rdy) && limit--);
 
        /* undo loopback if we played with it earlier */
        if (!link) {
@@ -966,10 +975,22 @@ void ixgbe_ipsec_rx(struct ixgbe_ring *rx_ring,
  **/
 void ixgbe_init_ipsec_offload(struct ixgbe_adapter *adapter)
 {
+       struct ixgbe_hw *hw = &adapter->hw;
        struct ixgbe_ipsec *ipsec;
+       u32 t_dis, r_dis;
        size_t size;
 
-       if (adapter->hw.mac.type == ixgbe_mac_82598EB)
+       if (hw->mac.type == ixgbe_mac_82598EB)
+               return;
+
+       /* If there is no support for either Tx or Rx offload
+        * we should not be advertising support for IPsec.
+        */
+       t_dis = IXGBE_READ_REG(hw, IXGBE_SECTXSTAT) &
+               IXGBE_SECTXSTAT_SECTX_OFF_DIS;
+       r_dis = IXGBE_READ_REG(hw, IXGBE_SECRXSTAT) &
+               IXGBE_SECRXSTAT_SECRX_OFF_DIS;
+       if (t_dis || r_dis)
                return;
 
        ipsec = kzalloc(sizeof(*ipsec), GFP_KERNEL);
@@ -1001,13 +1022,6 @@ void ixgbe_init_ipsec_offload(struct ixgbe_adapter *adapter)
 
        adapter->netdev->xfrmdev_ops = &ixgbe_xfrmdev_ops;
 
-#define IXGBE_ESP_FEATURES     (NETIF_F_HW_ESP | \
-                                NETIF_F_HW_ESP_TX_CSUM | \
-                                NETIF_F_GSO_ESP)
-
-       adapter->netdev->features |= IXGBE_ESP_FEATURES;
-       adapter->netdev->hw_enc_features |= IXGBE_ESP_FEATURES;
-
        return;
 
 err2:
index 893a9206e718611250196fb6459d80d73d58cd64..d361f570ca37be6a8df4cd2e2c7a806cee8b1a54 100644 (file)
@@ -593,6 +593,14 @@ static bool ixgbe_set_sriov_queues(struct ixgbe_adapter *adapter)
        }
 
 #endif
+       /* To support macvlan offload we have to use num_tc to
+        * restrict the queues that can be used by the device.
+        * By doing this we can avoid reporting a false number of
+        * queues.
+        */
+       if (vmdq_i > 1)
+               netdev_set_num_tc(adapter->netdev, 1);
+
        /* populate TC0 for use by pool 0 */
        netdev_set_tc_queue(adapter->netdev, 0,
                            adapter->num_rx_queues_per_pool, 0);
index 0b1ba3ae159c765726e6b928d425ab8db64de622..3e87dbbc90246dba3a59e3f8ccded5885b441ae2 100644 (file)
@@ -6117,6 +6117,7 @@ static int ixgbe_sw_init(struct ixgbe_adapter *adapter,
 #ifdef CONFIG_IXGBE_DCB
        ixgbe_init_dcb(adapter);
 #endif
+       ixgbe_init_ipsec_offload(adapter);
 
        /* default flow control settings */
        hw->fc.requested_mode = ixgbe_fc_full;
@@ -8822,14 +8823,6 @@ int ixgbe_setup_tc(struct net_device *dev, u8 tc)
        } else {
                netdev_reset_tc(dev);
 
-               /* To support macvlan offload we have to use num_tc to
-                * restrict the queues that can be used by the device.
-                * By doing this we can avoid reporting a false number of
-                * queues.
-                */
-               if (!tc && adapter->num_rx_pools > 1)
-                       netdev_set_num_tc(dev, 1);
-
                if (adapter->hw.mac.type == ixgbe_mac_82598EB)
                        adapter->hw.fc.requested_mode = adapter->last_lfc_mode;
 
@@ -9904,7 +9897,7 @@ ixgbe_features_check(struct sk_buff *skb, struct net_device *dev,
         * the TSO, so it's the exception.
         */
        if (skb->encapsulation && !(features & NETIF_F_TSO_MANGLEID)) {
-#ifdef CONFIG_XFRM
+#ifdef CONFIG_XFRM_OFFLOAD
                if (!skb->sp)
 #endif
                        features &= ~NETIF_F_TSO;
@@ -10437,6 +10430,14 @@ skip_sriov:
        if (hw->mac.type >= ixgbe_mac_82599EB)
                netdev->features |= NETIF_F_SCTP_CRC;
 
+#ifdef CONFIG_XFRM_OFFLOAD
+#define IXGBE_ESP_FEATURES     (NETIF_F_HW_ESP | \
+                                NETIF_F_HW_ESP_TX_CSUM | \
+                                NETIF_F_GSO_ESP)
+
+       if (adapter->ipsec)
+               netdev->features |= IXGBE_ESP_FEATURES;
+#endif
        /* copy netdev features into list of user selectable features */
        netdev->hw_features |= netdev->features |
                               NETIF_F_HW_VLAN_CTAG_FILTER |
@@ -10499,8 +10500,6 @@ skip_sriov:
                                         NETIF_F_FCOE_MTU;
        }
 #endif /* IXGBE_FCOE */
-       ixgbe_init_ipsec_offload(adapter);
-
        if (adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE)
                netdev->hw_features |= NETIF_F_LRO;
        if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED)
index e8ed37749ab1c91be3223a9ff727cd33ca21a046..44cfb2021145b9be9284c3862c52abf5c5ba6f82 100644 (file)
@@ -599,13 +599,15 @@ struct ixgbe_nvm_version {
 #define IXGBE_SECTXCTRL_STORE_FORWARD   0x00000004
 
 #define IXGBE_SECTXSTAT_SECTX_RDY       0x00000001
-#define IXGBE_SECTXSTAT_ECC_TXERR       0x00000002
+#define IXGBE_SECTXSTAT_SECTX_OFF_DIS   0x00000002
+#define IXGBE_SECTXSTAT_ECC_TXERR       0x00000004
 
 #define IXGBE_SECRXCTRL_SECRX_DIS       0x00000001
 #define IXGBE_SECRXCTRL_RX_DIS          0x00000002
 
 #define IXGBE_SECRXSTAT_SECRX_RDY       0x00000001
-#define IXGBE_SECRXSTAT_ECC_RXERR       0x00000002
+#define IXGBE_SECRXSTAT_SECRX_OFF_DIS   0x00000002
+#define IXGBE_SECRXSTAT_ECC_RXERR       0x00000004
 
 /* LinkSec (MacSec) Registers */
 #define IXGBE_LSECTXCAP         0x08A00
index 77b2adb293415a9de16caaabbd203b397cd12a4a..6aaaf3d9ba31d9538d9307caa0450a848bf6b091 100644 (file)
@@ -4756,12 +4756,6 @@ static void mlxsw_sp_rt6_destroy(struct mlxsw_sp_rt6 *mlxsw_sp_rt6)
        kfree(mlxsw_sp_rt6);
 }
 
-static bool mlxsw_sp_fib6_rt_can_mp(const struct fib6_info *rt)
-{
-       /* RTF_CACHE routes are ignored */
-       return (rt->fib6_flags & (RTF_GATEWAY | RTF_ADDRCONF)) == RTF_GATEWAY;
-}
-
 static struct fib6_info *
 mlxsw_sp_fib6_entry_rt(const struct mlxsw_sp_fib6_entry *fib6_entry)
 {
@@ -4771,11 +4765,11 @@ mlxsw_sp_fib6_entry_rt(const struct mlxsw_sp_fib6_entry *fib6_entry)
 
 static struct mlxsw_sp_fib6_entry *
 mlxsw_sp_fib6_node_mp_entry_find(const struct mlxsw_sp_fib_node *fib_node,
-                                const struct fib6_info *nrt, bool replace)
+                                const struct fib6_info *nrt, bool append)
 {
        struct mlxsw_sp_fib6_entry *fib6_entry;
 
-       if (!mlxsw_sp_fib6_rt_can_mp(nrt) || replace)
+       if (!append)
                return NULL;
 
        list_for_each_entry(fib6_entry, &fib_node->entry_list, common.list) {
@@ -4790,8 +4784,7 @@ mlxsw_sp_fib6_node_mp_entry_find(const struct mlxsw_sp_fib_node *fib_node,
                        break;
                if (rt->fib6_metric < nrt->fib6_metric)
                        continue;
-               if (rt->fib6_metric == nrt->fib6_metric &&
-                   mlxsw_sp_fib6_rt_can_mp(rt))
+               if (rt->fib6_metric == nrt->fib6_metric)
                        return fib6_entry;
                if (rt->fib6_metric > nrt->fib6_metric)
                        break;
@@ -5170,7 +5163,7 @@ static struct mlxsw_sp_fib6_entry *
 mlxsw_sp_fib6_node_entry_find(const struct mlxsw_sp_fib_node *fib_node,
                              const struct fib6_info *nrt, bool replace)
 {
-       struct mlxsw_sp_fib6_entry *fib6_entry, *fallback = NULL;
+       struct mlxsw_sp_fib6_entry *fib6_entry;
 
        list_for_each_entry(fib6_entry, &fib_node->entry_list, common.list) {
                struct fib6_info *rt = mlxsw_sp_fib6_entry_rt(fib6_entry);
@@ -5179,18 +5172,13 @@ mlxsw_sp_fib6_node_entry_find(const struct mlxsw_sp_fib_node *fib_node,
                        continue;
                if (rt->fib6_table->tb6_id != nrt->fib6_table->tb6_id)
                        break;
-               if (replace && rt->fib6_metric == nrt->fib6_metric) {
-                       if (mlxsw_sp_fib6_rt_can_mp(rt) ==
-                           mlxsw_sp_fib6_rt_can_mp(nrt))
-                               return fib6_entry;
-                       if (mlxsw_sp_fib6_rt_can_mp(nrt))
-                               fallback = fallback ?: fib6_entry;
-               }
+               if (replace && rt->fib6_metric == nrt->fib6_metric)
+                       return fib6_entry;
                if (rt->fib6_metric > nrt->fib6_metric)
-                       return fallback ?: fib6_entry;
+                       return fib6_entry;
        }
 
-       return fallback;
+       return NULL;
 }
 
 static int
@@ -5316,7 +5304,8 @@ static void mlxsw_sp_fib6_entry_replace(struct mlxsw_sp *mlxsw_sp,
 }
 
 static int mlxsw_sp_router_fib6_add(struct mlxsw_sp *mlxsw_sp,
-                                   struct fib6_info *rt, bool replace)
+                                   struct fib6_info *rt, bool replace,
+                                   bool append)
 {
        struct mlxsw_sp_fib6_entry *fib6_entry;
        struct mlxsw_sp_fib_node *fib_node;
@@ -5342,7 +5331,7 @@ static int mlxsw_sp_router_fib6_add(struct mlxsw_sp *mlxsw_sp,
        /* Before creating a new entry, try to append route to an existing
         * multipath entry.
         */
-       fib6_entry = mlxsw_sp_fib6_node_mp_entry_find(fib_node, rt, replace);
+       fib6_entry = mlxsw_sp_fib6_node_mp_entry_find(fib_node, rt, append);
        if (fib6_entry) {
                err = mlxsw_sp_fib6_entry_nexthop_add(mlxsw_sp, fib6_entry, rt);
                if (err)
@@ -5350,6 +5339,14 @@ static int mlxsw_sp_router_fib6_add(struct mlxsw_sp *mlxsw_sp,
                return 0;
        }
 
+       /* We received an append event, yet did not find any route to
+        * append to.
+        */
+       if (WARN_ON(append)) {
+               err = -EINVAL;
+               goto err_fib6_entry_append;
+       }
+
        fib6_entry = mlxsw_sp_fib6_entry_create(mlxsw_sp, fib_node, rt);
        if (IS_ERR(fib6_entry)) {
                err = PTR_ERR(fib6_entry);
@@ -5367,6 +5364,7 @@ static int mlxsw_sp_router_fib6_add(struct mlxsw_sp *mlxsw_sp,
 err_fib6_node_entry_link:
        mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_entry);
 err_fib6_entry_create:
+err_fib6_entry_append:
 err_fib6_entry_nexthop_add:
        mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
        return err;
@@ -5717,7 +5715,7 @@ static void mlxsw_sp_router_fib6_event_work(struct work_struct *work)
        struct mlxsw_sp_fib_event_work *fib_work =
                container_of(work, struct mlxsw_sp_fib_event_work, work);
        struct mlxsw_sp *mlxsw_sp = fib_work->mlxsw_sp;
-       bool replace;
+       bool replace, append;
        int err;
 
        rtnl_lock();
@@ -5728,8 +5726,10 @@ static void mlxsw_sp_router_fib6_event_work(struct work_struct *work)
        case FIB_EVENT_ENTRY_APPEND: /* fall through */
        case FIB_EVENT_ENTRY_ADD:
                replace = fib_work->event == FIB_EVENT_ENTRY_REPLACE;
+               append = fib_work->event == FIB_EVENT_ENTRY_APPEND;
                err = mlxsw_sp_router_fib6_add(mlxsw_sp,
-                                              fib_work->fen6_info.rt, replace);
+                                              fib_work->fen6_info.rt, replace,
+                                              append);
                if (err)
                        mlxsw_sp_router_fib_abort(mlxsw_sp);
                mlxsw_sp_rt6_release(fib_work->fen6_info.rt);
index e97652c40d13a40fad9bb71e2c554b9d3933bef5..eea5666a86b2ae341524710e678d4caf5776a18b 100644 (file)
@@ -1018,8 +1018,10 @@ mlxsw_sp_port_vlan_bridge_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
        int err;
 
        /* No need to continue if only VLAN flags were changed */
-       if (mlxsw_sp_port_vlan->bridge_port)
+       if (mlxsw_sp_port_vlan->bridge_port) {
+               mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan);
                return 0;
+       }
 
        err = mlxsw_sp_port_vlan_fid_join(mlxsw_sp_port_vlan, bridge_port);
        if (err)
index 19cfa162ac6556868c5115f0cf83a2dd03bdbd15..1decf3a1cad34cf8b8bbe50ae2fe268fc9775049 100644 (file)
@@ -455,6 +455,7 @@ static int nfp_flower_vnic_alloc(struct nfp_app *app, struct nfp_net *nn,
 
        eth_hw_addr_random(nn->dp.netdev);
        netif_keep_dst(nn->dp.netdev);
+       nn->vnic_no_name = true;
 
        return 0;
 
index ec524d97869d6fdf12160eda47aa4043aa4fedeb..78afe75129ab5b7a852d5bffa40f5daa9b1c76d1 100644 (file)
@@ -381,6 +381,8 @@ nfp_tun_neigh_event_handler(struct notifier_block *nb, unsigned long event,
        err = PTR_ERR_OR_ZERO(rt);
        if (err)
                return NOTIFY_DONE;
+
+       ip_rt_put(rt);
 #else
        return NOTIFY_DONE;
 #endif
index 57cb035dcc6dc82afd7d0826e541c4b49e7745ac..2a71a9ffd095a87e19c4546fc0838dafd7cbb28e 100644 (file)
@@ -590,6 +590,8 @@ struct nfp_net_dp {
  * @vnic_list:         Entry on device vNIC list
  * @pdev:              Backpointer to PCI device
  * @app:               APP handle if available
+ * @vnic_no_name:      For non-port PF vNIC make ndo_get_phys_port_name return
+ *                     -EOPNOTSUPP to keep backwards compatibility (set by app)
  * @port:              Pointer to nfp_port structure if vNIC is a port
  * @app_priv:          APP private data for this vNIC
  */
@@ -663,6 +665,8 @@ struct nfp_net {
        struct pci_dev *pdev;
        struct nfp_app *app;
 
+       bool vnic_no_name;
+
        struct nfp_port *port;
 
        void *app_priv;
index 75110c8d6a9034ff049d9ff8cf5e9105618fcb76..d4c27f849f9bbfae5d2d9e795fe28a000839bc07 100644 (file)
@@ -3121,7 +3121,7 @@ static void nfp_net_stat64(struct net_device *netdev,
        struct nfp_net *nn = netdev_priv(netdev);
        int r;
 
-       for (r = 0; r < nn->dp.num_r_vecs; r++) {
+       for (r = 0; r < nn->max_r_vecs; r++) {
                struct nfp_net_r_vector *r_vec = &nn->r_vecs[r];
                u64 data[3];
                unsigned int start;
@@ -3286,7 +3286,7 @@ nfp_net_get_phys_port_name(struct net_device *netdev, char *name, size_t len)
        if (nn->port)
                return nfp_port_get_phys_port_name(netdev, name, len);
 
-       if (nn->dp.is_vf)
+       if (nn->dp.is_vf || nn->vnic_no_name)
                return -EOPNOTSUPP;
 
        n = snprintf(name, len, "n%d", nn->id);
index 2dd89dba9311ae6ec97377874f01d439729a2a67..d32af598da9081cbacfa6af9b16cb8d7f957ed50 100644 (file)
@@ -98,21 +98,18 @@ struct nfp_resource {
 
 static int nfp_cpp_resource_find(struct nfp_cpp *cpp, struct nfp_resource *res)
 {
-       char name_pad[NFP_RESOURCE_ENTRY_NAME_SZ] = {};
        struct nfp_resource_entry entry;
        u32 cpp_id, key;
        int ret, i;
 
        cpp_id = NFP_CPP_ID(NFP_RESOURCE_TBL_TARGET, 3, 0);  /* Atomic read */
 
-       strncpy(name_pad, res->name, sizeof(name_pad));
-
        /* Search for a matching entry */
-       if (!memcmp(name_pad, NFP_RESOURCE_TBL_NAME "\0\0\0\0\0\0\0\0", 8)) {
+       if (!strcmp(res->name, NFP_RESOURCE_TBL_NAME)) {
                nfp_err(cpp, "Grabbing device lock not supported\n");
                return -EOPNOTSUPP;
        }
-       key = crc32_posix(name_pad, sizeof(name_pad));
+       key = crc32_posix(res->name, NFP_RESOURCE_ENTRY_NAME_SZ);
 
        for (i = 0; i < NFP_RESOURCE_TBL_ENTRIES; i++) {
                u64 addr = NFP_RESOURCE_TBL_BASE +
index e78e5db394589674e981bc802a09bdf918c3183c..c694e3428dfc4706a0b4652271211b1145d8110e 100644 (file)
@@ -384,6 +384,7 @@ int emac_sgmii_config(struct platform_device *pdev, struct emac_adapter *adpt)
                }
 
                sgmii_pdev = of_find_device_by_node(np);
+               of_node_put(np);
                if (!sgmii_pdev) {
                        dev_err(&pdev->dev, "invalid internal-phy property\n");
                        return -ENODEV;
index 4ff231df73225dc449b21c7c1f312666b2a957fd..c5979569fd60f28fbf67b72f0c03cd613355d9cc 100644 (file)
@@ -334,9 +334,10 @@ static int meson8b_dwmac_probe(struct platform_device *pdev)
 
        dwmac->data = (const struct meson8b_dwmac_data *)
                of_device_get_match_data(&pdev->dev);
-       if (!dwmac->data)
-               return -EINVAL;
-
+       if (!dwmac->data) {
+               ret = -EINVAL;
+               goto err_remove_config_dt;
+       }
        res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
        dwmac->regs = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(dwmac->regs)) {
index 14770fc8865e8022d06fc0e05b7aa27feab2117d..1f50e83cafb2c14d2d783ac471a562801424265b 100644 (file)
@@ -252,13 +252,8 @@ int stmmac_hwif_init(struct stmmac_priv *priv)
                                return ret;
                }
 
-               /* Run quirks, if needed */
-               if (entry->quirks) {
-                       ret = entry->quirks(priv);
-                       if (ret)
-                               return ret;
-               }
-
+               /* Save quirks, if needed for posterior use */
+               priv->hwif_quirks = entry->quirks;
                return 0;
        }
 
index 025efbf6145cca6ce55b63a654cb5ec78d0d7fa9..76649adf8fb0639e66094cb29f83ed58f124bf2c 100644 (file)
@@ -129,6 +129,7 @@ struct stmmac_priv {
        struct net_device *dev;
        struct device *device;
        struct mac_device_info *hw;
+       int (*hwif_quirks)(struct stmmac_priv *priv);
        struct mutex lock;
 
        /* RX Queue */
index 11fb7c777d89b6b1e86b9aa1a83c8345a664fb23..e79b0d7b388a16d524917b0dfed1b4dd2f079c2f 100644 (file)
@@ -3182,17 +3182,22 @@ dma_map_err:
 
 static void stmmac_rx_vlan(struct net_device *dev, struct sk_buff *skb)
 {
-       struct ethhdr *ehdr;
+       struct vlan_ethhdr *veth;
+       __be16 vlan_proto;
        u16 vlanid;
 
-       if ((dev->features & NETIF_F_HW_VLAN_CTAG_RX) ==
-           NETIF_F_HW_VLAN_CTAG_RX &&
-           !__vlan_get_tag(skb, &vlanid)) {
+       veth = (struct vlan_ethhdr *)skb->data;
+       vlan_proto = veth->h_vlan_proto;
+
+       if ((vlan_proto == htons(ETH_P_8021Q) &&
+            dev->features & NETIF_F_HW_VLAN_CTAG_RX) ||
+           (vlan_proto == htons(ETH_P_8021AD) &&
+            dev->features & NETIF_F_HW_VLAN_STAG_RX)) {
                /* pop the vlan tag */
-               ehdr = (struct ethhdr *)skb->data;
-               memmove(skb->data + VLAN_HLEN, ehdr, ETH_ALEN * 2);
+               vlanid = ntohs(veth->h_vlan_TCI);
+               memmove(skb->data + VLAN_HLEN, veth, ETH_ALEN * 2);
                skb_pull(skb, VLAN_HLEN);
-               __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlanid);
+               __vlan_hwaccel_put_tag(skb, vlan_proto, vlanid);
        }
 }
 
@@ -4130,6 +4135,13 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
        if (priv->dma_cap.tsoen)
                dev_info(priv->device, "TSO supported\n");
 
+       /* Run HW quirks, if any */
+       if (priv->hwif_quirks) {
+               ret = priv->hwif_quirks(priv);
+               if (ret)
+                       return ret;
+       }
+
        return 0;
 }
 
@@ -4235,7 +4247,7 @@ int stmmac_dvr_probe(struct device *device,
        ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
 #ifdef STMMAC_VLAN_TAG_USED
        /* Both mac100 and gmac support receive VLAN tag detection */
-       ndev->features |= NETIF_F_HW_VLAN_CTAG_RX;
+       ndev->features |= NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_STAG_RX;
 #endif
        priv->msg_enable = netif_msg_init(debug, default_msg_level);
 
index 69e31ceccfae4d90a56f6e49312112ec372d1d48..2a0c06e0f730c35e5e7d40d9d9893bf36cf9c6fa 100644 (file)
  * @phy_node:          pointer to the PHY device node
  * @mii_bus:           pointer to the MII bus
  * @last_link:         last link status
- * @has_mdio:          indicates whether MDIO is included in the HW
  */
 struct net_local {
 
@@ -144,7 +143,6 @@ struct net_local {
        struct mii_bus *mii_bus;
 
        int last_link;
-       bool has_mdio;
 };
 
 
@@ -863,14 +861,14 @@ static int xemaclite_mdio_setup(struct net_local *lp, struct device *dev)
        bus->write = xemaclite_mdio_write;
        bus->parent = dev;
 
-       lp->mii_bus = bus;
-
        rc = of_mdiobus_register(bus, np);
        if (rc) {
                dev_err(dev, "Failed to register mdio bus.\n");
                goto err_register;
        }
 
+       lp->mii_bus = bus;
+
        return 0;
 
 err_register:
@@ -1145,9 +1143,7 @@ static int xemaclite_of_probe(struct platform_device *ofdev)
        xemaclite_update_address(lp, ndev->dev_addr);
 
        lp->phy_node = of_parse_phandle(ofdev->dev.of_node, "phy-handle", 0);
-       rc = xemaclite_mdio_setup(lp, &ofdev->dev);
-       if (rc)
-               dev_warn(&ofdev->dev, "error registering MDIO bus\n");
+       xemaclite_mdio_setup(lp, &ofdev->dev);
 
        dev_info(dev, "MAC address is now %pM\n", ndev->dev_addr);
 
@@ -1191,7 +1187,7 @@ static int xemaclite_of_remove(struct platform_device *of_dev)
        struct net_local *lp = netdev_priv(ndev);
 
        /* Un-register the mii_bus, if configured */
-       if (lp->has_mdio) {
+       if (lp->mii_bus) {
                mdiobus_unregister(lp->mii_bus);
                mdiobus_free(lp->mii_bus);
                lp->mii_bus = NULL;
index 23a2d145813ab9fb449a4dd3f7fc1a934bcd9137..0765d5f61714e6a1a8679802cb079ea45053a2f2 100644 (file)
@@ -2,6 +2,5 @@ config HYPERV_NET
        tristate "Microsoft Hyper-V virtual network driver"
        depends on HYPERV
        select UCS2_STRING
-       select FAILOVER
        help
          Select this option to enable the Hyper-V virtual network driver.
index 23304aca25f95d69ef7f6ede3a0c2df45cd805be..1a924b867b0742b0aa3e5a15f4da3e6885173e74 100644 (file)
@@ -901,6 +901,8 @@ struct net_device_context {
        struct hv_device *device_ctx;
        /* netvsc_device */
        struct netvsc_device __rcu *nvdev;
+       /* list of netvsc net_devices */
+       struct list_head list;
        /* reconfigure work */
        struct delayed_work dwork;
        /* last reconfig time */
@@ -931,8 +933,6 @@ struct net_device_context {
        u32 vf_alloc;
        /* Serial number of the VF to team with */
        u32 vf_serial;
-
-       struct failover *failover;
 };
 
 /* Per channel data */
@@ -1277,17 +1277,17 @@ struct ndis_lsov2_offload {
 
 struct ndis_ipsecv2_offload {
        u32     encap;
-       u16     ip6;
-       u16     ip4opt;
-       u16     ip6ext;
-       u16     ah;
-       u16     esp;
-       u16     ah_esp;
-       u16     xport;
-       u16     tun;
-       u16     xport_tun;
-       u16     lso;
-       u16     extseq;
+       u     ip6;
+       u     ip4opt;
+       u     ip6ext;
+       u     ah;
+       u     esp;
+       u     ah_esp;
+       u     xport;
+       u     tun;
+       u     xport_tun;
+       u     lso;
+       u     extseq;
        u32     udp_esp;
        u32     auth;
        u32     crypto;
@@ -1295,8 +1295,8 @@ struct ndis_ipsecv2_offload {
 };
 
 struct ndis_rsc_offload {
-       u16     ip4;
-       u16     ip6;
+       u     ip4;
+       u     ip6;
 };
 
 struct ndis_encap_offload {
index 7b18a8c267c2b88d2c5e84bfa87da9691883c154..fe2256bf1d137fea6b76c5e3a564b191e2b5da7c 100644 (file)
@@ -42,7 +42,6 @@
 #include <net/pkt_sched.h>
 #include <net/checksum.h>
 #include <net/ip6_checksum.h>
-#include <net/failover.h>
 
 #include "hyperv_net.h"
 
@@ -68,6 +67,8 @@ static int debug = -1;
 module_param(debug, int, 0444);
 MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
 
+static LIST_HEAD(netvsc_dev_list);
+
 static void netvsc_change_rx_flags(struct net_device *net, int change)
 {
        struct net_device_context *ndev_ctx = netdev_priv(net);
@@ -1780,6 +1781,36 @@ out_unlock:
        rtnl_unlock();
 }
 
+static struct net_device *get_netvsc_bymac(const u8 *mac)
+{
+       struct net_device_context *ndev_ctx;
+
+       list_for_each_entry(ndev_ctx, &netvsc_dev_list, list) {
+               struct net_device *dev = hv_get_drvdata(ndev_ctx->device_ctx);
+
+               if (ether_addr_equal(mac, dev->perm_addr))
+                       return dev;
+       }
+
+       return NULL;
+}
+
+static struct net_device *get_netvsc_byref(struct net_device *vf_netdev)
+{
+       struct net_device_context *net_device_ctx;
+       struct net_device *dev;
+
+       dev = netdev_master_upper_dev_get(vf_netdev);
+       if (!dev || dev->netdev_ops != &device_ops)
+               return NULL;    /* not a netvsc device */
+
+       net_device_ctx = netdev_priv(dev);
+       if (!rtnl_dereference(net_device_ctx->nvdev))
+               return NULL;    /* device is removed */
+
+       return dev;
+}
+
 /* Called when VF is injecting data into network stack.
  * Change the associated network device from VF to netvsc.
  * note: already called with rcu_read_lock
@@ -1802,6 +1833,46 @@ static rx_handler_result_t netvsc_vf_handle_frame(struct sk_buff **pskb)
        return RX_HANDLER_ANOTHER;
 }
 
+static int netvsc_vf_join(struct net_device *vf_netdev,
+                         struct net_device *ndev)
+{
+       struct net_device_context *ndev_ctx = netdev_priv(ndev);
+       int ret;
+
+       ret = netdev_rx_handler_register(vf_netdev,
+                                        netvsc_vf_handle_frame, ndev);
+       if (ret != 0) {
+               netdev_err(vf_netdev,
+                          "can not register netvsc VF receive handler (err = %d)\n",
+                          ret);
+               goto rx_handler_failed;
+       }
+
+       ret = netdev_master_upper_dev_link(vf_netdev, ndev,
+                                          NULL, NULL, NULL);
+       if (ret != 0) {
+               netdev_err(vf_netdev,
+                          "can not set master device %s (err = %d)\n",
+                          ndev->name, ret);
+               goto upper_link_failed;
+       }
+
+       /* set slave flag before open to prevent IPv6 addrconf */
+       vf_netdev->flags |= IFF_SLAVE;
+
+       schedule_delayed_work(&ndev_ctx->vf_takeover, VF_TAKEOVER_INT);
+
+       call_netdevice_notifiers(NETDEV_JOIN, vf_netdev);
+
+       netdev_info(vf_netdev, "joined to %s\n", ndev->name);
+       return 0;
+
+upper_link_failed:
+       netdev_rx_handler_unregister(vf_netdev);
+rx_handler_failed:
+       return ret;
+}
+
 static void __netvsc_vf_setup(struct net_device *ndev,
                              struct net_device *vf_netdev)
 {
@@ -1852,95 +1923,104 @@ static void netvsc_vf_setup(struct work_struct *w)
        rtnl_unlock();
 }
 
-static int netvsc_pre_register_vf(struct net_device *vf_netdev,
-                                 struct net_device *ndev)
+static int netvsc_register_vf(struct net_device *vf_netdev)
 {
+       struct net_device *ndev;
        struct net_device_context *net_device_ctx;
        struct netvsc_device *netvsc_dev;
+       int ret;
+
+       if (vf_netdev->addr_len != ETH_ALEN)
+               return NOTIFY_DONE;
+
+       /*
+        * We will use the MAC address to locate the synthetic interface to
+        * associate with the VF interface. If we don't find a matching
+        * synthetic interface, move on.
+        */
+       ndev = get_netvsc_bymac(vf_netdev->perm_addr);
+       if (!ndev)
+               return NOTIFY_DONE;
 
        net_device_ctx = netdev_priv(ndev);
        netvsc_dev = rtnl_dereference(net_device_ctx->nvdev);
        if (!netvsc_dev || rtnl_dereference(net_device_ctx->vf_netdev))
-               return -ENODEV;
-
-       return 0;
-}
+               return NOTIFY_DONE;
 
-static int netvsc_register_vf(struct net_device *vf_netdev,
-                             struct net_device *ndev)
-{
-       struct net_device_context *ndev_ctx = netdev_priv(ndev);
-
-       /* set slave flag before open to prevent IPv6 addrconf */
-       vf_netdev->flags |= IFF_SLAVE;
-
-       schedule_delayed_work(&ndev_ctx->vf_takeover, VF_TAKEOVER_INT);
+       /* if syntihetic interface is a different namespace,
+        * then move the VF to that namespace; join will be
+        * done again in that context.
+        */
+       if (!net_eq(dev_net(ndev), dev_net(vf_netdev))) {
+               ret = dev_change_net_namespace(vf_netdev,
+                                              dev_net(ndev), "eth%d");
+               if (ret)
+                       netdev_err(vf_netdev,
+                                  "could not move to same namespace as %s: %d\n",
+                                  ndev->name, ret);
+               else
+                       netdev_info(vf_netdev,
+                                   "VF moved to namespace with: %s\n",
+                                   ndev->name);
+               return NOTIFY_DONE;
+       }
 
-       call_netdevice_notifiers(NETDEV_JOIN, vf_netdev);
+       netdev_info(ndev, "VF registering: %s\n", vf_netdev->name);
 
-       netdev_info(vf_netdev, "joined to %s\n", ndev->name);
+       if (netvsc_vf_join(vf_netdev, ndev) != 0)
+               return NOTIFY_DONE;
 
        dev_hold(vf_netdev);
-       rcu_assign_pointer(ndev_ctx->vf_netdev, vf_netdev);
-
-       return 0;
+       rcu_assign_pointer(net_device_ctx->vf_netdev, vf_netdev);
+       return NOTIFY_OK;
 }
 
 /* VF up/down change detected, schedule to change data path */
-static int netvsc_vf_changed(struct net_device *vf_netdev,
-                            struct net_device *ndev)
+static int netvsc_vf_changed(struct net_device *vf_netdev)
 {
        struct net_device_context *net_device_ctx;
        struct netvsc_device *netvsc_dev;
+       struct net_device *ndev;
        bool vf_is_up = netif_running(vf_netdev);
 
+       ndev = get_netvsc_byref(vf_netdev);
+       if (!ndev)
+               return NOTIFY_DONE;
+
        net_device_ctx = netdev_priv(ndev);
        netvsc_dev = rtnl_dereference(net_device_ctx->nvdev);
        if (!netvsc_dev)
-               return -ENODEV;
+               return NOTIFY_DONE;
 
        netvsc_switch_datapath(ndev, vf_is_up);
        netdev_info(ndev, "Data path switched %s VF: %s\n",
                    vf_is_up ? "to" : "from", vf_netdev->name);
 
-       return 0;
+       return NOTIFY_OK;
 }
 
-static int netvsc_pre_unregister_vf(struct net_device *vf_netdev,
-                                   struct net_device *ndev)
+static int netvsc_unregister_vf(struct net_device *vf_netdev)
 {
+       struct net_device *ndev;
        struct net_device_context *net_device_ctx;
 
-       net_device_ctx = netdev_priv(ndev);
-       cancel_delayed_work_sync(&net_device_ctx->vf_takeover);
-
-       return 0;
-}
-
-static int netvsc_unregister_vf(struct net_device *vf_netdev,
-                               struct net_device *ndev)
-{
-       struct net_device_context *net_device_ctx;
+       ndev = get_netvsc_byref(vf_netdev);
+       if (!ndev)
+               return NOTIFY_DONE;
 
        net_device_ctx = netdev_priv(ndev);
+       cancel_delayed_work_sync(&net_device_ctx->vf_takeover);
 
        netdev_info(ndev, "VF unregistering: %s\n", vf_netdev->name);
 
+       netdev_rx_handler_unregister(vf_netdev);
+       netdev_upper_dev_unlink(vf_netdev, ndev);
        RCU_INIT_POINTER(net_device_ctx->vf_netdev, NULL);
        dev_put(vf_netdev);
 
-       return 0;
+       return NOTIFY_OK;
 }
 
-static struct failover_ops netvsc_failover_ops = {
-       .slave_pre_register     = netvsc_pre_register_vf,
-       .slave_register         = netvsc_register_vf,
-       .slave_pre_unregister   = netvsc_pre_unregister_vf,
-       .slave_unregister       = netvsc_unregister_vf,
-       .slave_link_change      = netvsc_vf_changed,
-       .slave_handle_frame     = netvsc_vf_handle_frame,
-};
-
 static int netvsc_probe(struct hv_device *dev,
                        const struct hv_vmbus_device_id *dev_id)
 {
@@ -2024,23 +2104,19 @@ static int netvsc_probe(struct hv_device *dev,
        else
                net->max_mtu = ETH_DATA_LEN;
 
-       ret = register_netdev(net);
+       rtnl_lock();
+       ret = register_netdevice(net);
        if (ret != 0) {
                pr_err("Unable to register netdev.\n");
                goto register_failed;
        }
 
-       net_device_ctx->failover = failover_register(net, &netvsc_failover_ops);
-       if (IS_ERR(net_device_ctx->failover)) {
-               ret = PTR_ERR(net_device_ctx->failover);
-               goto err_failover;
-       }
-
-       return ret;
+       list_add(&net_device_ctx->list, &netvsc_dev_list);
+       rtnl_unlock();
+       return 0;
 
-err_failover:
-       unregister_netdev(net);
 register_failed:
+       rtnl_unlock();
        rndis_filter_device_remove(dev, nvdev);
 rndis_failed:
        free_percpu(net_device_ctx->vf_stats);
@@ -2080,14 +2156,13 @@ static int netvsc_remove(struct hv_device *dev)
        rtnl_lock();
        vf_netdev = rtnl_dereference(ndev_ctx->vf_netdev);
        if (vf_netdev)
-               failover_slave_unregister(vf_netdev);
+               netvsc_unregister_vf(vf_netdev);
 
        if (nvdev)
                rndis_filter_device_remove(dev, nvdev);
 
        unregister_netdevice(net);
-
-       failover_unregister(ndev_ctx->failover);
+       list_del(&ndev_ctx->list);
 
        rtnl_unlock();
        rcu_read_unlock();
@@ -2115,8 +2190,54 @@ static struct  hv_driver netvsc_drv = {
        .remove = netvsc_remove,
 };
 
+/*
+ * On Hyper-V, every VF interface is matched with a corresponding
+ * synthetic interface. The synthetic interface is presented first
+ * to the guest. When the corresponding VF instance is registered,
+ * we will take care of switching the data path.
+ */
+static int netvsc_netdev_event(struct notifier_block *this,
+                              unsigned long event, void *ptr)
+{
+       struct net_device *event_dev = netdev_notifier_info_to_dev(ptr);
+
+       /* Skip our own events */
+       if (event_dev->netdev_ops == &device_ops)
+               return NOTIFY_DONE;
+
+       /* Avoid non-Ethernet type devices */
+       if (event_dev->type != ARPHRD_ETHER)
+               return NOTIFY_DONE;
+
+       /* Avoid Vlan dev with same MAC registering as VF */
+       if (is_vlan_dev(event_dev))
+               return NOTIFY_DONE;
+
+       /* Avoid Bonding master dev with same MAC registering as VF */
+       if ((event_dev->priv_flags & IFF_BONDING) &&
+           (event_dev->flags & IFF_MASTER))
+               return NOTIFY_DONE;
+
+       switch (event) {
+       case NETDEV_REGISTER:
+               return netvsc_register_vf(event_dev);
+       case NETDEV_UNREGISTER:
+               return netvsc_unregister_vf(event_dev);
+       case NETDEV_UP:
+       case NETDEV_DOWN:
+               return netvsc_vf_changed(event_dev);
+       default:
+               return NOTIFY_DONE;
+       }
+}
+
+static struct notifier_block netvsc_netdev_notifier = {
+       .notifier_call = netvsc_netdev_event,
+};
+
 static void __exit netvsc_drv_exit(void)
 {
+       unregister_netdevice_notifier(&netvsc_netdev_notifier);
        vmbus_driver_unregister(&netvsc_drv);
 }
 
@@ -2135,6 +2256,7 @@ static int __init netvsc_drv_init(void)
        if (ret)
                return ret;
 
+       register_netdevice_notifier(&netvsc_netdev_notifier);
        return 0;
 }
 
index 4e4c8daf44c308285201ecc051bc4e535e03036e..33265747bf3994c668cfcb2a8f7f3d9f768d370a 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/mdio-bitbang.h>
 #include <linux/mdio-gpio.h>
-#include <linux/gpio.h>
 #include <linux/gpio/consumer.h>
-
-#include <linux/of_gpio.h>
 #include <linux/of_mdio.h>
 
 struct mdio_gpio_info {
index 9825bfd42abc7542df38a939315348a7d46f4ddf..18e819d964f1cdadf7616dd70321bce6c6bf43e3 100644 (file)
@@ -3572,11 +3572,14 @@ static int __init init_mac80211_hwsim(void)
        hwsim_wq = alloc_workqueue("hwsim_wq", 0, 0);
        if (!hwsim_wq)
                return -ENOMEM;
-       rhashtable_init(&hwsim_radios_rht, &hwsim_rht_params);
+
+       err = rhashtable_init(&hwsim_radios_rht, &hwsim_rht_params);
+       if (err)
+               goto out_free_wq;
 
        err = register_pernet_device(&hwsim_net_ops);
        if (err)
-               return err;
+               goto out_free_rht;
 
        err = platform_driver_register(&mac80211_hwsim_driver);
        if (err)
@@ -3701,6 +3704,10 @@ out_unregister_driver:
        platform_driver_unregister(&mac80211_hwsim_driver);
 out_unregister_pernet:
        unregister_pernet_device(&hwsim_net_ops);
+out_free_rht:
+       rhashtable_destroy(&hwsim_radios_rht);
+out_free_wq:
+       destroy_workqueue(hwsim_wq);
        return err;
 }
 module_init(init_mac80211_hwsim);
index 679da1abd73c31ebb9b6f0650ee64e53fbe65116..922ce0abf5cf105a5394285b07356ebcad055d78 100644 (file)
@@ -239,7 +239,7 @@ static void rx_refill_timeout(struct timer_list *t)
 static int netfront_tx_slot_available(struct netfront_queue *queue)
 {
        return (queue->tx.req_prod_pvt - queue->tx.rsp_cons) <
-               (NET_TX_RING_SIZE - MAX_SKB_FRAGS - 2);
+               (NET_TX_RING_SIZE - XEN_NETIF_NR_SLOTS_MIN - 1);
 }
 
 static void xennet_maybe_wake_tx(struct netfront_queue *queue)
@@ -790,7 +790,7 @@ static int xennet_get_responses(struct netfront_queue *queue,
        RING_IDX cons = queue->rx.rsp_cons;
        struct sk_buff *skb = xennet_get_rx_skb(queue, cons);
        grant_ref_t ref = xennet_get_rx_ref(queue, cons);
-       int max = MAX_SKB_FRAGS + (rx->status <= RX_COPY_THRESHOLD);
+       int max = XEN_NETIF_NR_SLOTS_MIN + (rx->status <= RX_COPY_THRESHOLD);
        int slots = 1;
        int err = 0;
        unsigned long ret;
index effb1309682eb2564d77a5550526510cb891b7bd..21710a7460c823bbc4f84134d7ecce70d3f993ba 100644 (file)
@@ -2208,7 +2208,7 @@ static int nvme_init_subsystem(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
                 * Verify that the subsystem actually supports multiple
                 * controllers, else bail out.
                 */
-               if (!ctrl->opts->discovery_nqn &&
+               if (!(ctrl->opts && ctrl->opts->discovery_nqn) &&
                    nvme_active_ctrls(found) && !(id->cmic & (1 << 1))) {
                        dev_err(ctrl->device,
                                "ignoring ctrl due to duplicate subnqn (%s).\n",
@@ -3197,40 +3197,28 @@ static void nvme_scan_ns_sequential(struct nvme_ctrl *ctrl, unsigned nn)
        nvme_remove_invalid_namespaces(ctrl, nn);
 }
 
-static bool nvme_scan_changed_ns_log(struct nvme_ctrl *ctrl)
+static void nvme_clear_changed_ns_log(struct nvme_ctrl *ctrl)
 {
        size_t log_size = NVME_MAX_CHANGED_NAMESPACES * sizeof(__le32);
        __le32 *log;
-       int error, i;
-       bool ret = false;
+       int error;
 
        log = kzalloc(log_size, GFP_KERNEL);
        if (!log)
-               return false;
+               return;
 
+       /*
+        * We need to read the log to clear the AEN, but we don't want to rely
+        * on it for the changed namespace information as userspace could have
+        * raced with us in reading the log page, which could cause us to miss
+        * updates.
+        */
        error = nvme_get_log(ctrl, NVME_LOG_CHANGED_NS, log, log_size);
-       if (error) {
+       if (error)
                dev_warn(ctrl->device,
                        "reading changed ns log failed: %d\n", error);
-               goto out_free_log;
-       }
-
-       if (log[0] == cpu_to_le32(0xffffffff))
-               goto out_free_log;
-
-       for (i = 0; i < NVME_MAX_CHANGED_NAMESPACES; i++) {
-               u32 nsid = le32_to_cpu(log[i]);
 
-               if (nsid == 0)
-                       break;
-               dev_info(ctrl->device, "rescanning namespace %d.\n", nsid);
-               nvme_validate_ns(ctrl, nsid);
-       }
-       ret = true;
-
-out_free_log:
        kfree(log);
-       return ret;
 }
 
 static void nvme_scan_work(struct work_struct *work)
@@ -3246,9 +3234,8 @@ static void nvme_scan_work(struct work_struct *work)
        WARN_ON_ONCE(!ctrl->tagset);
 
        if (test_and_clear_bit(NVME_AER_NOTICE_NS_CHANGED, &ctrl->events)) {
-               if (nvme_scan_changed_ns_log(ctrl))
-                       goto out_sort_namespaces;
                dev_info(ctrl->device, "rescanning namespaces.\n");
+               nvme_clear_changed_ns_log(ctrl);
        }
 
        if (nvme_identify_ctrl(ctrl, &id))
@@ -3263,7 +3250,6 @@ static void nvme_scan_work(struct work_struct *work)
        nvme_scan_ns_sequential(ctrl, nn);
 out_free_id:
        kfree(id);
-out_sort_namespaces:
        down_write(&ctrl->namespaces_rwsem);
        list_sort(NULL, &ctrl->namespaces, ns_cmp);
        up_write(&ctrl->namespaces_rwsem);
@@ -3641,16 +3627,6 @@ void nvme_start_queues(struct nvme_ctrl *ctrl)
 }
 EXPORT_SYMBOL_GPL(nvme_start_queues);
 
-int nvme_reinit_tagset(struct nvme_ctrl *ctrl, struct blk_mq_tag_set *set)
-{
-       if (!ctrl->ops->reinit_request)
-               return 0;
-
-       return blk_mq_tagset_iter(set, set->driver_data,
-                       ctrl->ops->reinit_request);
-}
-EXPORT_SYMBOL_GPL(nvme_reinit_tagset);
-
 int __init nvme_core_init(void)
 {
        int result = -ENOMEM;
index fa32c1216409a349ed502902317e443471bbd747..903eb4545e2699bc1b62365e5ca4490e824a8c5c 100644 (file)
@@ -536,67 +536,55 @@ static struct nvmf_transport_ops *nvmf_lookup_transport(
        return NULL;
 }
 
-blk_status_t nvmf_check_if_ready(struct nvme_ctrl *ctrl, struct request *rq,
-               bool queue_live, bool is_connected)
+/*
+ * For something we're not in a state to send to the device the default action
+ * is to busy it and retry it after the controller state is recovered.  However,
+ * anything marked for failfast or nvme multipath is immediately failed.
+ *
+ * Note: commands used to initialize the controller will be marked for failfast.
+ * Note: nvme cli/ioctl commands are marked for failfast.
+ */
+blk_status_t nvmf_fail_nonready_command(struct request *rq)
 {
-       struct nvme_command *cmd = nvme_req(rq)->cmd;
+       if (!blk_noretry_request(rq) && !(rq->cmd_flags & REQ_NVME_MPATH))
+               return BLK_STS_RESOURCE;
+       nvme_req(rq)->status = NVME_SC_ABORT_REQ;
+       return BLK_STS_IOERR;
+}
+EXPORT_SYMBOL_GPL(nvmf_fail_nonready_command);
 
-       if (likely(ctrl->state == NVME_CTRL_LIVE && is_connected))
-               return BLK_STS_OK;
+bool __nvmf_check_ready(struct nvme_ctrl *ctrl, struct request *rq,
+               bool queue_live)
+{
+       struct nvme_request *req = nvme_req(rq);
+
+       /*
+        * If we are in some state of setup or teardown only allow
+        * internally generated commands.
+        */
+       if (!blk_rq_is_passthrough(rq) || (req->flags & NVME_REQ_USERCMD))
+               return false;
 
+       /*
+        * Only allow commands on a live queue, except for the connect command,
+        * which is require to set the queue live in the appropinquate states.
+        */
        switch (ctrl->state) {
        case NVME_CTRL_NEW:
        case NVME_CTRL_CONNECTING:
-       case NVME_CTRL_DELETING:
-               /*
-                * This is the case of starting a new or deleting an association
-                * but connectivity was lost before it was fully created or torn
-                * down. We need to error the commands used to initialize the
-                * controller so the reconnect can go into a retry attempt.  The
-                * commands should all be marked REQ_FAILFAST_DRIVER, which will
-                * hit the reject path below. Anything else will be queued while
-                * the state settles.
-                */
-               if (!is_connected)
-                       break;
-
-               /*
-                * If queue is live, allow only commands that are internally
-                * generated pass through.  These are commands on the admin
-                * queue to initialize the controller. This will reject any
-                * ioctl admin cmds received while initializing.
-                */
-               if (queue_live && !(nvme_req(rq)->flags & NVME_REQ_USERCMD))
-                       return BLK_STS_OK;
-
-               /*
-                * If the queue is not live, allow only a connect command.  This
-                * will reject any ioctl admin cmd as well as initialization
-                * commands if the controller reverted the queue to non-live.
-                */
-               if (!queue_live && blk_rq_is_passthrough(rq) &&
-                    cmd->common.opcode == nvme_fabrics_command &&
-                    cmd->fabrics.fctype == nvme_fabrics_type_connect)
-                       return BLK_STS_OK;
+               if (req->cmd->common.opcode == nvme_fabrics_command &&
+                   req->cmd->fabrics.fctype == nvme_fabrics_type_connect)
+                       return true;
                break;
        default:
                break;
+       case NVME_CTRL_DEAD:
+               return false;
        }
 
-       /*
-        * Any other new io is something we're not in a state to send to the
-        * device.  Default action is to busy it and retry it after the
-        * controller state is recovered. However, anything marked for failfast
-        * or nvme multipath is immediately failed.  Note: commands used to
-        * initialize the controller will be marked for failfast.
-        * Note: nvme cli/ioctl commands are marked for failfast.
-        */
-       if (!blk_noretry_request(rq) && !(rq->cmd_flags & REQ_NVME_MPATH))
-               return BLK_STS_RESOURCE;
-       nvme_req(rq)->status = NVME_SC_ABORT_REQ;
-       return BLK_STS_IOERR;
+       return queue_live;
 }
-EXPORT_SYMBOL_GPL(nvmf_check_if_ready);
+EXPORT_SYMBOL_GPL(__nvmf_check_ready);
 
 static const match_table_t opt_tokens = {
        { NVMF_OPT_TRANSPORT,           "transport=%s"          },
index 7491a0bbf711d6eb3321a7bdc4d3ff22699d3416..e1818a27aa2d7bcf75ff0e2c4522a61e294d8d9b 100644 (file)
@@ -162,7 +162,17 @@ void nvmf_unregister_transport(struct nvmf_transport_ops *ops);
 void nvmf_free_options(struct nvmf_ctrl_options *opts);
 int nvmf_get_address(struct nvme_ctrl *ctrl, char *buf, int size);
 bool nvmf_should_reconnect(struct nvme_ctrl *ctrl);
-blk_status_t nvmf_check_if_ready(struct nvme_ctrl *ctrl,
-       struct request *rq, bool queue_live, bool is_connected);
+blk_status_t nvmf_fail_nonready_command(struct request *rq);
+bool __nvmf_check_ready(struct nvme_ctrl *ctrl, struct request *rq,
+               bool queue_live);
+
+static inline bool nvmf_check_ready(struct nvme_ctrl *ctrl, struct request *rq,
+               bool queue_live)
+{
+       if (likely(ctrl->state == NVME_CTRL_LIVE ||
+                  ctrl->state == NVME_CTRL_ADMIN_ONLY))
+               return true;
+       return __nvmf_check_ready(ctrl, rq, queue_live);
+}
 
 #endif /* _NVME_FABRICS_H */
index 0bad65803271ff68bc883e0dd16c78b8386fabf8..b528a2f5826cbfe19b22aadd7e09e1ceff512cb6 100644 (file)
@@ -142,6 +142,7 @@ struct nvme_fc_ctrl {
        struct nvme_fc_rport    *rport;
        u32                     cnum;
 
+       bool                    ioq_live;
        bool                    assoc_active;
        u64                     association_id;
 
@@ -1470,21 +1471,6 @@ nvme_fc_xmt_disconnect_assoc(struct nvme_fc_ctrl *ctrl)
 
 static void nvme_fc_error_recovery(struct nvme_fc_ctrl *ctrl, char *errmsg);
 
-static int
-nvme_fc_reinit_request(void *data, struct request *rq)
-{
-       struct nvme_fc_fcp_op *op = blk_mq_rq_to_pdu(rq);
-       struct nvme_fc_cmd_iu *cmdiu = &op->cmd_iu;
-
-       memset(cmdiu, 0, sizeof(*cmdiu));
-       cmdiu->scsi_id = NVME_CMD_SCSI_ID;
-       cmdiu->fc_id = NVME_CMD_FC_ID;
-       cmdiu->iu_len = cpu_to_be16(sizeof(*cmdiu) / sizeof(u32));
-       memset(&op->rsp_iu, 0, sizeof(op->rsp_iu));
-
-       return 0;
-}
-
 static void
 __nvme_fc_exit_request(struct nvme_fc_ctrl *ctrl,
                struct nvme_fc_fcp_op *op)
@@ -1893,6 +1879,7 @@ nvme_fc_free_queue(struct nvme_fc_queue *queue)
         */
 
        queue->connection_id = 0;
+       atomic_set(&queue->csn, 1);
 }
 
 static void
@@ -2279,14 +2266,13 @@ nvme_fc_queue_rq(struct blk_mq_hw_ctx *hctx,
        struct nvme_fc_cmd_iu *cmdiu = &op->cmd_iu;
        struct nvme_command *sqe = &cmdiu->sqe;
        enum nvmefc_fcp_datadir io_dir;
+       bool queue_ready = test_bit(NVME_FC_Q_LIVE, &queue->flags);
        u32 data_len;
        blk_status_t ret;
 
-       ret = nvmf_check_if_ready(&queue->ctrl->ctrl, rq,
-               test_bit(NVME_FC_Q_LIVE, &queue->flags),
-               ctrl->rport->remoteport.port_state == FC_OBJSTATE_ONLINE);
-       if (unlikely(ret))
-               return ret;
+       if (ctrl->rport->remoteport.port_state != FC_OBJSTATE_ONLINE ||
+           !nvmf_check_ready(&queue->ctrl->ctrl, rq, queue_ready))
+               return nvmf_fail_nonready_command(rq);
 
        ret = nvme_setup_cmd(ns, rq, sqe);
        if (ret)
@@ -2463,6 +2449,8 @@ nvme_fc_create_io_queues(struct nvme_fc_ctrl *ctrl)
        if (ret)
                goto out_delete_hw_queues;
 
+       ctrl->ioq_live = true;
+
        return 0;
 
 out_delete_hw_queues:
@@ -2480,7 +2468,7 @@ out_free_tag_set:
 }
 
 static int
-nvme_fc_reinit_io_queues(struct nvme_fc_ctrl *ctrl)
+nvme_fc_recreate_io_queues(struct nvme_fc_ctrl *ctrl)
 {
        struct nvmf_ctrl_options *opts = ctrl->ctrl.opts;
        unsigned int nr_io_queues;
@@ -2500,12 +2488,6 @@ nvme_fc_reinit_io_queues(struct nvme_fc_ctrl *ctrl)
        if (ctrl->ctrl.queue_count == 1)
                return 0;
 
-       nvme_fc_init_io_queues(ctrl);
-
-       ret = nvme_reinit_tagset(&ctrl->ctrl, ctrl->ctrl.tagset);
-       if (ret)
-               goto out_free_io_queues;
-
        ret = nvme_fc_create_hw_io_queues(ctrl, ctrl->ctrl.sqsize + 1);
        if (ret)
                goto out_free_io_queues;
@@ -2603,8 +2585,6 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl)
         * Create the admin queue
         */
 
-       nvme_fc_init_queue(ctrl, 0);
-
        ret = __nvme_fc_create_hw_queue(ctrl, &ctrl->queues[0], 0,
                                NVME_AQ_DEPTH);
        if (ret)
@@ -2615,8 +2595,7 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl)
        if (ret)
                goto out_delete_hw_queue;
 
-       if (ctrl->ctrl.state != NVME_CTRL_NEW)
-               blk_mq_unquiesce_queue(ctrl->ctrl.admin_q);
+       blk_mq_unquiesce_queue(ctrl->ctrl.admin_q);
 
        ret = nvmf_connect_admin_queue(&ctrl->ctrl);
        if (ret)
@@ -2689,10 +2668,10 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl)
         */
 
        if (ctrl->ctrl.queue_count > 1) {
-               if (ctrl->ctrl.state == NVME_CTRL_NEW)
+               if (!ctrl->ioq_live)
                        ret = nvme_fc_create_io_queues(ctrl);
                else
-                       ret = nvme_fc_reinit_io_queues(ctrl);
+                       ret = nvme_fc_recreate_io_queues(ctrl);
                if (ret)
                        goto out_term_aen_ops;
        }
@@ -2776,8 +2755,7 @@ nvme_fc_delete_association(struct nvme_fc_ctrl *ctrl)
         * use blk_mq_tagset_busy_itr() and the transport routine to
         * terminate the exchanges.
         */
-       if (ctrl->ctrl.state != NVME_CTRL_NEW)
-               blk_mq_quiesce_queue(ctrl->ctrl.admin_q);
+       blk_mq_quiesce_queue(ctrl->ctrl.admin_q);
        blk_mq_tagset_busy_iter(&ctrl->admin_tag_set,
                                nvme_fc_terminate_exchange, &ctrl->ctrl);
 
@@ -2917,7 +2895,6 @@ static const struct nvme_ctrl_ops nvme_fc_ctrl_ops = {
        .submit_async_event     = nvme_fc_submit_async_event,
        .delete_ctrl            = nvme_fc_delete_ctrl,
        .get_address            = nvmf_get_address,
-       .reinit_request         = nvme_fc_reinit_request,
 };
 
 static void
@@ -2934,7 +2911,7 @@ nvme_fc_connect_ctrl_work(struct work_struct *work)
                nvme_fc_reconnect_or_delete(ctrl, ret);
        else
                dev_info(ctrl->ctrl.device,
-                       "NVME-FC{%d}: controller reconnect complete\n",
+                       "NVME-FC{%d}: controller connect complete\n",
                        ctrl->cnum);
 }
 
@@ -2982,7 +2959,7 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts,
 {
        struct nvme_fc_ctrl *ctrl;
        unsigned long flags;
-       int ret, idx, retry;
+       int ret, idx;
 
        if (!(rport->remoteport.port_role &
            (FC_PORT_ROLE_NVME_DISCOVERY | FC_PORT_ROLE_NVME_TARGET))) {
@@ -3009,11 +2986,13 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts,
        }
 
        ctrl->ctrl.opts = opts;
+       ctrl->ctrl.nr_reconnects = 0;
        INIT_LIST_HEAD(&ctrl->ctrl_list);
        ctrl->lport = lport;
        ctrl->rport = rport;
        ctrl->dev = lport->dev;
        ctrl->cnum = idx;
+       ctrl->ioq_live = false;
        ctrl->assoc_active = false;
        init_waitqueue_head(&ctrl->ioabort_wait);
 
@@ -3032,6 +3011,7 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts,
 
        ctrl->ctrl.sqsize = opts->queue_size - 1;
        ctrl->ctrl.kato = opts->kato;
+       ctrl->ctrl.cntlid = 0xffff;
 
        ret = -ENOMEM;
        ctrl->queues = kcalloc(ctrl->ctrl.queue_count,
@@ -3039,6 +3019,8 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts,
        if (!ctrl->queues)
                goto out_free_ida;
 
+       nvme_fc_init_queue(ctrl, 0);
+
        memset(&ctrl->admin_tag_set, 0, sizeof(ctrl->admin_tag_set));
        ctrl->admin_tag_set.ops = &nvme_fc_admin_mq_ops;
        ctrl->admin_tag_set.queue_depth = NVME_AQ_MQ_TAG_DEPTH;
@@ -3081,62 +3063,24 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts,
        list_add_tail(&ctrl->ctrl_list, &rport->ctrl_list);
        spin_unlock_irqrestore(&rport->lock, flags);
 
-       /*
-        * It's possible that transactions used to create the association
-        * may fail. Examples: CreateAssociation LS or CreateIOConnection
-        * LS gets dropped/corrupted/fails; or a frame gets dropped or a
-        * command times out for one of the actions to init the controller
-        * (Connect, Get/Set_Property, Set_Features, etc). Many of these
-        * transport errors (frame drop, LS failure) inherently must kill
-        * the association. The transport is coded so that any command used
-        * to create the association (prior to a LIVE state transition
-        * while NEW or CONNECTING) will fail if it completes in error or
-        * times out.
-        *
-        * As such: as the connect request was mostly likely due to a
-        * udev event that discovered the remote port, meaning there is
-        * not an admin or script there to restart if the connect
-        * request fails, retry the initial connection creation up to
-        * three times before giving up and declaring failure.
-        */
-       for (retry = 0; retry < 3; retry++) {
-               ret = nvme_fc_create_association(ctrl);
-               if (!ret)
-                       break;
-       }
-
-       if (ret) {
-               nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_DELETING);
-               cancel_work_sync(&ctrl->ctrl.reset_work);
-               cancel_delayed_work_sync(&ctrl->connect_work);
-
-               /* couldn't schedule retry - fail out */
+       if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_RESETTING) ||
+           !nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_CONNECTING)) {
                dev_err(ctrl->ctrl.device,
-                       "NVME-FC{%d}: Connect retry failed\n", ctrl->cnum);
-
-               ctrl->ctrl.opts = NULL;
+                       "NVME-FC{%d}: failed to init ctrl state\n", ctrl->cnum);
+               goto fail_ctrl;
+       }
 
-               /* initiate nvme ctrl ref counting teardown */
-               nvme_uninit_ctrl(&ctrl->ctrl);
+       nvme_get_ctrl(&ctrl->ctrl);
 
-               /* Remove core ctrl ref. */
+       if (!queue_delayed_work(nvme_wq, &ctrl->connect_work, 0)) {
                nvme_put_ctrl(&ctrl->ctrl);
-
-               /* as we're past the point where we transition to the ref
-                * counting teardown path, if we return a bad pointer here,
-                * the calling routine, thinking it's prior to the
-                * transition, will do an rport put. Since the teardown
-                * path also does a rport put, we do an extra get here to
-                * so proper order/teardown happens.
-                */
-               nvme_fc_rport_get(rport);
-
-               if (ret > 0)
-                       ret = -EIO;
-               return ERR_PTR(ret);
+               dev_err(ctrl->ctrl.device,
+                       "NVME-FC{%d}: failed to schedule initial connect\n",
+                       ctrl->cnum);
+               goto fail_ctrl;
        }
 
-       nvme_get_ctrl(&ctrl->ctrl);
+       flush_delayed_work(&ctrl->connect_work);
 
        dev_info(ctrl->ctrl.device,
                "NVME-FC{%d}: new ctrl: NQN \"%s\"\n",
@@ -3144,6 +3088,30 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts,
 
        return &ctrl->ctrl;
 
+fail_ctrl:
+       nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_DELETING);
+       cancel_work_sync(&ctrl->ctrl.reset_work);
+       cancel_delayed_work_sync(&ctrl->connect_work);
+
+       ctrl->ctrl.opts = NULL;
+
+       /* initiate nvme ctrl ref counting teardown */
+       nvme_uninit_ctrl(&ctrl->ctrl);
+
+       /* Remove core ctrl ref. */
+       nvme_put_ctrl(&ctrl->ctrl);
+
+       /* as we're past the point where we transition to the ref
+        * counting teardown path, if we return a bad pointer here,
+        * the calling routine, thinking it's prior to the
+        * transition, will do an rport put. Since the teardown
+        * path also does a rport put, we do an extra get here to
+        * so proper order/teardown happens.
+        */
+       nvme_fc_rport_get(rport);
+
+       return ERR_PTR(-EIO);
+
 out_cleanup_admin_q:
        blk_cleanup_queue(ctrl->ctrl.admin_q);
 out_free_admin_tag_set:
index d7b664ae5923e1217a493d68f1dac96c8a3cce4c..1ffd3e8b13a18dccf887beac8d1d053e64ce9c9b 100644 (file)
@@ -12,6 +12,7 @@
  */
 
 #include <linux/moduleparam.h>
+#include <trace/events/block.h>
 #include "nvme.h"
 
 static bool multipath = true;
@@ -111,6 +112,9 @@ static blk_qc_t nvme_ns_head_make_request(struct request_queue *q,
        if (likely(ns)) {
                bio->bi_disk = ns->disk;
                bio->bi_opf |= REQ_NVME_MPATH;
+               trace_block_bio_remap(bio->bi_disk->queue, bio,
+                                     disk_devt(ns->head->disk),
+                                     bio->bi_iter.bi_sector);
                ret = direct_make_request(bio);
        } else if (!list_empty_careful(&head->list)) {
                dev_warn_ratelimited(dev, "no path available - requeuing I/O\n");
index 34df07d44f8071e51f0c27bde7ade5c15bf2c00a..231807cbc849869afcbc16fce2e3389539ce2684 100644 (file)
@@ -321,7 +321,6 @@ struct nvme_ctrl_ops {
        void (*submit_async_event)(struct nvme_ctrl *ctrl);
        void (*delete_ctrl)(struct nvme_ctrl *ctrl);
        int (*get_address)(struct nvme_ctrl *ctrl, char *buf, int size);
-       int (*reinit_request)(void *data, struct request *rq);
        void (*stop_ctrl)(struct nvme_ctrl *ctrl);
 };
 
@@ -416,7 +415,6 @@ void nvme_unfreeze(struct nvme_ctrl *ctrl);
 void nvme_wait_freeze(struct nvme_ctrl *ctrl);
 void nvme_wait_freeze_timeout(struct nvme_ctrl *ctrl, long timeout);
 void nvme_start_freeze(struct nvme_ctrl *ctrl);
-int nvme_reinit_tagset(struct nvme_ctrl *ctrl, struct blk_mq_tag_set *set);
 
 #define NVME_QID_ANY -1
 struct request *nvme_alloc_request(struct request_queue *q,
index 2aba03876d846a4bc47a3216dab864ec5c0df2d0..c9424da0d23e3cbbdd0e2b5209d9eddca9f1591f 100644 (file)
@@ -1189,21 +1189,38 @@ static int nvme_rdma_map_data(struct nvme_rdma_queue *queue,
        count = ib_dma_map_sg(ibdev, req->sg_table.sgl, req->nents,
                    rq_data_dir(rq) == WRITE ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
        if (unlikely(count <= 0)) {
-               sg_free_table_chained(&req->sg_table, true);
-               return -EIO;
+               ret = -EIO;
+               goto out_free_table;
        }
 
        if (count == 1) {
                if (rq_data_dir(rq) == WRITE && nvme_rdma_queue_idx(queue) &&
                    blk_rq_payload_bytes(rq) <=
-                               nvme_rdma_inline_data_size(queue))
-                       return nvme_rdma_map_sg_inline(queue, req, c);
+                               nvme_rdma_inline_data_size(queue)) {
+                       ret = nvme_rdma_map_sg_inline(queue, req, c);
+                       goto out;
+               }
 
-               if (dev->pd->flags & IB_PD_UNSAFE_GLOBAL_RKEY)
-                       return nvme_rdma_map_sg_single(queue, req, c);
+               if (dev->pd->flags & IB_PD_UNSAFE_GLOBAL_RKEY) {
+                       ret = nvme_rdma_map_sg_single(queue, req, c);
+                       goto out;
+               }
        }
 
-       return nvme_rdma_map_sg_fr(queue, req, c, count);
+       ret = nvme_rdma_map_sg_fr(queue, req, c, count);
+out:
+       if (unlikely(ret))
+               goto out_unmap_sg;
+
+       return 0;
+
+out_unmap_sg:
+       ib_dma_unmap_sg(ibdev, req->sg_table.sgl,
+                       req->nents, rq_data_dir(rq) ==
+                       WRITE ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+out_free_table:
+       sg_free_table_chained(&req->sg_table, true);
+       return ret;
 }
 
 static void nvme_rdma_send_done(struct ib_cq *cq, struct ib_wc *wc)
@@ -1613,15 +1630,14 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
        struct nvme_rdma_qe *sqe = &req->sqe;
        struct nvme_command *c = sqe->data;
        struct ib_device *dev;
+       bool queue_ready = test_bit(NVME_RDMA_Q_LIVE, &queue->flags);
        blk_status_t ret;
        int err;
 
        WARN_ON_ONCE(rq->tag < 0);
 
-       ret = nvmf_check_if_ready(&queue->ctrl->ctrl, rq,
-               test_bit(NVME_RDMA_Q_LIVE, &queue->flags), true);
-       if (unlikely(ret))
-               return ret;
+       if (!nvmf_check_ready(&queue->ctrl->ctrl, rq, queue_ready))
+               return nvmf_fail_nonready_command(rq);
 
        dev = queue->device->dev;
        ib_dma_sync_single_for_cpu(dev, sqe->dma,
index 9625328427690345b86f73c4a80e0c1035635e4b..38803576d5e122396ae25f1a675d48fd268f67ac 100644 (file)
@@ -119,9 +119,11 @@ static void nvmet_execute_get_log_page_smart(struct nvmet_req *req)
        else
                status = nvmet_get_smart_log_nsid(req, log);
        if (status)
-               goto out;
+               goto out_free_log;
 
        status = nvmet_copy_to_sgl(req, 0, log, sizeof(*log));
+out_free_log:
+       kfree(log);
 out:
        nvmet_req_complete(req, status);
 }
index 1304ec3a7edeaadd2daf26ff74f55cb75e784696..d8d91f04bd7eedae3e183c3a89dc3d42bd33a3ff 100644 (file)
@@ -158,12 +158,11 @@ static blk_status_t nvme_loop_queue_rq(struct blk_mq_hw_ctx *hctx,
        struct nvme_loop_queue *queue = hctx->driver_data;
        struct request *req = bd->rq;
        struct nvme_loop_iod *iod = blk_mq_rq_to_pdu(req);
+       bool queue_ready = test_bit(NVME_LOOP_Q_LIVE, &queue->flags);
        blk_status_t ret;
 
-       ret = nvmf_check_if_ready(&queue->ctrl->ctrl, req,
-               test_bit(NVME_LOOP_Q_LIVE, &queue->flags), true);
-       if (unlikely(ret))
-               return ret;
+       if (!nvmf_check_ready(&queue->ctrl->ctrl, req, queue_ready))
+               return nvmf_fail_nonready_command(req);
 
        ret = nvme_setup_cmd(ns, req, &iod->cmd);
        if (ret)
index 44333bd8f90886260e2219acad391dadaa9fd095..a97f4eada60b317e38a8cd1e0c780851a825986e 100644 (file)
@@ -20,7 +20,7 @@ menuconfig PARPORT
          drive, PLIP link (Parallel Line Internet Protocol is mainly used to
          create a mini network by connecting the parallel ports of two local
          machines) etc., then you need to say Y here; please read
-         <file:Documentation/parport.txt> and
+         <file:Documentation/admin-guide/parport.rst> and
          <file:drivers/parport/BUGS-parport>.
 
          For extensive information about drivers for many devices attaching
@@ -33,7 +33,7 @@ menuconfig PARPORT
          the module will be called parport.
          If you have more than one parallel port and want to specify which
          port and IRQ to be used by this driver at module load time, take a
-         look at <file:Documentation/parport.txt>.
+         look at <file:Documentation/admin-guide/parport.rst>.
 
          If unsure, say Y.
 
@@ -71,7 +71,7 @@ config PARPORT_PC_FIFO
          As well as actually having a FIFO, or DMA capability, the kernel
          will need to know which IRQ the parallel port has.  By default,
          parallel port interrupts will not be used, and so neither will the
-         FIFO.  See <file:Documentation/parport.txt> to find out how to
+         FIFO.  See <file:Documentation/admin-guide/parport.rst> to find out how to
          specify which IRQ/DMA to use.
 
 config PARPORT_PC_SUPERIO
index 36a41ff506f0368be1a33710b6dcef098b16d7f0..ac97aa020db326dfc32ce821943ff37e2d77749c 100644 (file)
 #define MLXREG_HOTPLUG_RST_CNTR                3
 
 #define MLXREG_HOTPLUG_ATTRS_MAX       24
+#define MLXREG_HOTPLUG_NOT_ASSERT      3
 
 /**
  * struct mlxreg_hotplug_priv_data - platform private data:
  * @irq: platform device interrupt number;
+ * @dev: basic device;
  * @pdev: platform device;
  * @plat: platform data;
- * @dwork: delayed work template;
+ * @regmap: register map handle;
+ * @dwork_irq: delayed work template;
  * @lock: spin lock;
  * @hwmon: hwmon device;
  * @mlxreg_hotplug_attr: sysfs attributes array;
@@ -71,6 +74,8 @@
  * @cell: location of top aggregation interrupt register;
  * @mask: top aggregation interrupt common mask;
  * @aggr_cache: last value of aggregation register status;
+ * @after_probe: flag indication probing completion;
+ * @not_asserted: number of entries in workqueue with no signal assertion;
  */
 struct mlxreg_hotplug_priv_data {
        int irq;
@@ -79,7 +84,6 @@ struct mlxreg_hotplug_priv_data {
        struct mlxreg_hotplug_platform_data *plat;
        struct regmap *regmap;
        struct delayed_work dwork_irq;
-       struct delayed_work dwork;
        spinlock_t lock; /* sync with interrupt */
        struct device *hwmon;
        struct attribute *mlxreg_hotplug_attr[MLXREG_HOTPLUG_ATTRS_MAX + 1];
@@ -91,6 +95,7 @@ struct mlxreg_hotplug_priv_data {
        u32 mask;
        u32 aggr_cache;
        bool after_probe;
+       u8 not_asserted;
 };
 
 static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv,
@@ -409,6 +414,18 @@ static void mlxreg_hotplug_work_handler(struct work_struct *work)
        aggr_asserted = priv->aggr_cache ^ regval;
        priv->aggr_cache = regval;
 
+       /*
+        * Handler is invoked, but no assertion is detected at top aggregation
+        * status level. Set aggr_asserted to mask value to allow handler extra
+        * run over all relevant signals to recover any missed signal.
+        */
+       if (priv->not_asserted == MLXREG_HOTPLUG_NOT_ASSERT) {
+               priv->not_asserted = 0;
+               aggr_asserted = pdata->mask;
+       }
+       if (!aggr_asserted)
+               goto unmask_event;
+
        /* Handle topology and health configuration changes. */
        for (i = 0; i < pdata->counter; i++, item++) {
                if (aggr_asserted & item->aggr_mask) {
@@ -419,27 +436,26 @@ static void mlxreg_hotplug_work_handler(struct work_struct *work)
                }
        }
 
-       if (aggr_asserted) {
-               spin_lock_irqsave(&priv->lock, flags);
+       spin_lock_irqsave(&priv->lock, flags);
 
-               /*
-                * It is possible, that some signals have been inserted, while
-                * interrupt has been masked by mlxreg_hotplug_work_handler.
-                * In this case such signals will be missed. In order to handle
-                * these signals delayed work is canceled and work task
-                * re-scheduled for immediate execution. It allows to handle
-                * missed signals, if any. In other case work handler just
-                * validates that no new signals have been received during
-                * masking.
-                */
-               cancel_delayed_work(&priv->dwork_irq);
-               schedule_delayed_work(&priv->dwork_irq, 0);
+       /*
+        * It is possible, that some signals have been inserted, while
+        * interrupt has been masked by mlxreg_hotplug_work_handler. In this
+        * case such signals will be missed. In order to handle these signals
+        * delayed work is canceled and work task re-scheduled for immediate
+        * execution. It allows to handle missed signals, if any. In other case
+        * work handler just validates that no new signals have been received
+        * during masking.
+        */
+       cancel_delayed_work(&priv->dwork_irq);
+       schedule_delayed_work(&priv->dwork_irq, 0);
 
-               spin_unlock_irqrestore(&priv->lock, flags);
+       spin_unlock_irqrestore(&priv->lock, flags);
 
-               return;
-       }
+       return;
 
+unmask_event:
+       priv->not_asserted++;
        /* Unmask aggregation event (no need acknowledge). */
        ret = regmap_write(priv->regmap, pdata->cell +
                           MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask);
index f27cb186437dcc7214ca6985e5c0a3c13bc70592..ac4d4883041537c3f4c6124acd6b52f141b6c89a 100644 (file)
@@ -1052,7 +1052,7 @@ config SAMSUNG_LAPTOP
          function keys, wireless LED, LCD backlight level.
 
          It may also provide some sysfs files described in
-         <file:Documentation/ABI/testing/sysfs-platform-samsung-laptop>
+         <file:Documentation/ABI/testing/sysfs-driver-samsung-laptop>
 
          To compile this driver as a module, choose M here: the module
          will be called samsung-laptop.
index 1be71f956d5c2872a1c31d77482bf65ddcb733a1..8952173dd380b6e650c6d54dd6498660286f0a27 100644 (file)
@@ -129,6 +129,7 @@ static const struct key_entry acer_wmi_keymap[] __initconst = {
        {KE_IGNORE, 0x83, {KEY_TOUCHPAD_TOGGLE} },
        {KE_KEY, 0x85, {KEY_TOUCHPAD_TOGGLE} },
        {KE_KEY, 0x86, {KEY_WLAN} },
+       {KE_KEY, 0x87, {KEY_POWER} },
        {KE_END, 0}
 };
 
index 7c4eb86c851ed9568cb882d32a9a5fdd3a0d13a0..fd2ffebc868fc7ed6ae2c55a899debbf1c5041bd 100644 (file)
@@ -495,7 +495,7 @@ static int gmux_set_power_state(enum vga_switcheroo_client_id id,
        return gmux_set_discrete_state(apple_gmux_data, state);
 }
 
-static int gmux_get_client_id(struct pci_dev *pdev)
+static enum vga_switcheroo_client_id gmux_get_client_id(struct pci_dev *pdev)
 {
        /*
         * Early Macbook Pros with switchable graphics use nvidia
index c4768be24ba9c402b8d4e0163008e11bc64d4ac1..700c48ddfa7c099b79c8d040954e8b2a35e5164c 100644 (file)
@@ -1593,8 +1593,7 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
                                    int idx)
 {
        struct device *dev = container_of(kobj, struct device, kobj);
-       struct platform_device *pdev = to_platform_device(dev);
-       struct asus_laptop *asus = platform_get_drvdata(pdev);
+       struct asus_laptop *asus = dev_get_drvdata(dev);
        acpi_handle handle = asus->handle;
        bool supported;
 
index f086469ea740987dec7c9996b982968491fa3140..6afd011de9e514ef05e13c6a5912ff2e78c2be00 100644 (file)
@@ -72,7 +72,7 @@ static u64 asus_wireless_method(acpi_handle handle, const char *method,
                acpi_handle_err(handle,
                                "Failed to eval method %s, param %#x (%d)\n",
                                method, param, s);
-       acpi_handle_debug(handle, "%s returned %#x\n", method, (uint) ret);
+       acpi_handle_debug(handle, "%s returned %#llx\n", method, ret);
        return ret;
 }
 
index ffffb9909ae1527a06ef7d68fc42a6c55b77b7ed..3d523ca6469462f4dba34935904c2ea66326a630 100644 (file)
@@ -1875,8 +1875,7 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
                                    struct attribute *attr, int idx)
 {
        struct device *dev = container_of(kobj, struct device, kobj);
-       struct platform_device *pdev = to_platform_device(dev);
-       struct asus_wmi *asus = platform_get_drvdata(pdev);
+       struct asus_wmi *asus = dev_get_drvdata(dev);
        bool ok = true;
        int devid = -1;
 
index c52c6723374b50b26041d7681c3d9ae3564d50ce..f1fa8612db406168f53db3d71a025255c0622af0 100644 (file)
@@ -38,6 +38,7 @@
 struct quirk_entry {
        bool touchpad_led;
        bool kbd_led_levels_off_1;
+       bool kbd_missing_ac_tag;
 
        bool needs_kbd_timeouts;
        /*
@@ -68,6 +69,10 @@ static struct quirk_entry quirk_dell_xps13_9333 = {
        .kbd_timeouts = { 0, 5, 15, 60, 5 * 60, 15 * 60, -1 },
 };
 
+static struct quirk_entry quirk_dell_xps13_9370 = {
+       .kbd_missing_ac_tag = true,
+};
+
 static struct quirk_entry quirk_dell_latitude_e6410 = {
        .kbd_led_levels_off_1 = true,
 };
@@ -291,6 +296,15 @@ static const struct dmi_system_id dell_quirks[] __initconst = {
                },
                .driver_data = &quirk_dell_xps13_9333,
        },
+       {
+               .callback = dmi_matched,
+               .ident = "Dell XPS 13 9370",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "XPS 13 9370"),
+               },
+               .driver_data = &quirk_dell_xps13_9370,
+       },
        {
                .callback = dmi_matched,
                .ident = "Dell Latitude E6410",
@@ -1401,7 +1415,8 @@ static inline int kbd_init_info(void)
         *       timeout value which is shared for both battery and AC power
         *       settings. So do not try to set AC values on old models.
         */
-       if (dell_smbios_find_token(KBD_LED_AC_TOKEN))
+       if ((quirks && quirks->kbd_missing_ac_tag) ||
+           dell_smbios_find_token(KBD_LED_AC_TOKEN))
                kbd_timeout_ac_supported = true;
 
        kbd_get_state(&state);
index 33fb2a20458a58fba2bee9ce79ad7571c184c7f3..9dc282ed5a9e1db7d926348ea30bd7905893a27c 100644 (file)
@@ -555,11 +555,10 @@ static void free_group(struct platform_device *pdev)
 
 static int __init dell_smbios_init(void)
 {
-       const struct dmi_device *valid;
        int ret, wmi, smm;
 
-       valid = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "Dell System", NULL);
-       if (!valid) {
+       if (!dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "Dell System", NULL) &&
+           !dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "www.dell.com", NULL)) {
                pr_err("Unable to run on non-Dell system\n");
                return -ENODEV;
        }
index 8d102195a3927fa4bf76f4230d069d6038414923..16c7f3d9a3352ec48d72f877e2e7486ea78250c7 100644 (file)
@@ -233,7 +233,7 @@ static const u16 bios_to_linux_keycode[256] = {
        [18]    = KEY_PROG1,
        [19]    = KEY_BRIGHTNESSDOWN,
        [20]    = KEY_BRIGHTNESSUP,
-       [21]    = KEY_UNKNOWN,
+       [21]    = KEY_BRIGHTNESS_AUTO,
        [22]    = KEY_KBDILLUMTOGGLE,
        [23]    = KEY_UNKNOWN,
        [24]    = KEY_SWITCHVIDEOMODE,
@@ -261,6 +261,12 @@ static const u16 bios_to_linux_keycode[256] = {
  * override them.
  */
 static const struct key_entry dell_wmi_keymap_type_0010[] = {
+       /* Fn-lock switched to function keys */
+       { KE_IGNORE, 0x0, { KEY_RESERVED } },
+
+       /* Fn-lock switched to multimedia keys */
+       { KE_IGNORE, 0x1, { KEY_RESERVED } },
+
        /* Mic mute */
        { KE_KEY, 0x150, { KEY_MICMUTE } },
 
@@ -296,6 +302,14 @@ static const struct key_entry dell_wmi_keymap_type_0010[] = {
        { KE_KEY,    0x851, { KEY_PROG2 } },
        { KE_KEY,    0x852, { KEY_PROG3 } },
 
+       /*
+        * Radio disable (notify only -- there is no model for which the
+        * WMI event is supposed to trigger an action).
+        */
+       { KE_IGNORE, 0xe008, { KEY_RFKILL } },
+
+       /* Fn-lock */
+       { KE_IGNORE, 0xe035, { KEY_RESERVED } },
 };
 
 /*
index cd95b6f3a06405835edadfc6ea92a5b46bab591f..6afeaece2f50ca4deec027577631a787c274b7fb 100644 (file)
@@ -91,6 +91,9 @@
 #define FLAG_RFKILL                    BIT(5)
 #define FLAG_LID                       BIT(8)
 #define FLAG_DOCK                      BIT(9)
+#define FLAG_TOUCHPAD_TOGGLE           BIT(26)
+#define FLAG_MICMUTE                   BIT(29)
+#define FLAG_SOFTKEYS                  (FLAG_RFKILL | FLAG_TOUCHPAD_TOGGLE | FLAG_MICMUTE)
 
 /* FUNC interface - LED control */
 #define FUNC_LED_OFF                   BIT(0)
@@ -456,14 +459,15 @@ static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event)
 /* ACPI device for hotkey handling */
 
 static const struct key_entry keymap_default[] = {
-       { KE_KEY, KEY1_CODE, { KEY_PROG1 } },
-       { KE_KEY, KEY2_CODE, { KEY_PROG2 } },
-       { KE_KEY, KEY3_CODE, { KEY_PROG3 } },
-       { KE_KEY, KEY4_CODE, { KEY_PROG4 } },
-       { KE_KEY, KEY5_CODE, { KEY_RFKILL } },
-       { KE_KEY, BIT(5),    { KEY_RFKILL } },
-       { KE_KEY, BIT(26),   { KEY_TOUCHPAD_TOGGLE } },
-       { KE_KEY, BIT(29),   { KEY_MICMUTE } },
+       { KE_KEY, KEY1_CODE,            { KEY_PROG1 } },
+       { KE_KEY, KEY2_CODE,            { KEY_PROG2 } },
+       { KE_KEY, KEY3_CODE,            { KEY_PROG3 } },
+       { KE_KEY, KEY4_CODE,            { KEY_PROG4 } },
+       { KE_KEY, KEY5_CODE,            { KEY_RFKILL } },
+       /* Soft keys read from status flags */
+       { KE_KEY, FLAG_RFKILL,          { KEY_RFKILL } },
+       { KE_KEY, FLAG_TOUCHPAD_TOGGLE, { KEY_TOUCHPAD_TOGGLE } },
+       { KE_KEY, FLAG_MICMUTE,         { KEY_MICMUTE } },
        { KE_END, 0 }
 };
 
@@ -903,7 +907,8 @@ static void acpi_fujitsu_laptop_release(struct acpi_device *device)
 static void acpi_fujitsu_laptop_notify(struct acpi_device *device, u32 event)
 {
        struct fujitsu_laptop *priv = acpi_driver_data(device);
-       int scancode, i = 0, ret;
+       unsigned long flags;
+       int scancode, i = 0;
        unsigned int irb;
 
        if (event != ACPI_FUJITSU_NOTIFY_CODE) {
@@ -930,21 +935,17 @@ static void acpi_fujitsu_laptop_notify(struct acpi_device *device, u32 event)
                                         "Unknown GIRB result [%x]\n", irb);
        }
 
-       /* On some models (first seen on the Skylake-based Lifebook
-        * E736/E746/E756), the touchpad toggle hotkey (Fn+F4) is
-        * handled in software; its state is queried using FUNC_FLAGS
+       /*
+        * First seen on the Skylake-based Lifebook E736/E746/E756), the
+        * touchpad toggle hotkey (Fn+F4) is handled in software. Other models
+        * have since added additional "soft keys". These are reported in the
+        * status flags queried using FUNC_FLAGS.
         */
-       if (priv->flags_supported & (BIT(5) | BIT(26) | BIT(29))) {
-               ret = call_fext_func(device, FUNC_FLAGS, 0x1, 0x0, 0x0);
-               if (ret & BIT(5))
-                       sparse_keymap_report_event(priv->input,
-                                                  BIT(5), 1, true);
-               if (ret & BIT(26))
-                       sparse_keymap_report_event(priv->input,
-                                                  BIT(26), 1, true);
-               if (ret & BIT(29))
-                       sparse_keymap_report_event(priv->input,
-                                                  BIT(29), 1, true);
+       if (priv->flags_supported & (FLAG_SOFTKEYS)) {
+               flags = call_fext_func(device, FUNC_FLAGS, 0x1, 0x0, 0x0);
+               flags &= (FLAG_SOFTKEYS);
+               for_each_set_bit(i, &flags, BITS_PER_LONG)
+                       sparse_keymap_report_event(priv->input, BIT(i), 1, true);
        }
 }
 
index 535199c9e6bc6fa182ea9612fcabf85a7ba02ba8..45b7cb01f4101ee8526ac5f4f7f86a626959f220 100644 (file)
@@ -43,6 +43,7 @@
 #define IDEAPAD_RFKILL_DEV_NUM (3)
 
 #define BM_CONSERVATION_BIT (5)
+#define HA_FNLOCK_BIT       (10)
 
 #define CFG_BT_BIT     (16)
 #define CFG_3G_BIT     (17)
@@ -59,6 +60,8 @@ static const char *const ideapad_wmi_fnesc_events[] = {
 enum {
        BMCMD_CONSERVATION_ON = 3,
        BMCMD_CONSERVATION_OFF = 5,
+       HACMD_FNLOCK_ON = 0xe,
+       HACMD_FNLOCK_OFF = 0xf,
 };
 
 enum {
@@ -139,11 +142,11 @@ static int method_gbmd(acpi_handle handle, unsigned long *ret)
        return result;
 }
 
-static int method_sbmc(acpi_handle handle, int cmd)
+static int method_int1(acpi_handle handle, char *method, int cmd)
 {
        acpi_status status;
 
-       status = acpi_execute_simple_method(handle, "SBMC", cmd);
+       status = acpi_execute_simple_method(handle, method, cmd);
        return ACPI_FAILURE(status) ? -1 : 0;
 }
 
@@ -487,7 +490,7 @@ static ssize_t conservation_mode_store(struct device *dev,
        if (ret)
                return ret;
 
-       ret = method_sbmc(priv->adev->handle, state ?
+       ret = method_int1(priv->adev->handle, "SBMC", state ?
                                              BMCMD_CONSERVATION_ON :
                                              BMCMD_CONSERVATION_OFF);
        if (ret < 0)
@@ -497,11 +500,51 @@ static ssize_t conservation_mode_store(struct device *dev,
 
 static DEVICE_ATTR_RW(conservation_mode);
 
+static ssize_t fn_lock_show(struct device *dev,
+                           struct device_attribute *attr,
+                           char *buf)
+{
+       struct ideapad_private *priv = dev_get_drvdata(dev);
+       unsigned long result;
+       int hals;
+       int fail = read_method_int(priv->adev->handle, "HALS", &hals);
+
+       if (fail)
+               return sprintf(buf, "-1\n");
+
+       result = hals;
+       return sprintf(buf, "%u\n", test_bit(HA_FNLOCK_BIT, &result));
+}
+
+static ssize_t fn_lock_store(struct device *dev,
+                            struct device_attribute *attr,
+                            const char *buf, size_t count)
+{
+       struct ideapad_private *priv = dev_get_drvdata(dev);
+       bool state;
+       int ret;
+
+       ret = kstrtobool(buf, &state);
+       if (ret)
+               return ret;
+
+       ret = method_int1(priv->adev->handle, "SALS", state ?
+                         HACMD_FNLOCK_ON :
+                         HACMD_FNLOCK_OFF);
+       if (ret < 0)
+               return -EIO;
+       return count;
+}
+
+static DEVICE_ATTR_RW(fn_lock);
+
+
 static struct attribute *ideapad_attributes[] = {
        &dev_attr_camera_power.attr,
        &dev_attr_fan_mode.attr,
        &dev_attr_touchpad.attr,
        &dev_attr_conservation_mode.attr,
+       &dev_attr_fn_lock.attr,
        NULL
 };
 
@@ -522,6 +565,9 @@ static umode_t ideapad_is_visible(struct kobject *kobj,
        } else if (attr == &dev_attr_conservation_mode.attr) {
                supported = acpi_has_method(priv->adev->handle, "GBMD") &&
                            acpi_has_method(priv->adev->handle, "SBMC");
+       } else if (attr == &dev_attr_fn_lock.attr) {
+               supported = acpi_has_method(priv->adev->handle, "HALS") &&
+                       acpi_has_method(priv->adev->handle, "SALS");
        } else
                supported = true;
 
@@ -1079,6 +1125,13 @@ static const struct dmi_system_id no_hw_rfkill_list[] = {
                        DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-17ISK"),
                },
        },
+       {
+               .ident = "Lenovo ideapad MIIX 720-12IKB",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "MIIX 720-12IKB"),
+               },
+       },
        {
                .ident = "Lenovo Legion Y520-15IKBN",
                .matches = {
@@ -1163,6 +1216,13 @@ static const struct dmi_system_id no_hw_rfkill_list[] = {
                        DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 920-13IKB"),
                },
        },
+       {
+               .ident = "Lenovo Zhaoyang E42-80",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "ZHAOYANG E42-80"),
+               },
+       },
        {}
 };
 
index 2c85f75e32b08b27af3c96fa413fc9ebbccc252c..75c8fef7a482c41717c69aa8ef98b21ef4dd1043 100644 (file)
@@ -584,11 +584,11 @@ int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data)
        if (cmd == IPC_I2C_READ) {
                writel(addr, scu->i2c_base + IPC_I2C_CNTRL_ADDR);
                /* Write not getting updated without delay */
-               mdelay(1);
+               usleep_range(1000, 2000);
                *data = readl(scu->i2c_base + I2C_DATA_ADDR);
        } else if (cmd == IPC_I2C_WRITE) {
                writel(*data, scu->i2c_base + I2C_DATA_ADDR);
-               mdelay(1);
+               usleep_range(1000, 2000);
                writel(addr, scu->i2c_base + IPC_I2C_CNTRL_ADDR);
        } else {
                dev_err(scu->dev,
index 7a0bd24c1ae2dcd5304150d52a54d124192e753a..a0fd9aa6d93258f7305dae2dd60506f9f1464689 100644 (file)
 /* LPC bus IO offsets */
 #define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR         0x2000
 #define MLXPLAT_CPLD_LPC_REG_BASE_ADRR         0x2500
+#define MLXPLAT_CPLD_LPC_REG_LED1_OFFSET       0x20
+#define MLXPLAT_CPLD_LPC_REG_LED2_OFFSET       0x21
+#define MLXPLAT_CPLD_LPC_REG_LED3_OFFSET       0x22
+#define MLXPLAT_CPLD_LPC_REG_LED4_OFFSET       0x23
+#define MLXPLAT_CPLD_LPC_REG_LED5_OFFSET       0x24
 #define MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET       0x3a
 #define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET  0x3b
 #define MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET     0x40
@@ -84,6 +89,8 @@
 #define MLXPLAT_CPLD_PWR_MASK          GENMASK(1, 0)
 #define MLXPLAT_CPLD_FAN_MASK          GENMASK(3, 0)
 #define MLXPLAT_CPLD_FAN_NG_MASK       GENMASK(5, 0)
+#define MLXPLAT_CPLD_LED_LO_NIBBLE_MASK        GENMASK(7, 4)
+#define MLXPLAT_CPLD_LED_HI_NIBBLE_MASK        GENMASK(3, 0)
 
 /* Default I2C parent bus number */
 #define MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR       1
  * @pdev_i2c - i2c controller platform device
  * @pdev_mux - array of mux platform devices
  * @pdev_hotplug - hotplug platform devices
+ * @pdev_led - led platform devices
  */
 struct mlxplat_priv {
        struct platform_device *pdev_i2c;
        struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS];
        struct platform_device *pdev_hotplug;
+       struct platform_device *pdev_led;
 };
 
 /* Regions for LPC I2C controller and LPC base register space */
@@ -592,9 +601,227 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_ng_data = {
        .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW,
 };
 
+/* Platform led default data */
+static struct mlxreg_core_data mlxplat_mlxcpld_default_led_data[] = {
+       {
+               .label = "status:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "status:red",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK
+       },
+       {
+               .label = "psu:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+       {
+               .label = "psu:red",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+       {
+               .label = "fan1:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "fan1:red",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "fan2:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+       {
+               .label = "fan2:red",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+       {
+               .label = "fan3:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "fan3:red",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "fan4:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+       {
+               .label = "fan4:red",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+};
+
+static struct mlxreg_core_platform_data mlxplat_default_led_data = {
+               .data = mlxplat_mlxcpld_default_led_data,
+               .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_led_data),
+};
+
+/* Platform led MSN21xx system family data */
+static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_led_data[] = {
+       {
+               .label = "status:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "status:red",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK
+       },
+       {
+               .label = "fan:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "fan:red",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "psu1:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "psu1:red",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "psu2:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+       {
+               .label = "psu2:red",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+       {
+               .label = "uid:blue",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED5_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+};
+
+static struct mlxreg_core_platform_data mlxplat_msn21xx_led_data = {
+               .data = mlxplat_mlxcpld_msn21xx_led_data,
+               .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_led_data),
+};
+
+/* Platform led for default data for 200GbE systems */
+static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_led_data[] = {
+       {
+               .label = "status:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "status:orange",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK
+       },
+       {
+               .label = "psu:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+       {
+               .label = "psu:orange",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+       {
+               .label = "fan1:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "fan1:orange",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "fan2:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+       {
+               .label = "fan2:orange",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+       {
+               .label = "fan3:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "fan3:orange",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "fan4:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+       {
+               .label = "fan4:orange",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+       {
+               .label = "fan5:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "fan5:orange",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "fan6:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+       {
+               .label = "fan6:orange",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+};
+
+static struct mlxreg_core_platform_data mlxplat_default_ng_led_data = {
+               .data = mlxplat_mlxcpld_default_ng_led_data,
+               .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_led_data),
+};
+
+
 static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
+       case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
@@ -611,6 +838,11 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
 static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
+       case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET:
@@ -632,6 +864,11 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
 static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
+       case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET:
@@ -692,6 +929,7 @@ static struct resource mlxplat_mlxcpld_resources[] = {
 
 static struct platform_device *mlxplat_dev;
 static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug;
+static struct mlxreg_core_platform_data *mlxplat_led;
 
 static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
 {
@@ -705,6 +943,7 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
        mlxplat_hotplug = &mlxplat_mlxcpld_default_data;
        mlxplat_hotplug->deferred_nr =
                mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
+       mlxplat_led = &mlxplat_default_led_data;
 
        return 1;
 };
@@ -721,6 +960,7 @@ static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
        mlxplat_hotplug = &mlxplat_mlxcpld_msn21xx_data;
        mlxplat_hotplug->deferred_nr =
                mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
+       mlxplat_led = &mlxplat_msn21xx_led_data;
 
        return 1;
 };
@@ -737,6 +977,7 @@ static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi)
        mlxplat_hotplug = &mlxplat_mlxcpld_msn274x_data;
        mlxplat_hotplug->deferred_nr =
                mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
+       mlxplat_led = &mlxplat_default_led_data;
 
        return 1;
 };
@@ -753,6 +994,7 @@ static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi)
        mlxplat_hotplug = &mlxplat_mlxcpld_msn201x_data;
        mlxplat_hotplug->deferred_nr =
                mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
+       mlxplat_led = &mlxplat_default_ng_led_data;
 
        return 1;
 };
@@ -769,6 +1011,7 @@ static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi)
        mlxplat_hotplug = &mlxplat_mlxcpld_default_ng_data;
        mlxplat_hotplug->deferred_nr =
                mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
+       mlxplat_led = &mlxplat_msn21xx_led_data;
 
        return 1;
 };
@@ -844,6 +1087,36 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "SN34"),
                },
        },
+       {
+               .callback = mlxplat_dmi_default_matched,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_NAME, "VMOD0001"),
+               },
+       },
+       {
+               .callback = mlxplat_dmi_msn21xx_matched,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_NAME, "VMOD0002"),
+               },
+       },
+       {
+               .callback = mlxplat_dmi_msn274x_matched,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_NAME, "VMOD0003"),
+               },
+       },
+       {
+               .callback = mlxplat_dmi_msn201x_matched,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_NAME, "VMOD0004"),
+               },
+       },
+       {
+               .callback = mlxplat_dmi_qmb7xx_matched,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_NAME, "VMOD0005"),
+               },
+       },
        { }
 };
 
@@ -960,14 +1233,27 @@ static int __init mlxplat_init(void)
                goto fail_platform_mux_register;
        }
 
+       /* Add LED driver. */
+       mlxplat_led->regmap = mlxplat_hotplug->regmap;
+       priv->pdev_led = platform_device_register_resndata(
+                               &mlxplat_dev->dev, "leds-mlxreg",
+                               PLATFORM_DEVID_NONE, NULL, 0,
+                               mlxplat_led, sizeof(*mlxplat_led));
+       if (IS_ERR(priv->pdev_led)) {
+               err = PTR_ERR(priv->pdev_led);
+               goto fail_platform_hotplug_register;
+       }
+
        /* Sync registers with hardware. */
        regcache_mark_dirty(mlxplat_hotplug->regmap);
        err = regcache_sync(mlxplat_hotplug->regmap);
        if (err)
-               goto fail_platform_hotplug_register;
+               goto fail_platform_led_register;
 
        return 0;
 
+fail_platform_led_register:
+       platform_device_unregister(priv->pdev_led);
 fail_platform_hotplug_register:
        platform_device_unregister(priv->pdev_hotplug);
 fail_platform_mux_register:
@@ -986,6 +1272,7 @@ static void __exit mlxplat_exit(void)
        struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
        int i;
 
+       platform_device_unregister(priv->pdev_led);
        platform_device_unregister(priv->pdev_hotplug);
 
        for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--)
index 03305e0b89ff808b5665d474b86baba62539c05e..7b160ee981152992655ff0b6f9357617f44fa18b 100644 (file)
@@ -1216,8 +1216,7 @@ static umode_t samsung_sysfs_is_visible(struct kobject *kobj,
                                        struct attribute *attr, int idx)
 {
        struct device *dev = container_of(kobj, struct device, kobj);
-       struct platform_device *pdev = to_platform_device(dev);
-       struct samsung_laptop *samsung = platform_get_drvdata(pdev);
+       struct samsung_laptop *samsung = dev_get_drvdata(dev);
        bool ok = true;
 
        if (attr == &dev_attr_performance_level.attr)
index 452aacabaa8efc71115bd4c107e485f490fe138d..853a7ce4601cd1f0d508197b27e79455e936e2f1 100644 (file)
@@ -53,6 +53,20 @@ static const struct silead_ts_dmi_data jumper_ezpad_mini3_data = {
        .properties     = jumper_ezpad_mini3_props,
 };
 
+static const struct property_entry jumper_ezpad_6_pro_props[] = {
+       PROPERTY_ENTRY_U32("touchscreen-size-x", 1980),
+       PROPERTY_ENTRY_U32("touchscreen-size-y", 1500),
+       PROPERTY_ENTRY_STRING("firmware-name", "gsl3692-jumper-ezpad-6-pro.fw"),
+       PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+       PROPERTY_ENTRY_BOOL("silead,home-button"),
+       { }
+};
+
+static const struct silead_ts_dmi_data jumper_ezpad_6_pro_data = {
+       .acpi_name      = "MSSL1680:00",
+       .properties     = jumper_ezpad_6_pro_props,
+};
+
 static const struct property_entry dexp_ursus_7w_props[] = {
        PROPERTY_ENTRY_U32("touchscreen-size-x", 890),
        PROPERTY_ENTRY_U32("touchscreen-size-y", 630),
@@ -127,7 +141,25 @@ static const struct silead_ts_dmi_data pipo_w2s_data = {
        .properties     = pipo_w2s_props,
 };
 
-static const struct property_entry pov_mobii_wintab_p800w_props[] = {
+static const struct property_entry pov_mobii_wintab_p800w_v20_props[] = {
+       PROPERTY_ENTRY_U32("touchscreen-min-x", 32),
+       PROPERTY_ENTRY_U32("touchscreen-min-y", 16),
+       PROPERTY_ENTRY_U32("touchscreen-size-x", 1692),
+       PROPERTY_ENTRY_U32("touchscreen-size-y", 1146),
+       PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
+       PROPERTY_ENTRY_STRING("firmware-name",
+                             "gsl3680-pov-mobii-wintab-p800w-v20.fw"),
+       PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+       PROPERTY_ENTRY_BOOL("silead,home-button"),
+       { }
+};
+
+static const struct silead_ts_dmi_data pov_mobii_wintab_p800w_v20_data = {
+       .acpi_name      = "MSSL1680:00",
+       .properties     = pov_mobii_wintab_p800w_v20_props,
+};
+
+static const struct property_entry pov_mobii_wintab_p800w_v21_props[] = {
        PROPERTY_ENTRY_U32("touchscreen-size-x", 1800),
        PROPERTY_ENTRY_U32("touchscreen-size-y", 1150),
        PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
@@ -137,9 +169,9 @@ static const struct property_entry pov_mobii_wintab_p800w_props[] = {
        { }
 };
 
-static const struct silead_ts_dmi_data pov_mobii_wintab_p800w_data = {
+static const struct silead_ts_dmi_data pov_mobii_wintab_p800w_v21_data = {
        .acpi_name      = "MSSL1680:00",
-       .properties     = pov_mobii_wintab_p800w_props,
+       .properties     = pov_mobii_wintab_p800w_v21_props,
 };
 
 static const struct property_entry itworks_tw891_props[] = {
@@ -277,6 +309,23 @@ static const struct silead_ts_dmi_data teclast_x3_plus_data = {
        .properties     = teclast_x3_plus_props,
 };
 
+static const struct property_entry onda_v891w_v1_props[] = {
+       PROPERTY_ENTRY_U32("touchscreen-min-x", 46),
+       PROPERTY_ENTRY_U32("touchscreen-min-y",  8),
+       PROPERTY_ENTRY_U32("touchscreen-size-x", 1676),
+       PROPERTY_ENTRY_U32("touchscreen-size-y", 1130),
+       PROPERTY_ENTRY_STRING("firmware-name",
+                             "gsl3680-onda-v891w-v1.fw"),
+       PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+       PROPERTY_ENTRY_BOOL("silead,home-button"),
+       { }
+};
+
+static const struct silead_ts_dmi_data onda_v891w_v1_data = {
+       .acpi_name      = "MSSL1680:00",
+       .properties     = onda_v891w_v1_props,
+};
+
 static const struct dmi_system_id silead_ts_dmi_table[] = {
        {
                /* CUBE iwork8 Air */
@@ -296,6 +345,17 @@ static const struct dmi_system_id silead_ts_dmi_table[] = {
                        DMI_MATCH(DMI_BIOS_VERSION, "jumperx.T87.KFBNEEA"),
                },
        },
+       {
+               /* Jumper EZpad 6 Pro */
+               .driver_data = (void *)&jumper_ezpad_6_pro_data,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Jumper"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "EZpad"),
+                       DMI_MATCH(DMI_BIOS_VERSION, "5.12"),
+                       /* Above matches are too generic, add bios-date match */
+                       DMI_MATCH(DMI_BIOS_DATE, "08/18/2017"),
+               },
+       },
        {
                /* DEXP Ursus 7W */
                .driver_data = (void *)&dexp_ursus_7w_data,
@@ -361,8 +421,19 @@ static const struct dmi_system_id silead_ts_dmi_table[] = {
                },
        },
        {
-               /* Point of View mobii wintab p800w */
-               .driver_data = (void *)&pov_mobii_wintab_p800w_data,
+               /* Point of View mobii wintab p800w (v2.0) */
+               .driver_data = (void *)&pov_mobii_wintab_p800w_v20_data,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
+                       DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"),
+                       DMI_MATCH(DMI_BIOS_VERSION, "3BAIR1014"),
+                       /* Above matches are too generic, add bios-date match */
+                       DMI_MATCH(DMI_BIOS_DATE, "10/24/2014"),
+               },
+       },
+       {
+               /* Point of View mobii wintab p800w (v2.1) */
+               .driver_data = (void *)&pov_mobii_wintab_p800w_v21_data,
                .matches = {
                        DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
                        DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"),
@@ -412,6 +483,15 @@ static const struct dmi_system_id silead_ts_dmi_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "S806"),
                },
        },
+       {
+               /* Chuwi Hi8 (H1D_S806_206) */
+               .driver_data = (void *)&chuwi_hi8_data,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "BayTrail"),
+                       DMI_MATCH(DMI_BIOS_VERSION, "H1D_S806_206"),
+               },
+       },
        {
                /* Chuwi Vi8 (CWI506) */
                .driver_data = (void *)&chuwi_vi8_data,
@@ -463,6 +543,17 @@ static const struct dmi_system_id silead_ts_dmi_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "Y8W81"),
                },
        },
+       {
+               /* ONDA V891w revision P891WBEBV1B00 aka v1 */
+               .driver_data = (void *)&onda_v891w_v1_data,
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "ONDA"),
+                       DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONDA Tablet"),
+                       DMI_EXACT_MATCH(DMI_BOARD_VERSION, "V001"),
+                       /* Exact match, different versions need different fw */
+                       DMI_EXACT_MATCH(DMI_BIOS_VERSION, "ONDA.W89EBBN08"),
+               },
+       },
        { },
 };
 
index ab2d28867c52178fae4778a615f78d0b798c624b..cae9b059569229d7c937e2f7101040969d9c7d5f 100644 (file)
@@ -212,7 +212,12 @@ enum tpacpi_hkey_event_t {
        TP_HKEY_EV_ALARM_BAT_XHOT       = 0x6012, /* battery critically hot */
        TP_HKEY_EV_ALARM_SENSOR_HOT     = 0x6021, /* sensor too hot */
        TP_HKEY_EV_ALARM_SENSOR_XHOT    = 0x6022, /* sensor critically hot */
-       TP_HKEY_EV_THM_TABLE_CHANGED    = 0x6030, /* thermal table changed */
+       TP_HKEY_EV_THM_TABLE_CHANGED    = 0x6030, /* windows; thermal table changed */
+       TP_HKEY_EV_THM_CSM_COMPLETED    = 0x6032, /* windows; thermal control set
+                                                  * command completed. Related to
+                                                  * AML DYTC */
+       TP_HKEY_EV_THM_TRANSFM_CHANGED  = 0x60F0, /* windows; thermal transformation
+                                                  * changed. Related to AML GMTS */
 
        /* AC-related events */
        TP_HKEY_EV_AC_CHANGED           = 0x6040, /* AC status changed */
@@ -4034,15 +4039,23 @@ static bool hotkey_notify_6xxx(const u32 hkey,
                                 bool *send_acpi_ev,
                                 bool *ignore_acpi_ev)
 {
-       bool known = true;
-
        /* 0x6000-0x6FFF: thermal alarms/notices and keyboard events */
        *send_acpi_ev = true;
        *ignore_acpi_ev = false;
 
        switch (hkey) {
        case TP_HKEY_EV_THM_TABLE_CHANGED:
-               pr_info("EC reports that Thermal Table has changed\n");
+               pr_debug("EC reports: Thermal Table has changed\n");
+               /* recommended action: do nothing, we don't have
+                * Lenovo ATM information */
+               return true;
+       case TP_HKEY_EV_THM_CSM_COMPLETED:
+               pr_debug("EC reports: Thermal Control Command set completed (DYTC)\n");
+               /* recommended action: do nothing, we don't have
+                * Lenovo ATM information */
+               return true;
+       case TP_HKEY_EV_THM_TRANSFM_CHANGED:
+               pr_debug("EC reports: Thermal Transformation changed (GMTS)\n");
                /* recommended action: do nothing, we don't have
                 * Lenovo ATM information */
                return true;
@@ -4083,7 +4096,7 @@ static bool hotkey_notify_6xxx(const u32 hkey,
                tpacpi_input_send_tabletsw();
                hotkey_tablet_mode_notify_change();
                *send_acpi_ev = false;
-               break;
+               return true;
 
        case TP_HKEY_EV_PALM_DETECTED:
        case TP_HKEY_EV_PALM_UNDETECTED:
@@ -4092,13 +4105,12 @@ static bool hotkey_notify_6xxx(const u32 hkey,
                return true;
 
        default:
-               pr_warn("unknown possible thermal alarm or keyboard event received\n");
-               known = false;
+               /* report simply as unknown, no sensor dump */
+               return false;
        }
 
        thermal_dump_all_sensors();
-
-       return known;
+       return true;
 }
 
 static void hotkey_notify(struct ibm_struct *ibm, u32 event)
index 4635cb35008c2cdead18f80ab9f692ed8968ff98..a4d262db9945ff10a1d0f67409cb0b03c76026b8 100644 (file)
@@ -401,7 +401,7 @@ config PWM_STI
 
 config PWM_STM32
        tristate "STMicroelectronics STM32 PWM"
-       depends on MFD_STM32_TIMERS || COMPILE_TEST
+       depends on MFD_STM32_TIMERS
        help
          Generic PWM framework driver for STM32 SoCs.
 
index 4fb1be246c44e4ec071f6426022269288d038c1f..0d0f8376bc35118e1aac4bf8f1c2be1d6010e44b 100644 (file)
@@ -460,8 +460,7 @@ MODULE_DEVICE_TABLE(of, atmel_tcb_pwm_dt_ids);
 #ifdef CONFIG_PM_SLEEP
 static int atmel_tcb_pwm_suspend(struct device *dev)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct atmel_tcb_pwm_chip *tcbpwm = platform_get_drvdata(pdev);
+       struct atmel_tcb_pwm_chip *tcbpwm = dev_get_drvdata(dev);
        void __iomem *base = tcbpwm->tc->regs;
        int i;
 
@@ -478,8 +477,7 @@ static int atmel_tcb_pwm_suspend(struct device *dev)
 
 static int atmel_tcb_pwm_resume(struct device *dev)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct atmel_tcb_pwm_chip *tcbpwm = platform_get_drvdata(pdev);
+       struct atmel_tcb_pwm_chip *tcbpwm = dev_get_drvdata(dev);
        void __iomem *base = tcbpwm->tc->regs;
        int i;
 
index 5d6ed1507d29284f2ba28f2cc781f4b797067f01..5561b9e190f84a63513ff3b86ecbeef7461404e8 100644 (file)
@@ -74,6 +74,10 @@ static int pwm_lpss_remove_platform(struct platform_device *pdev)
        return pwm_lpss_remove(lpwm);
 }
 
+static SIMPLE_DEV_PM_OPS(pwm_lpss_platform_pm_ops,
+                        pwm_lpss_suspend,
+                        pwm_lpss_resume);
+
 static const struct acpi_device_id pwm_lpss_acpi_match[] = {
        { "80860F09", (unsigned long)&pwm_lpss_byt_info },
        { "80862288", (unsigned long)&pwm_lpss_bsw_info },
@@ -86,6 +90,7 @@ static struct platform_driver pwm_lpss_driver_platform = {
        .driver = {
                .name = "pwm-lpss",
                .acpi_match_table = pwm_lpss_acpi_match,
+               .pm = &pwm_lpss_platform_pm_ops,
        },
        .probe = pwm_lpss_probe_platform,
        .remove = pwm_lpss_remove_platform,
index 8db0d40ccacde84a61d292936f6bbdeeed7ac358..4721a264bac2580cf8d21ee54396e0b494f1c9dc 100644 (file)
 /* Size of each PWM register space if multiple */
 #define PWM_SIZE                       0x400
 
+#define MAX_PWMS                       4
+
 struct pwm_lpss_chip {
        struct pwm_chip chip;
        void __iomem *regs;
        const struct pwm_lpss_boardinfo *info;
+       u32 saved_ctrl[MAX_PWMS];
 };
 
 static inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip)
@@ -177,6 +180,9 @@ struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r,
        unsigned long c;
        int ret;
 
+       if (WARN_ON(info->npwm > MAX_PWMS))
+               return ERR_PTR(-ENODEV);
+
        lpwm = devm_kzalloc(dev, sizeof(*lpwm), GFP_KERNEL);
        if (!lpwm)
                return ERR_PTR(-ENOMEM);
@@ -212,6 +218,30 @@ int pwm_lpss_remove(struct pwm_lpss_chip *lpwm)
 }
 EXPORT_SYMBOL_GPL(pwm_lpss_remove);
 
+int pwm_lpss_suspend(struct device *dev)
+{
+       struct pwm_lpss_chip *lpwm = dev_get_drvdata(dev);
+       int i;
+
+       for (i = 0; i < lpwm->info->npwm; i++)
+               lpwm->saved_ctrl[i] = readl(lpwm->regs + i * PWM_SIZE + PWM);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pwm_lpss_suspend);
+
+int pwm_lpss_resume(struct device *dev)
+{
+       struct pwm_lpss_chip *lpwm = dev_get_drvdata(dev);
+       int i;
+
+       for (i = 0; i < lpwm->info->npwm; i++)
+               writel(lpwm->saved_ctrl[i], lpwm->regs + i * PWM_SIZE + PWM);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pwm_lpss_resume);
+
 MODULE_DESCRIPTION("PWM driver for Intel LPSS");
 MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");
 MODULE_LICENSE("GPL v2");
index 98306bb02cfe71c0775eb430e7cf623fdc431889..7a4238ad1fcb1f25390032019170759c6666ae83 100644 (file)
@@ -28,5 +28,7 @@ struct pwm_lpss_boardinfo {
 struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r,
                                     const struct pwm_lpss_boardinfo *info);
 int pwm_lpss_remove(struct pwm_lpss_chip *lpwm);
+int pwm_lpss_suspend(struct device *dev);
+int pwm_lpss_resume(struct device *dev);
 
 #endif /* __PWM_LPSS_H */
index 0767deba8e622dbfb8227910252266c5f54ef777..822860b4801a6823008d51346e82d0f279c6c053 100644 (file)
@@ -541,8 +541,8 @@ static int meson_pwm_probe(struct platform_device *pdev)
        meson->data = of_device_get_match_data(&pdev->dev);
        meson->inverter_mask = BIT(meson->chip.npwm) - 1;
 
-       channels = devm_kcalloc(&pdev->dev, meson->chip.npwm, sizeof(*meson),
-                               GFP_KERNEL);
+       channels = devm_kcalloc(&pdev->dev, meson->chip.npwm,
+                               sizeof(*channels), GFP_KERNEL);
        if (!channels)
                return -ENOMEM;
 
index 91d11f2e2fefd2897a693199bc8c904faf165003..748f614d53755daabdd9f1529d7ba9cd602cb611 100644 (file)
@@ -261,8 +261,7 @@ MODULE_DEVICE_TABLE(of, rcar_pwm_of_table);
 #ifdef CONFIG_PM_SLEEP
 static struct pwm_device *rcar_pwm_dev_to_pwm_dev(struct device *dev)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct rcar_pwm_chip *rcar_pwm = platform_get_drvdata(pdev);
+       struct rcar_pwm_chip *rcar_pwm = dev_get_drvdata(dev);
        struct pwm_chip *chip = &rcar_pwm->chip;
 
        return &chip->pwms[0];
index 09383c6720fb623c59bf387909af4eaff010edba..4f842550fbd127ce1b0f53522dfb7f4e60b74329 100644 (file)
@@ -484,9 +484,7 @@ static int stm32_pwm_apply_locked(struct pwm_chip *chip, struct pwm_device *pwm,
 static const struct pwm_ops stm32pwm_ops = {
        .owner = THIS_MODULE,
        .apply = stm32_pwm_apply_locked,
-#if IS_ENABLED(CONFIG_DMA_ENGINE)
-       .capture = stm32_pwm_capture,
-#endif
+       .capture = IS_ENABLED(CONFIG_DMA_ENGINE) ? stm32_pwm_capture : NULL,
 };
 
 static int stm32_pwm_set_breakinput(struct stm32_pwm *priv,
index 2190debf3d35fca5df7a957ef31ab63bc0a47712..2bf8e7c49f2a7ed8ae9d9ec425b391e1544cd599 100644 (file)
@@ -686,7 +686,7 @@ static int q6v5_mpss_load(struct q6v5 *qproc)
        struct elf32_hdr *ehdr;
        phys_addr_t mpss_reloc;
        phys_addr_t boot_addr;
-       phys_addr_t min_addr = (phys_addr_t)ULLONG_MAX;
+       phys_addr_t min_addr = PHYS_ADDR_MAX;
        phys_addr_t max_addr = 0;
        bool relocate = false;
        char seg_name[10];
index 73cce3ecb97fefbccc66266a4fd29f08e453079e..d3a38c421503abbaab03d81fdaac739591251920 100644 (file)
@@ -1222,80 +1222,37 @@ static void dasd_hosts_init(struct dentry *base_dentry,
                device->hosts_dentry = pde;
 }
 
-/*
- * Allocate memory for a channel program with 'cplength' channel
- * command words and 'datasize' additional space. There are two
- * variantes: 1) dasd_kmalloc_request uses kmalloc to get the needed
- * memory and 2) dasd_smalloc_request uses the static ccw memory
- * that gets allocated for each device.
- */
-struct dasd_ccw_req *dasd_kmalloc_request(int magic, int cplength,
-                                         int datasize,
-                                         struct dasd_device *device)
-{
-       struct dasd_ccw_req *cqr;
-
-       /* Sanity checks */
-       BUG_ON(datasize > PAGE_SIZE ||
-            (cplength*sizeof(struct ccw1)) > PAGE_SIZE);
-
-       cqr = kzalloc(sizeof(struct dasd_ccw_req), GFP_ATOMIC);
-       if (cqr == NULL)
-               return ERR_PTR(-ENOMEM);
-       cqr->cpaddr = NULL;
-       if (cplength > 0) {
-               cqr->cpaddr = kcalloc(cplength, sizeof(struct ccw1),
-                                     GFP_ATOMIC | GFP_DMA);
-               if (cqr->cpaddr == NULL) {
-                       kfree(cqr);
-                       return ERR_PTR(-ENOMEM);
-               }
-       }
-       cqr->data = NULL;
-       if (datasize > 0) {
-               cqr->data = kzalloc(datasize, GFP_ATOMIC | GFP_DMA);
-               if (cqr->data == NULL) {
-                       kfree(cqr->cpaddr);
-                       kfree(cqr);
-                       return ERR_PTR(-ENOMEM);
-               }
-       }
-       cqr->magic =  magic;
-       set_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
-       dasd_get_device(device);
-       return cqr;
-}
-EXPORT_SYMBOL(dasd_kmalloc_request);
-
-struct dasd_ccw_req *dasd_smalloc_request(int magic, int cplength,
-                                         int datasize,
-                                         struct dasd_device *device)
+struct dasd_ccw_req *dasd_smalloc_request(int magic, int cplength, int datasize,
+                                         struct dasd_device *device,
+                                         struct dasd_ccw_req *cqr)
 {
        unsigned long flags;
-       struct dasd_ccw_req *cqr;
-       char *data;
-       int size;
+       char *data, *chunk;
+       int size = 0;
 
-       size = (sizeof(struct dasd_ccw_req) + 7L) & -8L;
        if (cplength > 0)
                size += cplength * sizeof(struct ccw1);
        if (datasize > 0)
                size += datasize;
+       if (!cqr)
+               size += (sizeof(*cqr) + 7L) & -8L;
+
        spin_lock_irqsave(&device->mem_lock, flags);
-       cqr = (struct dasd_ccw_req *)
-               dasd_alloc_chunk(&device->ccw_chunks, size);
+       data = chunk = dasd_alloc_chunk(&device->ccw_chunks, size);
        spin_unlock_irqrestore(&device->mem_lock, flags);
-       if (cqr == NULL)
+       if (!chunk)
                return ERR_PTR(-ENOMEM);
-       memset(cqr, 0, sizeof(struct dasd_ccw_req));
-       data = (char *) cqr + ((sizeof(struct dasd_ccw_req) + 7L) & -8L);
-       cqr->cpaddr = NULL;
+       if (!cqr) {
+               cqr = (void *) data;
+               data += (sizeof(*cqr) + 7L) & -8L;
+       }
+       memset(cqr, 0, sizeof(*cqr));
+       cqr->mem_chunk = chunk;
        if (cplength > 0) {
-               cqr->cpaddr = (struct ccw1 *) data;
-               data += cplength*sizeof(struct ccw1);
-               memset(cqr->cpaddr, 0, cplength*sizeof(struct ccw1));
+               cqr->cpaddr = data;
+               data += cplength * sizeof(struct ccw1);
+               memset(cqr->cpaddr, 0, cplength * sizeof(struct ccw1));
        }
-       cqr->data = NULL;
        if (datasize > 0) {
                cqr->data = data;
                memset(cqr->data, 0, datasize);
@@ -1307,33 +1264,12 @@ struct dasd_ccw_req *dasd_smalloc_request(int magic, int cplength,
 }
 EXPORT_SYMBOL(dasd_smalloc_request);
 
-/*
- * Free memory of a channel program. This function needs to free all the
- * idal lists that might have been created by dasd_set_cda and the
- * struct dasd_ccw_req itself.
- */
-void dasd_kfree_request(struct dasd_ccw_req *cqr, struct dasd_device *device)
-{
-       struct ccw1 *ccw;
-
-       /* Clear any idals used for the request. */
-       ccw = cqr->cpaddr;
-       do {
-               clear_normalized_cda(ccw);
-       } while (ccw++->flags & (CCW_FLAG_CC | CCW_FLAG_DC));
-       kfree(cqr->cpaddr);
-       kfree(cqr->data);
-       kfree(cqr);
-       dasd_put_device(device);
-}
-EXPORT_SYMBOL(dasd_kfree_request);
-
 void dasd_sfree_request(struct dasd_ccw_req *cqr, struct dasd_device *device)
 {
        unsigned long flags;
 
        spin_lock_irqsave(&device->mem_lock, flags);
-       dasd_free_chunk(&device->ccw_chunks, cqr);
+       dasd_free_chunk(&device->ccw_chunks, cqr->mem_chunk);
        spin_unlock_irqrestore(&device->mem_lock, flags);
        dasd_put_device(device);
 }
@@ -1885,6 +1821,33 @@ static void __dasd_device_process_ccw_queue(struct dasd_device *device,
        }
 }
 
+static void __dasd_process_cqr(struct dasd_device *device,
+                              struct dasd_ccw_req *cqr)
+{
+       char errorstring[ERRORLENGTH];
+
+       switch (cqr->status) {
+       case DASD_CQR_SUCCESS:
+               cqr->status = DASD_CQR_DONE;
+               break;
+       case DASD_CQR_ERROR:
+               cqr->status = DASD_CQR_NEED_ERP;
+               break;
+       case DASD_CQR_CLEARED:
+               cqr->status = DASD_CQR_TERMINATED;
+               break;
+       default:
+               /* internal error 12 - wrong cqr status*/
+               snprintf(errorstring, ERRORLENGTH, "12 %p %x02", cqr, cqr->status);
+               dev_err(&device->cdev->dev,
+                       "An error occurred in the DASD device driver, "
+                       "reason=%s\n", errorstring);
+               BUG();
+       }
+       if (cqr->callback)
+               cqr->callback(cqr, cqr->callback_data);
+}
+
 /*
  * the cqrs from the final queue are returned to the upper layer
  * by setting a dasd_block state and calling the callback function
@@ -1895,40 +1858,18 @@ static void __dasd_device_process_final_queue(struct dasd_device *device,
        struct list_head *l, *n;
        struct dasd_ccw_req *cqr;
        struct dasd_block *block;
-       void (*callback)(struct dasd_ccw_req *, void *data);
-       void *callback_data;
-       char errorstring[ERRORLENGTH];
 
        list_for_each_safe(l, n, final_queue) {
                cqr = list_entry(l, struct dasd_ccw_req, devlist);
                list_del_init(&cqr->devlist);
                block = cqr->block;
-               callback = cqr->callback;
-               callback_data = cqr->callback_data;
-               if (block)
+               if (!block) {
+                       __dasd_process_cqr(device, cqr);
+               } else {
                        spin_lock_bh(&block->queue_lock);
-               switch (cqr->status) {
-               case DASD_CQR_SUCCESS:
-                       cqr->status = DASD_CQR_DONE;
-                       break;
-               case DASD_CQR_ERROR:
-                       cqr->status = DASD_CQR_NEED_ERP;
-                       break;
-               case DASD_CQR_CLEARED:
-                       cqr->status = DASD_CQR_TERMINATED;
-                       break;
-               default:
-                       /* internal error 12 - wrong cqr status*/
-                       snprintf(errorstring, ERRORLENGTH, "12 %p %x02", cqr, cqr->status);
-                       dev_err(&device->cdev->dev,
-                               "An error occurred in the DASD device driver, "
-                               "reason=%s\n", errorstring);
-                       BUG();
-               }
-               if (cqr->callback != NULL)
-                       (callback)(cqr, callback_data);
-               if (block)
+                       __dasd_process_cqr(device, cqr);
                        spin_unlock_bh(&block->queue_lock);
+               }
        }
 }
 
@@ -3041,7 +2982,6 @@ static blk_status_t do_dasd_request(struct blk_mq_hw_ctx *hctx,
        cqr->callback_data = req;
        cqr->status = DASD_CQR_FILLED;
        cqr->dq = dq;
-       *((struct dasd_ccw_req **) blk_mq_rq_to_pdu(req)) = cqr;
 
        blk_mq_start_request(req);
        spin_lock(&block->queue_lock);
@@ -3072,7 +3012,7 @@ enum blk_eh_timer_return dasd_times_out(struct request *req, bool reserved)
        unsigned long flags;
        int rc = 0;
 
-       cqr = *((struct dasd_ccw_req **) blk_mq_rq_to_pdu(req));
+       cqr = blk_mq_rq_to_pdu(req);
        if (!cqr)
                return BLK_EH_DONE;
 
@@ -3174,7 +3114,7 @@ static int dasd_alloc_queue(struct dasd_block *block)
        int rc;
 
        block->tag_set.ops = &dasd_mq_ops;
-       block->tag_set.cmd_size = sizeof(struct dasd_ccw_req *);
+       block->tag_set.cmd_size = sizeof(struct dasd_ccw_req);
        block->tag_set.nr_hw_queues = DASD_NR_HW_QUEUES;
        block->tag_set.queue_depth = DASD_MAX_LCU_DEV * DASD_REQ_PER_DEV;
        block->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
@@ -4038,7 +3978,8 @@ static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device,
        struct ccw1 *ccw;
        unsigned long *idaw;
 
-       cqr = dasd_smalloc_request(magic, 1 /* RDC */, rdc_buffer_size, device);
+       cqr = dasd_smalloc_request(magic, 1 /* RDC */, rdc_buffer_size, device,
+                                  NULL);
 
        if (IS_ERR(cqr)) {
                /* internal error 13 - Allocating the RDC request failed*/
index 5e963fe0e38d4c2125c43ae801ca7e9b28d98d07..e36a114354fc368e2141aae5c080c7f61b674da8 100644 (file)
@@ -407,9 +407,9 @@ static int read_unit_address_configuration(struct dasd_device *device,
        int rc;
        unsigned long flags;
 
-       cqr = dasd_kmalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ + 1 /* RSSD */,
+       cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ + 1 /* RSSD */,
                                   (sizeof(struct dasd_psf_prssd_data)),
-                                  device);
+                                  device, NULL);
        if (IS_ERR(cqr))
                return PTR_ERR(cqr);
        cqr->startdev = device;
@@ -457,7 +457,7 @@ static int read_unit_address_configuration(struct dasd_device *device,
                lcu->flags |= NEED_UAC_UPDATE;
                spin_unlock_irqrestore(&lcu->lock, flags);
        }
-       dasd_kfree_request(cqr, cqr->memdev);
+       dasd_sfree_request(cqr, cqr->memdev);
        return rc;
 }
 
index 131f1989f6f3dff0345250c71943f5ac338af19c..e1fe02477ea8fca951232dabe7f89754c8f287ff 100644 (file)
@@ -536,7 +536,8 @@ static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev,
        /* Build the request */
        datasize = sizeof(struct dasd_diag_req) +
                count*sizeof(struct dasd_diag_bio);
-       cqr = dasd_smalloc_request(DASD_DIAG_MAGIC, 0, datasize, memdev);
+       cqr = dasd_smalloc_request(DASD_DIAG_MAGIC, 0, datasize, memdev,
+                                  blk_mq_rq_to_pdu(req));
        if (IS_ERR(cqr))
                return cqr;
 
index be208e7adcb46087e7fb2436fadf8a737d7c472e..bbf95b78ef5d9e4c5903e466e7de3f71b615c9ce 100644 (file)
@@ -886,7 +886,7 @@ static int dasd_eckd_read_conf_lpm(struct dasd_device *device,
        }
        cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* RCD */,
                                   0, /* use rcd_buf as data ara */
-                                  device);
+                                  device, NULL);
        if (IS_ERR(cqr)) {
                DBF_DEV_EVENT(DBF_WARNING, device, "%s",
                              "Could not allocate RCD request");
@@ -1442,7 +1442,7 @@ static int dasd_eckd_read_features(struct dasd_device *device)
        cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ + 1 /* RSSD */,
                                   (sizeof(struct dasd_psf_prssd_data) +
                                    sizeof(struct dasd_rssd_features)),
-                                  device);
+                                  device, NULL);
        if (IS_ERR(cqr)) {
                DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s", "Could not "
                                "allocate initialization request");
@@ -1504,7 +1504,7 @@ static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device,
 
        cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ ,
                                  sizeof(struct dasd_psf_ssc_data),
-                                 device);
+                                  device, NULL);
 
        if (IS_ERR(cqr)) {
                DBF_DEV_EVENT(DBF_WARNING, device, "%s",
@@ -1815,7 +1815,8 @@ dasd_eckd_analysis_ccw(struct dasd_device *device)
 
        cplength = 8;
        datasize = sizeof(struct DE_eckd_data) + 2*sizeof(struct LO_eckd_data);
-       cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, datasize, device);
+       cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, datasize, device,
+                                  NULL);
        if (IS_ERR(cqr))
                return cqr;
        ccw = cqr->cpaddr;
@@ -2092,7 +2093,8 @@ dasd_eckd_build_check_tcw(struct dasd_device *base, struct format_data_t *fdata,
         */
        itcw_size = itcw_calc_size(0, count, 0);
 
-       cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 0, itcw_size, startdev);
+       cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 0, itcw_size, startdev,
+                                  NULL);
        if (IS_ERR(cqr))
                return cqr;
 
@@ -2186,7 +2188,7 @@ dasd_eckd_build_check(struct dasd_device *base, struct format_data_t *fdata,
        cplength += count;
 
        cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, datasize,
-                                 startdev);
+                                  startdev, NULL);
        if (IS_ERR(cqr))
                return cqr;
 
@@ -2332,7 +2334,7 @@ dasd_eckd_build_format(struct dasd_device *base,
        }
        /* Allocate the format ccw request. */
        fcp = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength,
-                                  datasize, startdev);
+                                  datasize, startdev, NULL);
        if (IS_ERR(fcp))
                return fcp;
 
@@ -3103,7 +3105,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
        }
        /* Allocate the ccw request. */
        cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, datasize,
-                                  startdev);
+                                  startdev, blk_mq_rq_to_pdu(req));
        if (IS_ERR(cqr))
                return cqr;
        ccw = cqr->cpaddr;
@@ -3262,7 +3264,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track(
 
        /* Allocate the ccw request. */
        cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, datasize,
-                                  startdev);
+                                  startdev, blk_mq_rq_to_pdu(req));
        if (IS_ERR(cqr))
                return cqr;
        ccw = cqr->cpaddr;
@@ -3595,7 +3597,8 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
 
        /* Allocate the ccw request. */
        itcw_size = itcw_calc_size(0, ctidaw, 0);
-       cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 0, itcw_size, startdev);
+       cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 0, itcw_size, startdev,
+                                  blk_mq_rq_to_pdu(req));
        if (IS_ERR(cqr))
                return cqr;
 
@@ -3862,7 +3865,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_raw(struct dasd_device *startdev,
 
        /* Allocate the ccw request. */
        cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength,
-                                  datasize, startdev);
+                                  datasize, startdev, blk_mq_rq_to_pdu(req));
        if (IS_ERR(cqr))
                return cqr;
 
@@ -4102,7 +4105,7 @@ dasd_eckd_release(struct dasd_device *device)
                return -EACCES;
 
        useglobal = 0;
-       cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device);
+       cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device, NULL);
        if (IS_ERR(cqr)) {
                mutex_lock(&dasd_reserve_mutex);
                useglobal = 1;
@@ -4157,7 +4160,7 @@ dasd_eckd_reserve(struct dasd_device *device)
                return -EACCES;
 
        useglobal = 0;
-       cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device);
+       cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device, NULL);
        if (IS_ERR(cqr)) {
                mutex_lock(&dasd_reserve_mutex);
                useglobal = 1;
@@ -4211,7 +4214,7 @@ dasd_eckd_steal_lock(struct dasd_device *device)
                return -EACCES;
 
        useglobal = 0;
-       cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device);
+       cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device, NULL);
        if (IS_ERR(cqr)) {
                mutex_lock(&dasd_reserve_mutex);
                useglobal = 1;
@@ -4271,7 +4274,8 @@ static int dasd_eckd_snid(struct dasd_device *device,
 
        useglobal = 0;
        cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1,
-                                  sizeof(struct dasd_snid_data), device);
+                                  sizeof(struct dasd_snid_data), device,
+                                  NULL);
        if (IS_ERR(cqr)) {
                mutex_lock(&dasd_reserve_mutex);
                useglobal = 1;
@@ -4331,7 +4335,7 @@ dasd_eckd_performance(struct dasd_device *device, void __user *argp)
        cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */  + 1 /* RSSD */,
                                   (sizeof(struct dasd_psf_prssd_data) +
                                    sizeof(struct dasd_rssd_perf_stats_t)),
-                                  device);
+                                  device, NULL);
        if (IS_ERR(cqr)) {
                DBF_DEV_EVENT(DBF_WARNING, device, "%s",
                            "Could not allocate initialization request");
@@ -4477,7 +4481,7 @@ static int dasd_symm_io(struct dasd_device *device, void __user *argp)
        psf1 = psf_data[1];
 
        /* setup CCWs for PSF + RSSD */
-       cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 2 , 0, device);
+       cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 2, 0, device, NULL);
        if (IS_ERR(cqr)) {
                DBF_DEV_EVENT(DBF_WARNING, device, "%s",
                        "Could not allocate initialization request");
@@ -5037,7 +5041,7 @@ static int dasd_eckd_read_message_buffer(struct dasd_device *device,
        cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ + 1 /* RSSD */,
                                   (sizeof(struct dasd_psf_prssd_data) +
                                    sizeof(struct dasd_rssd_messages)),
-                                  device);
+                                  device, NULL);
        if (IS_ERR(cqr)) {
                DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s",
                                "Could not allocate read message buffer request");
@@ -5126,7 +5130,7 @@ static int dasd_eckd_query_host_access(struct dasd_device *device,
 
        cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ + 1 /* RSSD */,
                                   sizeof(struct dasd_psf_prssd_data) + 1,
-                                  device);
+                                  device, NULL);
        if (IS_ERR(cqr)) {
                DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s",
                                "Could not allocate read message buffer request");
@@ -5284,8 +5288,8 @@ dasd_eckd_psf_cuir_response(struct dasd_device *device, int response,
        int rc;
 
        cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ ,
-                                 sizeof(struct dasd_psf_cuir_response),
-                                 device);
+                                  sizeof(struct dasd_psf_cuir_response),
+                                  device, NULL);
 
        if (IS_ERR(cqr)) {
                DBF_DEV_EVENT(DBF_WARNING, device, "%s",
index 0af8c5295b650b1132e5946b123b558a08e91ccc..6ef8714dc6935047ec0f48d8cc3f6e34dd77c19c 100644 (file)
@@ -447,7 +447,7 @@ static void dasd_eer_snss_cb(struct dasd_ccw_req *cqr, void *data)
                 * is a new ccw in device->eer_cqr. Free the "old"
                 * snss request now.
                 */
-               dasd_kfree_request(cqr, device);
+               dasd_sfree_request(cqr, device);
 }
 
 /*
@@ -472,8 +472,8 @@ int dasd_eer_enable(struct dasd_device *device)
        if (rc)
                goto out;
 
-       cqr = dasd_kmalloc_request(DASD_ECKD_MAGIC, 1 /* SNSS */,
-                                  SNSS_DATA_SIZE, device);
+       cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* SNSS */,
+                                  SNSS_DATA_SIZE, device, NULL);
        if (IS_ERR(cqr)) {
                rc = -ENOMEM;
                cqr = NULL;
@@ -505,7 +505,7 @@ out:
        spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
 
        if (cqr)
-               dasd_kfree_request(cqr, device);
+               dasd_sfree_request(cqr, device);
 
        return rc;
 }
@@ -528,7 +528,7 @@ void dasd_eer_disable(struct dasd_device *device)
        in_use = test_and_clear_bit(DASD_FLAG_EER_IN_USE, &device->flags);
        spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
        if (cqr && !in_use)
-               dasd_kfree_request(cqr, device);
+               dasd_sfree_request(cqr, device);
 }
 
 /*
index a6b132f7e869eb4eb804b3fa8407cd064c92b699..56007a3e7f110358e27ad74563f24e428cbae473 100644 (file)
@@ -356,7 +356,8 @@ static struct dasd_ccw_req *dasd_fba_build_cp_discard(
        datasize = sizeof(struct DE_fba_data) +
                nr_ccws * (sizeof(struct LO_fba_data) + sizeof(struct ccw1));
 
-       cqr = dasd_smalloc_request(DASD_FBA_MAGIC, cplength, datasize, memdev);
+       cqr = dasd_smalloc_request(DASD_FBA_MAGIC, cplength, datasize, memdev,
+                                  blk_mq_rq_to_pdu(req));
        if (IS_ERR(cqr))
                return cqr;
 
@@ -490,7 +491,8 @@ static struct dasd_ccw_req *dasd_fba_build_cp_regular(
                datasize += (count - 1)*sizeof(struct LO_fba_data);
        }
        /* Allocate the ccw request. */
-       cqr = dasd_smalloc_request(DASD_FBA_MAGIC, cplength, datasize, memdev);
+       cqr = dasd_smalloc_request(DASD_FBA_MAGIC, cplength, datasize, memdev,
+                                  blk_mq_rq_to_pdu(req));
        if (IS_ERR(cqr))
                return cqr;
        ccw = cqr->cpaddr;
index 96709b1a7bf8d8af0f4e0db7748cd5ac8e5a8650..976b6bd4fb05ccb6afc5de34cdb12c080c7f2428 100644 (file)
@@ -158,40 +158,33 @@ do { \
 
 struct dasd_ccw_req {
        unsigned int magic;             /* Eye catcher */
+       int intrc;                      /* internal error, e.g. from start_IO */
        struct list_head devlist;       /* for dasd_device request queue */
        struct list_head blocklist;     /* for dasd_block request queue */
-
-       /* Where to execute what... */
        struct dasd_block *block;       /* the originating block device */
        struct dasd_device *memdev;     /* the device used to allocate this */
        struct dasd_device *startdev;   /* device the request is started on */
        struct dasd_device *basedev;    /* base device if no block->base */
        void *cpaddr;                   /* address of ccw or tcw */
+       short retries;                  /* A retry counter */
        unsigned char cpmode;           /* 0 = cmd mode, 1 = itcw */
        char status;                    /* status of this request */
-       short retries;                  /* A retry counter */
+       char lpm;                       /* logical path mask */
        unsigned long flags;            /* flags of this request */
        struct dasd_queue *dq;
-
-       /* ... and how */
        unsigned long starttime;        /* jiffies time of request start */
        unsigned long expires;          /* expiration period in jiffies */
-       char lpm;                       /* logical path mask */
        void *data;                     /* pointer to data area */
-
-       /* these are important for recovering erroneous requests          */
-       int intrc;                      /* internal error, e.g. from start_IO */
        struct irb irb;                 /* device status in case of an error */
        struct dasd_ccw_req *refers;    /* ERP-chain queueing. */
        void *function;                 /* originating ERP action */
+       void *mem_chunk;
 
-       /* these are for statistics only */
        unsigned long buildclk;         /* TOD-clock of request generation */
        unsigned long startclk;         /* TOD-clock of request start */
        unsigned long stopclk;          /* TOD-clock of request interrupt */
        unsigned long endclk;           /* TOD-clock of request termination */
 
-        /* Callback that is called after reaching final status. */
        void (*callback)(struct dasd_ccw_req *, void *data);
        void *callback_data;
 };
@@ -714,19 +707,10 @@ extern const struct block_device_operations dasd_device_operations;
 extern struct kmem_cache *dasd_page_cache;
 
 struct dasd_ccw_req *
-dasd_kmalloc_request(int , int, int, struct dasd_device *);
-struct dasd_ccw_req *
-dasd_smalloc_request(int , int, int, struct dasd_device *);
-void dasd_kfree_request(struct dasd_ccw_req *, struct dasd_device *);
+dasd_smalloc_request(int, int, int, struct dasd_device *, struct dasd_ccw_req *);
 void dasd_sfree_request(struct dasd_ccw_req *, struct dasd_device *);
 void dasd_wakeup_cb(struct dasd_ccw_req *, void *);
 
-static inline int
-dasd_kmalloc_set_cda(struct ccw1 *ccw, void *cda, struct dasd_device *device)
-{
-       return set_normalized_cda(ccw, cda);
-}
-
 struct dasd_device *dasd_alloc_device(void);
 void dasd_free_device(struct dasd_device *);
 
index a070ef0efe65d0079cc10245b1ed8b79b8e8fba9..f230516abb96d31b4eabb2689a7230905857c48f 100644 (file)
@@ -5,6 +5,7 @@
 
 # The following is required for define_trace.h to find ./trace.h
 CFLAGS_trace.o := -I$(src)
+CFLAGS_vfio_ccw_fsm.o := -I$(src)
 
 obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o isc.o \
        fcx.o itcw.o crw.o ccwreq.o trace.o ioasm.o
index dce92b2a895d6ff3bbe38104ed08ea32c7979432..dbe7c7ac9ac8c8c4456f142b14c740d3bdc0c5e6 100644 (file)
 #define CCWCHAIN_LEN_MAX       256
 
 struct pfn_array {
+       /* Starting guest physical I/O address. */
        unsigned long           pa_iova;
+       /* Array that stores PFNs of the pages need to pin. */
        unsigned long           *pa_iova_pfn;
+       /* Array that receives PFNs of the pages pinned. */
        unsigned long           *pa_pfn;
+       /* Number of pages pinned from @pa_iova. */
        int                     pa_nr;
 };
 
@@ -46,70 +50,33 @@ struct ccwchain {
 };
 
 /*
- * pfn_array_pin() - pin user pages in memory
+ * pfn_array_alloc_pin() - alloc memory for PFNs, then pin user pages in memory
  * @pa: pfn_array on which to perform the operation
  * @mdev: the mediated device to perform pin/unpin operations
+ * @iova: target guest physical address
+ * @len: number of bytes that should be pinned from @iova
  *
- * Attempt to pin user pages in memory.
+ * Attempt to allocate memory for PFNs, and pin user pages in memory.
  *
  * Usage of pfn_array:
- * @pa->pa_iova     starting guest physical I/O address. Assigned by caller.
- * @pa->pa_iova_pfn array that stores PFNs of the pages need to pin. Allocated
- *                  by caller.
- * @pa->pa_pfn      array that receives PFNs of the pages pinned. Allocated by
- *                  caller.
- * @pa->pa_nr       number of pages from @pa->pa_iova to pin. Assigned by
- *                  caller.
- *                  number of pages pinned. Assigned by callee.
+ * We expect (pa_nr == 0) and (pa_iova_pfn == NULL), any field in
+ * this structure will be filled in by this function.
  *
  * Returns:
  *   Number of pages pinned on success.
- *   If @pa->pa_nr is 0 or negative, returns 0.
+ *   If @pa->pa_nr is not 0, or @pa->pa_iova_pfn is not NULL initially,
+ *   returns -EINVAL.
  *   If no pages were pinned, returns -errno.
  */
-static int pfn_array_pin(struct pfn_array *pa, struct device *mdev)
-{
-       int i, ret;
-
-       if (pa->pa_nr <= 0) {
-               pa->pa_nr = 0;
-               return 0;
-       }
-
-       pa->pa_iova_pfn[0] = pa->pa_iova >> PAGE_SHIFT;
-       for (i = 1; i < pa->pa_nr; i++)
-               pa->pa_iova_pfn[i] = pa->pa_iova_pfn[i - 1] + 1;
-
-       ret = vfio_pin_pages(mdev, pa->pa_iova_pfn, pa->pa_nr,
-                            IOMMU_READ | IOMMU_WRITE, pa->pa_pfn);
-
-       if (ret > 0 && ret != pa->pa_nr) {
-               vfio_unpin_pages(mdev, pa->pa_iova_pfn, ret);
-               pa->pa_nr = 0;
-               return 0;
-       }
-
-       return ret;
-}
-
-/* Unpin the pages before releasing the memory. */
-static void pfn_array_unpin_free(struct pfn_array *pa, struct device *mdev)
-{
-       vfio_unpin_pages(mdev, pa->pa_iova_pfn, pa->pa_nr);
-       pa->pa_nr = 0;
-       kfree(pa->pa_iova_pfn);
-}
-
-/* Alloc memory for PFNs, then pin pages with them. */
 static int pfn_array_alloc_pin(struct pfn_array *pa, struct device *mdev,
                               u64 iova, unsigned int len)
 {
-       int ret = 0;
+       int i, ret = 0;
 
        if (!len)
                return 0;
 
-       if (pa->pa_nr)
+       if (pa->pa_nr || pa->pa_iova_pfn)
                return -EINVAL;
 
        pa->pa_iova = iova;
@@ -126,18 +93,39 @@ static int pfn_array_alloc_pin(struct pfn_array *pa, struct device *mdev,
                return -ENOMEM;
        pa->pa_pfn = pa->pa_iova_pfn + pa->pa_nr;
 
-       ret = pfn_array_pin(pa, mdev);
+       pa->pa_iova_pfn[0] = pa->pa_iova >> PAGE_SHIFT;
+       for (i = 1; i < pa->pa_nr; i++)
+               pa->pa_iova_pfn[i] = pa->pa_iova_pfn[i - 1] + 1;
 
-       if (ret > 0)
-               return ret;
-       else if (!ret)
+       ret = vfio_pin_pages(mdev, pa->pa_iova_pfn, pa->pa_nr,
+                            IOMMU_READ | IOMMU_WRITE, pa->pa_pfn);
+
+       if (ret < 0) {
+               goto err_out;
+       } else if (ret > 0 && ret != pa->pa_nr) {
+               vfio_unpin_pages(mdev, pa->pa_iova_pfn, ret);
                ret = -EINVAL;
+               goto err_out;
+       }
 
+       return ret;
+
+err_out:
+       pa->pa_nr = 0;
        kfree(pa->pa_iova_pfn);
+       pa->pa_iova_pfn = NULL;
 
        return ret;
 }
 
+/* Unpin the pages before releasing the memory. */
+static void pfn_array_unpin_free(struct pfn_array *pa, struct device *mdev)
+{
+       vfio_unpin_pages(mdev, pa->pa_iova_pfn, pa->pa_nr);
+       pa->pa_nr = 0;
+       kfree(pa->pa_iova_pfn);
+}
+
 static int pfn_array_table_init(struct pfn_array_table *pat, int nr)
 {
        pat->pat_pa = kcalloc(nr, sizeof(*pat->pat_pa), GFP_KERNEL);
@@ -365,6 +353,9 @@ static void cp_unpin_free(struct channel_program *cp)
  * This is the chain length not considering any TICs.
  * You need to do a new round for each TIC target.
  *
+ * The program is also validated for absence of not yet supported
+ * indirect data addressing scenarios.
+ *
  * Returns: the length of the ccw chain or -errno.
  */
 static int ccwchain_calc_length(u64 iova, struct channel_program *cp)
@@ -391,6 +382,14 @@ static int ccwchain_calc_length(u64 iova, struct channel_program *cp)
        do {
                cnt++;
 
+               /*
+                * As we don't want to fail direct addressing even if the
+                * orb specified one of the unsupported formats, we defer
+                * checking for IDAWs in unsupported formats to here.
+                */
+               if ((!cp->orb.cmd.c64 || cp->orb.cmd.i2k) && ccw_is_idal(ccw))
+                       return -EOPNOTSUPP;
+
                if ((!ccw_is_chain(ccw)) && (!ccw_is_tic(ccw)))
                        break;
 
@@ -503,7 +502,7 @@ static int ccwchain_fetch_direct(struct ccwchain *chain,
        struct ccw1 *ccw;
        struct pfn_array_table *pat;
        unsigned long *idaws;
-       int idaw_nr;
+       int ret;
 
        ccw = chain->ch_ccw + idx;
 
@@ -523,18 +522,19 @@ static int ccwchain_fetch_direct(struct ccwchain *chain,
         * needed when translating a direct ccw to a idal ccw.
         */
        pat = chain->ch_pat + idx;
-       if (pfn_array_table_init(pat, 1))
-               return -ENOMEM;
-       idaw_nr = pfn_array_alloc_pin(pat->pat_pa, cp->mdev,
-                                     ccw->cda, ccw->count);
-       if (idaw_nr < 0)
-               return idaw_nr;
+       ret = pfn_array_table_init(pat, 1);
+       if (ret)
+               goto out_init;
+
+       ret = pfn_array_alloc_pin(pat->pat_pa, cp->mdev, ccw->cda, ccw->count);
+       if (ret < 0)
+               goto out_init;
 
        /* Translate this direct ccw to a idal ccw. */
-       idaws = kcalloc(idaw_nr, sizeof(*idaws), GFP_DMA | GFP_KERNEL);
+       idaws = kcalloc(ret, sizeof(*idaws), GFP_DMA | GFP_KERNEL);
        if (!idaws) {
-               pfn_array_table_unpin_free(pat, cp->mdev);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto out_unpin;
        }
        ccw->cda = (__u32) virt_to_phys(idaws);
        ccw->flags |= CCW_FLAG_IDA;
@@ -542,6 +542,12 @@ static int ccwchain_fetch_direct(struct ccwchain *chain,
        pfn_array_table_idal_create_words(pat, idaws);
 
        return 0;
+
+out_unpin:
+       pfn_array_table_unpin_free(pat, cp->mdev);
+out_init:
+       ccw->cda = 0;
+       return ret;
 }
 
 static int ccwchain_fetch_idal(struct ccwchain *chain,
@@ -571,7 +577,7 @@ static int ccwchain_fetch_idal(struct ccwchain *chain,
        pat = chain->ch_pat + idx;
        ret = pfn_array_table_init(pat, idaw_nr);
        if (ret)
-               return ret;
+               goto out_init;
 
        /* Translate idal ccw to use new allocated idaws. */
        idaws = kzalloc(idaw_len, GFP_DMA | GFP_KERNEL);
@@ -603,6 +609,8 @@ out_free_idaws:
        kfree(idaws);
 out_unpin:
        pfn_array_table_unpin_free(pat, cp->mdev);
+out_init:
+       ccw->cda = 0;
        return ret;
 }
 
@@ -656,10 +664,8 @@ int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb)
        /*
         * XXX:
         * Only support prefetch enable mode now.
-        * Only support 64bit addressing idal.
-        * Only support 4k IDAW.
         */
-       if (!orb->cmd.pfch || !orb->cmd.c64 || orb->cmd.i2k)
+       if (!orb->cmd.pfch)
                return -EOPNOTSUPP;
 
        INIT_LIST_HEAD(&cp->ccwchain_list);
@@ -688,6 +694,10 @@ int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb)
        ret = ccwchain_loop_tic(chain, cp);
        if (ret)
                cp_unpin_free(cp);
+       /* It is safe to force: if not set but idals used
+        * ccwchain_calc_length returns an error.
+        */
+       cp->orb.cmd.c64 = 1;
 
        return ret;
 }
index ea6a2d0b2894decac95c3421c544183ee89c3383..770fa9cfc31041dd84a78a00f0f4135bef5a79ed 100644 (file)
@@ -177,6 +177,7 @@ static int vfio_ccw_sch_event(struct subchannel *sch, int process)
 {
        struct vfio_ccw_private *private = dev_get_drvdata(&sch->dev);
        unsigned long flags;
+       int rc = -EAGAIN;
 
        spin_lock_irqsave(sch->lock, flags);
        if (!device_is_registered(&sch->dev))
@@ -187,6 +188,7 @@ static int vfio_ccw_sch_event(struct subchannel *sch, int process)
 
        if (cio_update_schib(sch)) {
                vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_NOT_OPER);
+               rc = 0;
                goto out_unlock;
        }
 
@@ -195,11 +197,12 @@ static int vfio_ccw_sch_event(struct subchannel *sch, int process)
                private->state = private->mdev ? VFIO_CCW_STATE_IDLE :
                                 VFIO_CCW_STATE_STANDBY;
        }
+       rc = 0;
 
 out_unlock:
        spin_unlock_irqrestore(sch->lock, flags);
 
-       return 0;
+       return rc;
 }
 
 static struct css_device_id vfio_ccw_sch_ids[] = {
index 3c800642134e4330d62bb8c0053df62618840ff3..797a82731159a5f9f584810f924adc3467b1e702 100644 (file)
@@ -13,6 +13,9 @@
 #include "ioasm.h"
 #include "vfio_ccw_private.h"
 
+#define CREATE_TRACE_POINTS
+#include "vfio_ccw_trace.h"
+
 static int fsm_io_helper(struct vfio_ccw_private *private)
 {
        struct subchannel *sch;
@@ -110,6 +113,10 @@ static void fsm_disabled_irq(struct vfio_ccw_private *private,
         */
        cio_disable_subchannel(sch);
 }
+inline struct subchannel_id get_schid(struct vfio_ccw_private *p)
+{
+       return p->sch->schid;
+}
 
 /*
  * Deal with the ccw command request from the userspace.
@@ -121,6 +128,7 @@ static void fsm_io_request(struct vfio_ccw_private *private,
        union scsw *scsw = &private->scsw;
        struct ccw_io_region *io_region = &private->io_region;
        struct mdev_device *mdev = private->mdev;
+       char *errstr = "request";
 
        private->state = VFIO_CCW_STATE_BOXED;
 
@@ -132,15 +140,19 @@ static void fsm_io_request(struct vfio_ccw_private *private,
                /* Don't try to build a cp if transport mode is specified. */
                if (orb->tm.b) {
                        io_region->ret_code = -EOPNOTSUPP;
+                       errstr = "transport mode";
                        goto err_out;
                }
                io_region->ret_code = cp_init(&private->cp, mdev_dev(mdev),
                                              orb);
-               if (io_region->ret_code)
+               if (io_region->ret_code) {
+                       errstr = "cp init";
                        goto err_out;
+               }
 
                io_region->ret_code = cp_prefetch(&private->cp);
                if (io_region->ret_code) {
+                       errstr = "cp prefetch";
                        cp_free(&private->cp);
                        goto err_out;
                }
@@ -148,6 +160,7 @@ static void fsm_io_request(struct vfio_ccw_private *private,
                /* Start channel program and wait for I/O interrupt. */
                io_region->ret_code = fsm_io_helper(private);
                if (io_region->ret_code) {
+                       errstr = "cp fsm_io_helper";
                        cp_free(&private->cp);
                        goto err_out;
                }
@@ -164,6 +177,8 @@ static void fsm_io_request(struct vfio_ccw_private *private,
 
 err_out:
        private->state = VFIO_CCW_STATE_IDLE;
+       trace_vfio_ccw_io_fctl(scsw->cmd.fctl, get_schid(private),
+                              io_region->ret_code, errstr);
 }
 
 /*
diff --git a/drivers/s390/cio/vfio_ccw_trace.h b/drivers/s390/cio/vfio_ccw_trace.h
new file mode 100644 (file)
index 0000000..b1da53d
--- /dev/null
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Tracepoints for vfio_ccw driver
+ *
+ * Copyright IBM Corp. 2018
+ *
+ * Author(s): Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com>
+ *            Halil Pasic <pasic@linux.vnet.ibm.com>
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM vfio_ccw
+
+#if !defined(_VFIO_CCW_TRACE_) || defined(TRACE_HEADER_MULTI_READ)
+#define _VFIO_CCW_TRACE_
+
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(vfio_ccw_io_fctl,
+       TP_PROTO(int fctl, struct subchannel_id schid, int errno, char *errstr),
+       TP_ARGS(fctl, schid, errno, errstr),
+
+       TP_STRUCT__entry(
+               __field(int, fctl)
+               __field_struct(struct subchannel_id, schid)
+               __field(int, errno)
+               __field(char*, errstr)
+       ),
+
+       TP_fast_assign(
+               __entry->fctl = fctl;
+               __entry->schid = schid;
+               __entry->errno = errno;
+               __entry->errstr = errstr;
+       ),
+
+       TP_printk("schid=%x.%x.%04x fctl=%x errno=%d info=%s",
+                 __entry->schid.cssid,
+                 __entry->schid.ssid,
+                 __entry->schid.sch_no,
+                 __entry->fctl,
+                 __entry->errno,
+                 __entry->errstr)
+);
+
+#endif /* _VFIO_CCW_TRACE_ */
+
+/* This part must be outside protection */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE vfio_ccw_trace
+
+#include <trace/define_trace.h>
index 1754f55e2facfb4b21169a7c97ee514392c9eaa8..524f9ea62e52a0ed472b1177c57f7aa3b0f98f17 100644 (file)
@@ -30,7 +30,7 @@
  * the recommended way for applications to use the coprocessor, and
  * the driver interface is not intended for general use.
  *
- * See Documentation/sparc/oradax/oracle_dax.txt for more details.
+ * See Documentation/sparc/oradax/oracle-dax.txt for more details.
  */
 
 #include <linux/uaccess.h>
index a2b3430072c7e51f55604352f1d9141f5d7f3e2e..25f6600d6c090c45e9dfb6c7aabaadc7ffa72662 100644 (file)
@@ -845,7 +845,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
                                        rcode = -EINVAL;
                                        goto cleanup;
                                }
-                               p = kmalloc(sg_count[i], GFP_KERNEL|GFP_DMA32);
+                               p = kmalloc(sg_count[i], GFP_KERNEL);
                                if (!p) {
                                        dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
                                                sg_count[i], i, usg->count));
@@ -886,7 +886,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
                                        rcode = -EINVAL;
                                        goto cleanup;
                                }
-                               p = kmalloc(sg_count[i], GFP_KERNEL|GFP_DMA32);
+                               p = kmalloc(sg_count[i], GFP_KERNEL);
                                if (!p) {
                                        dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
                                          sg_count[i], i, upsg->count));
index 67d292dcc60766832a6c4edbb8f3971c94791215..2d82ec85753efc9628cbdf5faa7e1699e64113cb 100644 (file)
@@ -6112,10 +6112,6 @@ ahd_alloc(void *platform_arg, char *name)
        ahd->int_coalescing_stop_threshold =
            AHD_INT_COALESCING_STOP_THRESHOLD_DEFAULT;
 
-       if (ahd_platform_alloc(ahd, platform_arg) != 0) {
-               ahd_free(ahd);
-               ahd = NULL;
-       }
 #ifdef AHD_DEBUG
        if ((ahd_debug & AHD_SHOW_MEMORY) != 0) {
                printk("%s: scb size = 0x%x, hscb size = 0x%x\n",
@@ -6123,6 +6119,10 @@ ahd_alloc(void *platform_arg, char *name)
                       (u_int)sizeof(struct hardware_scb));
        }
 #endif
+       if (ahd_platform_alloc(ahd, platform_arg) != 0) {
+               ahd_free(ahd);
+               ahd = NULL;
+       }
        return (ahd);
 }
 
index af0e628ff39656ce5c4cc4828b1d40e6d9e2644a..15c7f3b6f35eecee2ca3ca88c16c63809c2791bf 100644 (file)
@@ -8871,7 +8871,7 @@ out:
        kfree(options);
 }
 
-static void hpsa_shutdown(struct pci_dev *pdev)
+static void __hpsa_shutdown(struct pci_dev *pdev)
 {
        struct ctlr_info *h;
 
@@ -8886,6 +8886,12 @@ static void hpsa_shutdown(struct pci_dev *pdev)
        hpsa_disable_interrupt_mode(h);         /* pci_init 2 */
 }
 
+static void hpsa_shutdown(struct pci_dev *pdev)
+{
+       __hpsa_shutdown(pdev);
+       pci_disable_device(pdev);
+}
+
 static void hpsa_free_device_info(struct ctlr_info *h)
 {
        int i;
@@ -8929,7 +8935,7 @@ static void hpsa_remove_one(struct pci_dev *pdev)
                scsi_remove_host(h->scsi_host);         /* init_one 8 */
        /* includes hpsa_free_irqs - init_one 4 */
        /* includes hpsa_disable_interrupt_mode - pci_init 2 */
-       hpsa_shutdown(pdev);
+       __hpsa_shutdown(pdev);
 
        hpsa_free_device_info(h);               /* scan */
 
index bf04fa90f4337174f7c5f8b99210fe9f7f556acb..569392d0d4c9e478b8e7d1fc745cb7e741005ff3 100644 (file)
@@ -3348,6 +3348,7 @@ _base_mpi_ep_writeq(__u64 b, volatile void __iomem *addr,
        spin_lock_irqsave(writeq_lock, flags);
        writel((u32)(data_out), addr);
        writel((u32)(data_out >> 32), (addr + 4));
+       mmiowb();
        spin_unlock_irqrestore(writeq_lock, flags);
 }
 
index fbbb328c64d57cd3c0ea3f2dd71e6623274314cf..7b675243bd16c61a703cffa69c0f5f0a55a62ea6 100644 (file)
@@ -5009,7 +5009,8 @@ qla2x00_iidma_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
                return;
 
        if (fcport->fp_speed == PORT_SPEED_UNKNOWN ||
-           fcport->fp_speed > ha->link_data_rate)
+           fcport->fp_speed > ha->link_data_rate ||
+           !ha->flags.gpsc_supported)
                return;
 
        rval = qla2x00_set_idma_speed(vha, fcport->loop_id, fcport->fp_speed,
index d14d3911516d5ff2051436b72dbc293b5da52691..9fa5a2557f2c7cc475430ed363ef3c7775768ef8 100644 (file)
@@ -2494,8 +2494,12 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                ox_id = le16_to_cpu(sts24->ox_id);
                par_sense_len = sizeof(sts24->data);
                /* Valid values of the retry delay timer are 0x1-0xffef */
-               if (sts24->retry_delay > 0 && sts24->retry_delay < 0xfff1)
-                       retry_delay = sts24->retry_delay;
+               if (sts24->retry_delay > 0 && sts24->retry_delay < 0xfff1) {
+                       retry_delay = sts24->retry_delay & 0x3fff;
+                       ql_dbg(ql_dbg_io, sp->vha, 0x3033,
+                           "%s: scope=%#x retry_delay=%#x\n", __func__,
+                           sts24->retry_delay >> 14, retry_delay);
+               }
        } else {
                if (scsi_status & SS_SENSE_LEN_VALID)
                        sense_len = le16_to_cpu(sts->req_sense_length);
index d8a36c13aedaf8606a4931287bb2879aee23dcae..7e875f5752299bdb6af02e542ba90362a399a5c7 100644 (file)
@@ -292,6 +292,14 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
                        if (time_after(jiffies, wait_time))
                                break;
 
+                       /*
+                        * Check if it's UNLOADING, cause we cannot poll in
+                        * this case, or else a NULL pointer dereference
+                        * is triggered.
+                        */
+                       if (unlikely(test_bit(UNLOADING, &base_vha->dpc_flags)))
+                               return QLA_FUNCTION_TIMEOUT;
+
                        /* Check for pending interrupts. */
                        qla2x00_poll(ha->rsp_q_map[0]);
 
index 76da8c3a6f097e21a75fda283acd3971791f9a5b..a14fef11776ec846c482178ee555c8122a598d22 100644 (file)
@@ -442,7 +442,7 @@ static s64 sd_zbc_check_zone_size(struct scsi_disk *sdkp)
                        } else if (this_zone_blocks != zone_blocks &&
                                   (block + this_zone_blocks < sdkp->capacity
                                    || this_zone_blocks > zone_blocks)) {
-                               this_zone_blocks = 0;
+                               zone_blocks = 0;
                                goto out;
                        }
                        block += this_zone_blocks;
index 17b314d9a148cb24bf252be3d76ee835c53c4dda..dc09d7ac905fff805bedb073e2a4e79529f88032 100644 (file)
@@ -50,7 +50,7 @@ ssize_t qcom_mdt_get_size(const struct firmware *fw)
        const struct elf32_phdr *phdrs;
        const struct elf32_phdr *phdr;
        const struct elf32_hdr *ehdr;
-       phys_addr_t min_addr = (phys_addr_t)ULLONG_MAX;
+       phys_addr_t min_addr = PHYS_ADDR_MAX;
        phys_addr_t max_addr = 0;
        int i;
 
@@ -97,7 +97,7 @@ int qcom_mdt_load(struct device *dev, const struct firmware *fw,
        const struct elf32_hdr *ehdr;
        const struct firmware *seg_fw;
        phys_addr_t mem_reloc;
-       phys_addr_t min_addr = (phys_addr_t)ULLONG_MAX;
+       phys_addr_t min_addr = PHYS_ADDR_MAX;
        phys_addr_t max_addr = 0;
        size_t fw_name_len;
        ssize_t offset;
index 8974a0fcda1bdb21872d6317ed954b1311e56ea2..4b5e250e86159f5585205498b8029d85abf39879 100644 (file)
@@ -1291,7 +1291,7 @@ restore_params:
  *
  * @stream: Soundwire stream
  *
- * Documentation/soundwire/stream.txt explains this API in detail
+ * Documentation/driver-api/soundwire/stream.rst explains this API in detail
  */
 int sdw_prepare_stream(struct sdw_stream_runtime *stream)
 {
@@ -1348,7 +1348,7 @@ static int _sdw_enable_stream(struct sdw_stream_runtime *stream)
  *
  * @stream: Soundwire stream
  *
- * Documentation/soundwire/stream.txt explains this API in detail
+ * Documentation/driver-api/soundwire/stream.rst explains this API in detail
  */
 int sdw_enable_stream(struct sdw_stream_runtime *stream)
 {
@@ -1400,7 +1400,7 @@ static int _sdw_disable_stream(struct sdw_stream_runtime *stream)
  *
  * @stream: Soundwire stream
  *
- * Documentation/soundwire/stream.txt explains this API in detail
+ * Documentation/driver-api/soundwire/stream.rst explains this API in detail
  */
 int sdw_disable_stream(struct sdw_stream_runtime *stream)
 {
@@ -1456,7 +1456,7 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
  *
  * @stream: Soundwire stream
  *
- * Documentation/soundwire/stream.txt explains this API in detail
+ * Documentation/driver-api/soundwire/stream.rst explains this API in detail
  */
 int sdw_deprepare_stream(struct sdw_stream_runtime *stream)
 {
index 0ba6771654f785776208b611ac93087e06818325..72ba9da3d179206562fad9add2a968a3c380e62e 100644 (file)
@@ -11,7 +11,7 @@ pool management for network interfaces.
 This document provides an overview the Linux DPIO driver, its
 subcomponents, and its APIs.
 
-See Documentation/dpaa2/overview.txt for a general overview of DPAA2
+See Documentation/networking/dpaa2/overview.rst for a general overview of DPAA2
 and the general DPAA2 driver architecture in Linux.
 
 Driver Overview
index 051f85dbe89e47677dc2834a87998e7162652bf2..6bee2a2dad68870586869d2ef18ee74db10d747d 100644 (file)
@@ -3,7 +3,7 @@ TODO:
 From the initial code review:
 
 The main thing you need to do is to implement all the controls using the
-control framework (see Documentation/video4linux/v4l2-controls.txt).
+control framework (see Documentation/media/kapi/v4l2-controls.rst).
 Most drivers are by now converted to the control framework, so you will
 find many examples of how to do this in drivers/media/radio.
 
index 63df5de5068debf057acd01d7a1b21a2db3fb343..34a18135ede00114a7dc3259b393fb5ef221b94a 100644 (file)
@@ -7,7 +7,7 @@ config VIDEO_ZORAN
          36057/36067 PCI controller chipset. This includes the Iomega
          Buz, Pinnacle DC10+ and the Linux Media Labs LML33. There is
          a driver homepage at <http://mjpeg.sf.net/driver-zoran/>. For
-         more information, check <file:Documentation/video4linux/Zoran>.
+         more information, check <file:Documentation/media/v4l-drivers/zoran.rst>.
 
          To compile this driver as a module, choose M here: the
          module will be called zr36067.
index 7c838b90a31d636865ce99a84466967d57b777aa..aba59521ad488973d0bee75f88a9d2a0f4f76e00 100644 (file)
@@ -867,8 +867,13 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
                i = -EIO;
        tty_ldisc_deref(ld);
 
-       if (i > 0)
-               tty_update_time(&inode->i_atime);
+       if (i > 0) {
+               struct timespec ts;
+
+               ts = timespec64_to_timespec(inode->i_atime);
+               tty_update_time(&ts);
+               inode->i_atime = timespec_to_timespec64(ts);
+       }
 
        return i;
 }
@@ -969,7 +974,11 @@ static inline ssize_t do_tty_write(
                cond_resched();
        }
        if (written) {
-               tty_update_time(&file_inode(file)->i_mtime);
+               struct timespec ts;
+
+               ts = timespec64_to_timespec(file_inode(file)->i_mtime);
+               tty_update_time(&ts);
+               file_inode(file)->i_mtime = timespec_to_timespec64(ts);
                ret = written;
        }
 out:
index 199d2570005051d34c3bee29da4230d4a3364804..dce9d12c7981afb1733be479e9daa43977bd218a 100644 (file)
@@ -1308,7 +1308,7 @@ ffs_sb_make_inode(struct super_block *sb, void *data,
        inode = new_inode(sb);
 
        if (likely(inode)) {
-               struct timespec ts = current_time(inode);
+               struct timespec64 ts = current_time(inode);
 
                inode->i_ino     = get_next_ino();
                inode->i_mode    = perms->mode;
index ce8c95b6365bbe020ed12078c1a7ae0c65c3cd96..a502f1af4a213607adec4aa28fa6ae8eb9ce0389 100644 (file)
@@ -2349,6 +2349,9 @@ struct vhost_msg_node *vhost_new_msg(struct vhost_virtqueue *vq, int type)
        struct vhost_msg_node *node = kmalloc(sizeof *node, GFP_KERNEL);
        if (!node)
                return NULL;
+
+       /* Make sure all padding within the structure is initialized. */
+       memset(&node->msg, 0, sizeof node->msg);
        node->vq = vq;
        node->msg.type = type;
        return node;
index d94254263ea5caa77887ceef92b9671fd38a4761..591a13a597874ec008430f00d448d9aab4a7b847 100644 (file)
@@ -1437,7 +1437,7 @@ config FB_SIS_315
 
 config FB_VIA
        tristate "VIA UniChrome (Pro) and Chrome9 display support"
-       depends on FB && PCI && X86 && GPIOLIB && I2C
+       depends on FB && PCI && GPIOLIB && I2C && (X86 || COMPILE_TEST)
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
@@ -1888,7 +1888,6 @@ config FB_W100
 config FB_SH_MOBILE_LCDC
        tristate "SuperH Mobile LCDC framebuffer support"
        depends on FB && (SUPERH || ARCH_RENESAS) && HAVE_CLK
-       depends on FB_SH_MOBILE_MERAM || !FB_SH_MOBILE_MERAM
        select FB_SYS_FILLRECT
        select FB_SYS_COPYAREA
        select FB_SYS_IMAGEBLIT
@@ -2253,39 +2252,6 @@ config FB_BROADSHEET
          and could also have been called by other names when coupled with
          a bridge adapter.
 
-config FB_AUO_K190X
-       tristate "AUO-K190X EPD controller support"
-       depends on FB
-       select FB_SYS_FILLRECT
-       select FB_SYS_COPYAREA
-       select FB_SYS_IMAGEBLIT
-       select FB_SYS_FOPS
-       select FB_DEFERRED_IO
-       help
-         Provides support for epaper controllers from the K190X series
-         of AUO. These controllers can be used to drive epaper displays
-         from Sipix.
-
-         This option enables the common support, shared by the individual
-         controller drivers. You will also have to enable the driver
-         for the controller type used in your device.
-
-config FB_AUO_K1900
-       tristate "AUO-K1900 EPD controller support"
-       depends on FB && FB_AUO_K190X
-       help
-         This driver implements support for the AUO K1900 epd-controller.
-         This controller can drive Sipix epaper displays but can only do
-         serial updates, reducing the number of possible frames per second.
-
-config FB_AUO_K1901
-       tristate "AUO-K1901 EPD controller support"
-       depends on FB && FB_AUO_K190X
-       help
-         This driver implements support for the AUO K1901 epd-controller.
-         This controller can drive Sipix epaper displays and supports
-         concurrent updates, making higher frames per second possible.
-
 config FB_JZ4740
        tristate "JZ4740 LCD framebuffer support"
        depends on FB && MACH_JZ4740
@@ -2346,18 +2312,6 @@ source "drivers/video/fbdev/omap/Kconfig"
 source "drivers/video/fbdev/omap2/Kconfig"
 source "drivers/video/fbdev/mmp/Kconfig"
 
-config FB_SH_MOBILE_MERAM
-       tristate "SuperH Mobile MERAM read ahead support"
-       depends on (SUPERH || ARCH_SHMOBILE)
-       select GENERIC_ALLOCATOR
-       ---help---
-         Enable MERAM support for the SuperH controller.
-
-         This will allow for caching of the framebuffer to provide more
-         reliable access under heavy main memory bus traffic situations.
-         Up to 4 memory channels can be configured, allowing 4 RGB or
-         2 YCbCr framebuffers to be configured.
-
 config FB_SSD1307
        tristate "Solomon SSD1307 framebuffer support"
        depends on FB && I2C
index 55282a21b50031da1b451b7f5911edad59003324..13c900320c2cc375593d02bd0aa99381d03a6f81 100644 (file)
@@ -100,9 +100,6 @@ obj-$(CONFIG_FB_PMAGB_B)      += pmagb-b-fb.o
 obj-$(CONFIG_FB_MAXINE)                  += maxinefb.o
 obj-$(CONFIG_FB_METRONOME)        += metronomefb.o
 obj-$(CONFIG_FB_BROADSHEET)       += broadsheetfb.o
-obj-$(CONFIG_FB_AUO_K190X)       += auo_k190x.o
-obj-$(CONFIG_FB_AUO_K1900)       += auo_k1900fb.o
-obj-$(CONFIG_FB_AUO_K1901)       += auo_k1901fb.o
 obj-$(CONFIG_FB_S1D13XXX)        += s1d13xxxfb.o
 obj-$(CONFIG_FB_SH7760)                  += sh7760fb.o
 obj-$(CONFIG_FB_IMX)              += imxfb.o
@@ -116,7 +113,6 @@ obj-$(CONFIG_FB_SM501)            += sm501fb.o
 obj-$(CONFIG_FB_UDL)             += udlfb.o
 obj-$(CONFIG_FB_SMSCUFX)         += smscufx.o
 obj-$(CONFIG_FB_XILINX)           += xilinxfb.o
-obj-$(CONFIG_FB_SH_MOBILE_MERAM)  += sh_mobile_meram.o
 obj-$(CONFIG_FB_SH_MOBILE_LCDC)          += sh_mobile_lcdcfb.o
 obj-$(CONFIG_FB_OMAP)             += omap/
 obj-y                             += omap2/
index 09b0e558dce81d7eea45f4f38fd148e70341837f..6cc46867ff579432d9112962417689d5ebce0b3f 100644 (file)
@@ -2442,7 +2442,7 @@ static void aty128_set_suspend(struct aty128fb_par *par, int suspend)
                (void)aty_ld_pll(POWER_MANAGEMENT);
                aty_st_le32(BUS_CNTL1, 0x00000010);
                aty_st_le32(MEM_POWER_MISC, 0x0c830000);
-               mdelay(100);
+               msleep(100);
 
                /* Switch PCI power management to D2 */
                pci_set_power_state(pdev, PCI_D2);
index 7137c12cbcee30ce60bbdcc27c62fdaf0c9cfbdc..e695adb0e5733db9e00f0934506a0af57de09601 100644 (file)
@@ -2678,17 +2678,17 @@ int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
                 * it, we'll restore the dynamic clocks state on wakeup
                 */
                radeon_pm_disable_dynamic_mode(rinfo);
-               mdelay(50);
+               msleep(50);
                radeon_pm_save_regs(rinfo, 1);
 
                if (rinfo->is_mobility && !(rinfo->pm_mode & radeon_pm_d2)) {
                        /* Switch off LVDS interface */
-                       mdelay(1);
+                       usleep_range(1000, 2000);
                        OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) & ~(LVDS_BL_MOD_EN));
-                       mdelay(1);
+                       usleep_range(1000, 2000);
                        OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) & ~(LVDS_EN | LVDS_ON));
                        OUTREG(LVDS_PLL_CNTL, (INREG(LVDS_PLL_CNTL) & ~30000) | 0x20000);
-                       mdelay(20);
+                       msleep(20);
                        OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) & ~(LVDS_DIGON));
                }
                pci_disable_device(pdev);
index d555a78df5c62292f5ccce4a6039d483fdb2016c..0adf0683cf081f8439935793ebd7ed24fa2cc8a3 100644 (file)
@@ -464,7 +464,7 @@ static int au1100fb_drv_probe(struct platform_device *dev)
                                            PAGE_ALIGN(fbdev->fb_len),
                                            &fbdev->fb_phys, GFP_KERNEL);
        if (!fbdev->fb_mem) {
-               print_err("fail to allocate frambuffer (size: %dK))",
+               print_err("fail to allocate framebuffer (size: %dK))",
                          fbdev->fb_len / 1024);
                return -ENOMEM;
        }
index 87d5a62bf6ca446fb8141b602c38839363dc120e..3872ccef4cb2c429a744e6dc4ea563e1c4b159c7 100644 (file)
@@ -1696,7 +1696,7 @@ static int au1200fb_drv_probe(struct platform_device *dev)
                                &fbdev->fb_phys, GFP_KERNEL,
                                DMA_ATTR_NON_CONSISTENT);
                if (!fbdev->fb_mem) {
-                       print_err("fail to allocate frambuffer (size: %dK))",
+                       print_err("fail to allocate framebuffer (size: %dK))",
                                  fbdev->fb_len / 1024);
                        ret = -ENOMEM;
                        goto failed;
diff --git a/drivers/video/fbdev/auo_k1900fb.c b/drivers/video/fbdev/auo_k1900fb.c
deleted file mode 100644 (file)
index 7637c60..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * auok190xfb.c -- FB driver for AUO-K1900 controllers
- *
- * Copyright (C) 2011, 2012 Heiko Stuebner <heiko@sntech.de>
- *
- * based on broadsheetfb.c
- *
- * Copyright (C) 2008, Jaya Kumar
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
- *
- * This driver is written to be used with the AUO-K1900 display controller.
- *
- * It is intended to be architecture independent. A board specific driver
- * must be used to perform all the physical IO interactions.
- *
- * The controller supports different update modes:
- * mode0+1 16 step gray (4bit)
- * mode2 4 step gray (2bit) - FIXME: add strange refresh
- * mode3 2 step gray (1bit) - FIXME: add strange refresh
- * mode4 handwriting mode (strange behaviour)
- * mode5 automatic selection of update mode
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/list.h>
-#include <linux/firmware.h>
-#include <linux/gpio.h>
-#include <linux/pm_runtime.h>
-
-#include <video/auo_k190xfb.h>
-
-#include "auo_k190x.h"
-
-/*
- * AUO-K1900 specific commands
- */
-
-#define AUOK1900_CMD_PARTIALDISP       0x1001
-#define AUOK1900_CMD_ROTATION          0x1006
-#define AUOK1900_CMD_LUT_STOP          0x1009
-
-#define AUOK1900_INIT_TEMP_AVERAGE     (1 << 13)
-#define AUOK1900_INIT_ROTATE(_x)       ((_x & 0x3) << 10)
-#define AUOK1900_INIT_RESOLUTION(_res) ((_res & 0x7) << 2)
-
-static void auok1900_init(struct auok190xfb_par *par)
-{
-       struct device *dev = par->info->device;
-       struct auok190x_board *board = par->board;
-       u16 init_param = 0;
-
-       pm_runtime_get_sync(dev);
-
-       init_param |= AUOK1900_INIT_TEMP_AVERAGE;
-       init_param |= AUOK1900_INIT_ROTATE(par->rotation);
-       init_param |= AUOK190X_INIT_INVERSE_WHITE;
-       init_param |= AUOK190X_INIT_FORMAT0;
-       init_param |= AUOK1900_INIT_RESOLUTION(par->resolution);
-       init_param |= AUOK190X_INIT_SHIFT_RIGHT;
-
-       auok190x_send_cmdargs(par, AUOK190X_CMD_INIT, 1, &init_param);
-
-       /* let the controller finish */
-       board->wait_for_rdy(par);
-
-       pm_runtime_mark_last_busy(dev);
-       pm_runtime_put_autosuspend(dev);
-}
-
-static void auok1900_update_region(struct auok190xfb_par *par, int mode,
-                                               u16 y1, u16 y2)
-{
-       struct device *dev = par->info->device;
-       unsigned char *buf = (unsigned char *)par->info->screen_base;
-       int xres = par->info->var.xres;
-       int line_length = par->info->fix.line_length;
-       u16 args[4];
-
-       pm_runtime_get_sync(dev);
-
-       mutex_lock(&(par->io_lock));
-
-       /* y1 and y2 must be a multiple of 2 so drop the lowest bit */
-       y1 &= 0xfffe;
-       y2 &= 0xfffe;
-
-       dev_dbg(dev, "update (x,y,w,h,mode)=(%d,%d,%d,%d,%d)\n",
-               1, y1+1, xres, y2-y1, mode);
-
-       /* to FIX handle different partial update modes */
-       args[0] = mode | 1;
-       args[1] = y1 + 1;
-       args[2] = xres;
-       args[3] = y2 - y1;
-       buf += y1 * line_length;
-       auok190x_send_cmdargs_pixels(par, AUOK1900_CMD_PARTIALDISP, 4, args,
-                                    ((y2 - y1) * line_length)/2, (u16 *) buf);
-       auok190x_send_command(par, AUOK190X_CMD_DATA_STOP);
-
-       par->update_cnt++;
-
-       mutex_unlock(&(par->io_lock));
-
-       pm_runtime_mark_last_busy(dev);
-       pm_runtime_put_autosuspend(dev);
-}
-
-static void auok1900fb_dpy_update_pages(struct auok190xfb_par *par,
-                                               u16 y1, u16 y2)
-{
-       int mode;
-
-       if (par->update_mode < 0) {
-               mode = AUOK190X_UPDATE_MODE(1);
-               par->last_mode = -1;
-       } else {
-               mode = AUOK190X_UPDATE_MODE(par->update_mode);
-               par->last_mode = par->update_mode;
-       }
-
-       if (par->flash)
-               mode |= AUOK190X_UPDATE_NONFLASH;
-
-       auok1900_update_region(par, mode, y1, y2);
-}
-
-static void auok1900fb_dpy_update(struct auok190xfb_par *par)
-{
-       int mode;
-
-       if (par->update_mode < 0) {
-               mode = AUOK190X_UPDATE_MODE(0);
-               par->last_mode = -1;
-       } else {
-               mode = AUOK190X_UPDATE_MODE(par->update_mode);
-               par->last_mode = par->update_mode;
-       }
-
-       if (par->flash)
-               mode |= AUOK190X_UPDATE_NONFLASH;
-
-       auok1900_update_region(par, mode, 0, par->info->var.yres);
-       par->update_cnt = 0;
-}
-
-static bool auok1900fb_need_refresh(struct auok190xfb_par *par)
-{
-       return (par->update_cnt > 10);
-}
-
-static int auok1900fb_probe(struct platform_device *pdev)
-{
-       struct auok190x_init_data init;
-       struct auok190x_board *board;
-
-       /* pick up board specific routines */
-       board = pdev->dev.platform_data;
-       if (!board)
-               return -EINVAL;
-
-       /* fill temporary init struct for common init */
-       init.id = "auo_k1900fb";
-       init.board = board;
-       init.update_partial = auok1900fb_dpy_update_pages;
-       init.update_all = auok1900fb_dpy_update;
-       init.need_refresh = auok1900fb_need_refresh;
-       init.init = auok1900_init;
-
-       return auok190x_common_probe(pdev, &init);
-}
-
-static int auok1900fb_remove(struct platform_device *pdev)
-{
-       return auok190x_common_remove(pdev);
-}
-
-static struct platform_driver auok1900fb_driver = {
-       .probe  = auok1900fb_probe,
-       .remove = auok1900fb_remove,
-       .driver = {
-               .name   = "auo_k1900fb",
-               .pm = &auok190x_pm,
-       },
-};
-module_platform_driver(auok1900fb_driver);
-
-MODULE_DESCRIPTION("framebuffer driver for the AUO-K1900 EPD controller");
-MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/auo_k1901fb.c b/drivers/video/fbdev/auo_k1901fb.c
deleted file mode 100644 (file)
index 681fe61..0000000
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * auok190xfb.c -- FB driver for AUO-K1901 controllers
- *
- * Copyright (C) 2011, 2012 Heiko Stuebner <heiko@sntech.de>
- *
- * based on broadsheetfb.c
- *
- * Copyright (C) 2008, Jaya Kumar
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
- *
- * This driver is written to be used with the AUO-K1901 display controller.
- *
- * It is intended to be architecture independent. A board specific driver
- * must be used to perform all the physical IO interactions.
- *
- * The controller supports different update modes:
- * mode0+1 16 step gray (4bit)
- * mode2+3 4 step gray (2bit)
- * mode4+5 2 step gray (1bit)
- * - mode4 is described as "without LUT"
- * mode7 automatic selection of update mode
- *
- * The most interesting difference to the K1900 is the ability to do screen
- * updates in an asynchronous fashion. Where the K1900 needs to wait for the
- * current update to complete, the K1901 can process later updates already.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/list.h>
-#include <linux/firmware.h>
-#include <linux/gpio.h>
-#include <linux/pm_runtime.h>
-
-#include <video/auo_k190xfb.h>
-
-#include "auo_k190x.h"
-
-/*
- * AUO-K1901 specific commands
- */
-
-#define AUOK1901_CMD_LUT_INTERFACE     0x0005
-#define AUOK1901_CMD_DMA_START         0x1001
-#define AUOK1901_CMD_CURSOR_START      0x1007
-#define AUOK1901_CMD_CURSOR_STOP       AUOK190X_CMD_DATA_STOP
-#define AUOK1901_CMD_DDMA_START                0x1009
-
-#define AUOK1901_INIT_GATE_PULSE_LOW   (0 << 14)
-#define AUOK1901_INIT_GATE_PULSE_HIGH  (1 << 14)
-#define AUOK1901_INIT_SINGLE_GATE      (0 << 13)
-#define AUOK1901_INIT_DOUBLE_GATE      (1 << 13)
-
-/* Bits to pixels
- *   Mode      15-12   11-8    7-4     3-0
- *   format2   2       T       1       T
- *   format3   1       T       2       T
- *   format4   T       2       T       1
- *   format5   T       1       T       2
- *
- *   halftone modes:
- *   format6   2       2       1       1
- *   format7   1       1       2       2
- */
-#define AUOK1901_INIT_FORMAT2          (1 << 7)
-#define AUOK1901_INIT_FORMAT3          ((1 << 7) | (1 << 6))
-#define AUOK1901_INIT_FORMAT4          (1 << 8)
-#define AUOK1901_INIT_FORMAT5          ((1 << 8) | (1 << 6))
-#define AUOK1901_INIT_FORMAT6          ((1 << 8) | (1 << 7))
-#define AUOK1901_INIT_FORMAT7          ((1 << 8) | (1 << 7) | (1 << 6))
-
-/* res[4] to bit 10
- * res[3-0] to bits 5-2
- */
-#define AUOK1901_INIT_RESOLUTION(_res) (((_res & (1 << 4)) << 6) \
-                                        | ((_res & 0xf) << 2))
-
-/*
- * portrait / landscape orientation in AUOK1901_CMD_DMA_START
- */
-#define AUOK1901_DMA_ROTATE90(_rot)            ((_rot & 1) << 13)
-
-/*
- * equivalent to 1 << 11, needs the ~ to have same rotation like K1900
- */
-#define AUOK1901_DDMA_ROTATE180(_rot)          ((~_rot & 2) << 10)
-
-static void auok1901_init(struct auok190xfb_par *par)
-{
-       struct device *dev = par->info->device;
-       struct auok190x_board *board = par->board;
-       u16 init_param = 0;
-
-       pm_runtime_get_sync(dev);
-
-       init_param |= AUOK190X_INIT_INVERSE_WHITE;
-       init_param |= AUOK190X_INIT_FORMAT0;
-       init_param |= AUOK1901_INIT_RESOLUTION(par->resolution);
-       init_param |= AUOK190X_INIT_SHIFT_LEFT;
-
-       auok190x_send_cmdargs(par, AUOK190X_CMD_INIT, 1, &init_param);
-
-       /* let the controller finish */
-       board->wait_for_rdy(par);
-
-       pm_runtime_mark_last_busy(dev);
-       pm_runtime_put_autosuspend(dev);
-}
-
-static void auok1901_update_region(struct auok190xfb_par *par, int mode,
-                                               u16 y1, u16 y2)
-{
-       struct device *dev = par->info->device;
-       unsigned char *buf = (unsigned char *)par->info->screen_base;
-       int xres = par->info->var.xres;
-       int line_length = par->info->fix.line_length;
-       u16 args[5];
-
-       pm_runtime_get_sync(dev);
-
-       mutex_lock(&(par->io_lock));
-
-       /* y1 and y2 must be a multiple of 2 so drop the lowest bit */
-       y1 &= 0xfffe;
-       y2 &= 0xfffe;
-
-       dev_dbg(dev, "update (x,y,w,h,mode)=(%d,%d,%d,%d,%d)\n",
-               1, y1+1, xres, y2-y1, mode);
-
-       /* K1901: first transfer the region data */
-       args[0] = AUOK1901_DMA_ROTATE90(par->rotation) | 1;
-       args[1] = y1 + 1;
-       args[2] = xres;
-       args[3] = y2 - y1;
-       buf += y1 * line_length;
-       auok190x_send_cmdargs_pixels_nowait(par, AUOK1901_CMD_DMA_START, 4,
-                                           args, ((y2 - y1) * line_length)/2,
-                                           (u16 *) buf);
-       auok190x_send_command_nowait(par, AUOK190X_CMD_DATA_STOP);
-
-       /* K1901: second tell the controller to update the region with mode */
-       args[0] = mode | AUOK1901_DDMA_ROTATE180(par->rotation);
-       args[1] = 1;
-       args[2] = y1 + 1;
-       args[3] = xres;
-       args[4] = y2 - y1;
-       auok190x_send_cmdargs_nowait(par, AUOK1901_CMD_DDMA_START, 5, args);
-
-       par->update_cnt++;
-
-       mutex_unlock(&(par->io_lock));
-
-       pm_runtime_mark_last_busy(dev);
-       pm_runtime_put_autosuspend(dev);
-}
-
-static void auok1901fb_dpy_update_pages(struct auok190xfb_par *par,
-                                               u16 y1, u16 y2)
-{
-       int mode;
-
-       if (par->update_mode < 0) {
-               mode = AUOK190X_UPDATE_MODE(1);
-               par->last_mode = -1;
-       } else {
-               mode = AUOK190X_UPDATE_MODE(par->update_mode);
-               par->last_mode = par->update_mode;
-       }
-
-       if (par->flash)
-               mode |= AUOK190X_UPDATE_NONFLASH;
-
-       auok1901_update_region(par, mode, y1, y2);
-}
-
-static void auok1901fb_dpy_update(struct auok190xfb_par *par)
-{
-       int mode;
-
-       /* When doing full updates, wait for the controller to be ready
-        * This will hopefully catch some hangs of the K1901
-        */
-       par->board->wait_for_rdy(par);
-
-       if (par->update_mode < 0) {
-               mode = AUOK190X_UPDATE_MODE(0);
-               par->last_mode = -1;
-       } else {
-               mode = AUOK190X_UPDATE_MODE(par->update_mode);
-               par->last_mode = par->update_mode;
-       }
-
-       if (par->flash)
-               mode |= AUOK190X_UPDATE_NONFLASH;
-
-       auok1901_update_region(par, mode, 0, par->info->var.yres);
-       par->update_cnt = 0;
-}
-
-static bool auok1901fb_need_refresh(struct auok190xfb_par *par)
-{
-       return (par->update_cnt > 10);
-}
-
-static int auok1901fb_probe(struct platform_device *pdev)
-{
-       struct auok190x_init_data init;
-       struct auok190x_board *board;
-
-       /* pick up board specific routines */
-       board = pdev->dev.platform_data;
-       if (!board)
-               return -EINVAL;
-
-       /* fill temporary init struct for common init */
-       init.id = "auo_k1901fb";
-       init.board = board;
-       init.update_partial = auok1901fb_dpy_update_pages;
-       init.update_all = auok1901fb_dpy_update;
-       init.need_refresh = auok1901fb_need_refresh;
-       init.init = auok1901_init;
-
-       return auok190x_common_probe(pdev, &init);
-}
-
-static int auok1901fb_remove(struct platform_device *pdev)
-{
-       return auok190x_common_remove(pdev);
-}
-
-static struct platform_driver auok1901fb_driver = {
-       .probe  = auok1901fb_probe,
-       .remove = auok1901fb_remove,
-       .driver = {
-               .name   = "auo_k1901fb",
-               .pm = &auok190x_pm,
-       },
-};
-module_platform_driver(auok1901fb_driver);
-
-MODULE_DESCRIPTION("framebuffer driver for the AUO-K1901 EPD controller");
-MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/auo_k190x.c b/drivers/video/fbdev/auo_k190x.c
deleted file mode 100644 (file)
index 9d24d1b..0000000
+++ /dev/null
@@ -1,1195 +0,0 @@
-/*
- * Common code for AUO-K190X framebuffer drivers
- *
- * Copyright (C) 2012 Heiko Stuebner <heiko@sntech.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/sched/mm.h>
-#include <linux/kernel.h>
-#include <linux/gpio.h>
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
-#include <linux/fb.h>
-#include <linux/delay.h>
-#include <linux/uaccess.h>
-#include <linux/vmalloc.h>
-#include <linux/regulator/consumer.h>
-
-#include <video/auo_k190xfb.h>
-
-#include "auo_k190x.h"
-
-struct panel_info {
-       int w;
-       int h;
-};
-
-/* table of panel specific parameters to be indexed into by the board drivers */
-static struct panel_info panel_table[] = {
-       /* standard 6" */
-       [AUOK190X_RESOLUTION_800_600] = {
-               .w = 800,
-               .h = 600,
-       },
-       /* standard 9" */
-       [AUOK190X_RESOLUTION_1024_768] = {
-               .w = 1024,
-               .h = 768,
-       },
-       [AUOK190X_RESOLUTION_600_800] = {
-               .w = 600,
-               .h = 800,
-       },
-       [AUOK190X_RESOLUTION_768_1024] = {
-               .w = 768,
-               .h = 1024,
-       },
-};
-
-/*
- * private I80 interface to the board driver
- */
-
-static void auok190x_issue_data(struct auok190xfb_par *par, u16 data)
-{
-       par->board->set_ctl(par, AUOK190X_I80_WR, 0);
-       par->board->set_hdb(par, data);
-       par->board->set_ctl(par, AUOK190X_I80_WR, 1);
-}
-
-static void auok190x_issue_cmd(struct auok190xfb_par *par, u16 data)
-{
-       par->board->set_ctl(par, AUOK190X_I80_DC, 0);
-       auok190x_issue_data(par, data);
-       par->board->set_ctl(par, AUOK190X_I80_DC, 1);
-}
-
-/**
- * Conversion of 16bit color to 4bit grayscale
- * does roughly (0.3 * R + 0.6 G + 0.1 B) / 2
- */
-static inline int rgb565_to_gray4(u16 data, struct fb_var_screeninfo *var)
-{
-       return ((((data & 0xF800) >> var->red.offset) * 77 +
-                ((data & 0x07E0) >> (var->green.offset + 1)) * 151 +
-                ((data & 0x1F) >> var->blue.offset) * 28) >> 8 >> 1);
-}
-
-static int auok190x_issue_pixels_rgb565(struct auok190xfb_par *par, int size,
-                                       u16 *data)
-{
-       struct fb_var_screeninfo *var = &par->info->var;
-       struct device *dev = par->info->device;
-       int i;
-       u16 tmp;
-
-       if (size & 7) {
-               dev_err(dev, "issue_pixels: size %d must be a multiple of 8\n",
-                       size);
-               return -EINVAL;
-       }
-
-       for (i = 0; i < (size >> 2); i++) {
-               par->board->set_ctl(par, AUOK190X_I80_WR, 0);
-
-               tmp  = (rgb565_to_gray4(data[4*i], var) & 0x000F);
-               tmp |= (rgb565_to_gray4(data[4*i+1], var) << 4) & 0x00F0;
-               tmp |= (rgb565_to_gray4(data[4*i+2], var) << 8) & 0x0F00;
-               tmp |= (rgb565_to_gray4(data[4*i+3], var) << 12) & 0xF000;
-
-               par->board->set_hdb(par, tmp);
-               par->board->set_ctl(par, AUOK190X_I80_WR, 1);
-       }
-
-       return 0;
-}
-
-static int auok190x_issue_pixels_gray8(struct auok190xfb_par *par, int size,
-                                      u16 *data)
-{
-       struct device *dev = par->info->device;
-       int i;
-       u16 tmp;
-
-       if (size & 3) {
-               dev_err(dev, "issue_pixels: size %d must be a multiple of 4\n",
-                       size);
-               return -EINVAL;
-       }
-
-       for (i = 0; i < (size >> 1); i++) {
-               par->board->set_ctl(par, AUOK190X_I80_WR, 0);
-
-               /* simple reduction of 8bit staticgray to 4bit gray
-                * combines 4 * 4bit pixel values into a 16bit value
-                */
-               tmp  = (data[2*i] & 0xF0) >> 4;
-               tmp |= (data[2*i] & 0xF000) >> 8;
-               tmp |= (data[2*i+1] & 0xF0) << 4;
-               tmp |= (data[2*i+1] & 0xF000);
-
-               par->board->set_hdb(par, tmp);
-               par->board->set_ctl(par, AUOK190X_I80_WR, 1);
-       }
-
-       return 0;
-}
-
-static int auok190x_issue_pixels(struct auok190xfb_par *par, int size,
-                                u16 *data)
-{
-       struct fb_info *info = par->info;
-       struct device *dev = par->info->device;
-
-       if (info->var.bits_per_pixel == 8 && info->var.grayscale)
-               auok190x_issue_pixels_gray8(par, size, data);
-       else if (info->var.bits_per_pixel == 16)
-               auok190x_issue_pixels_rgb565(par, size, data);
-       else
-               dev_err(dev, "unsupported color mode (bits: %d, gray: %d)\n",
-                       info->var.bits_per_pixel, info->var.grayscale);
-
-       return 0;
-}
-
-static u16 auok190x_read_data(struct auok190xfb_par *par)
-{
-       u16 data;
-
-       par->board->set_ctl(par, AUOK190X_I80_OE, 0);
-       data = par->board->get_hdb(par);
-       par->board->set_ctl(par, AUOK190X_I80_OE, 1);
-
-       return data;
-}
-
-/*
- * Command interface for the controller drivers
- */
-
-void auok190x_send_command_nowait(struct auok190xfb_par *par, u16 data)
-{
-       par->board->set_ctl(par, AUOK190X_I80_CS, 0);
-       auok190x_issue_cmd(par, data);
-       par->board->set_ctl(par, AUOK190X_I80_CS, 1);
-}
-EXPORT_SYMBOL_GPL(auok190x_send_command_nowait);
-
-void auok190x_send_cmdargs_nowait(struct auok190xfb_par *par, u16 cmd,
-                                 int argc, u16 *argv)
-{
-       int i;
-
-       par->board->set_ctl(par, AUOK190X_I80_CS, 0);
-       auok190x_issue_cmd(par, cmd);
-
-       for (i = 0; i < argc; i++)
-               auok190x_issue_data(par, argv[i]);
-       par->board->set_ctl(par, AUOK190X_I80_CS, 1);
-}
-EXPORT_SYMBOL_GPL(auok190x_send_cmdargs_nowait);
-
-int auok190x_send_command(struct auok190xfb_par *par, u16 data)
-{
-       int ret;
-
-       ret = par->board->wait_for_rdy(par);
-       if (ret)
-               return ret;
-
-       auok190x_send_command_nowait(par, data);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(auok190x_send_command);
-
-int auok190x_send_cmdargs(struct auok190xfb_par *par, u16 cmd,
-                          int argc, u16 *argv)
-{
-       int ret;
-
-       ret = par->board->wait_for_rdy(par);
-       if (ret)
-               return ret;
-
-       auok190x_send_cmdargs_nowait(par, cmd, argc, argv);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(auok190x_send_cmdargs);
-
-int auok190x_read_cmdargs(struct auok190xfb_par *par, u16 cmd,
-                          int argc, u16 *argv)
-{
-       int i, ret;
-
-       ret = par->board->wait_for_rdy(par);
-       if (ret)
-               return ret;
-
-       par->board->set_ctl(par, AUOK190X_I80_CS, 0);
-       auok190x_issue_cmd(par, cmd);
-
-       for (i = 0; i < argc; i++)
-               argv[i] = auok190x_read_data(par);
-       par->board->set_ctl(par, AUOK190X_I80_CS, 1);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(auok190x_read_cmdargs);
-
-void auok190x_send_cmdargs_pixels_nowait(struct auok190xfb_par *par, u16 cmd,
-                                 int argc, u16 *argv, int size, u16 *data)
-{
-       int i;
-
-       par->board->set_ctl(par, AUOK190X_I80_CS, 0);
-
-       auok190x_issue_cmd(par, cmd);
-
-       for (i = 0; i < argc; i++)
-               auok190x_issue_data(par, argv[i]);
-
-       auok190x_issue_pixels(par, size, data);
-
-       par->board->set_ctl(par, AUOK190X_I80_CS, 1);
-}
-EXPORT_SYMBOL_GPL(auok190x_send_cmdargs_pixels_nowait);
-
-int auok190x_send_cmdargs_pixels(struct auok190xfb_par *par, u16 cmd,
-                                 int argc, u16 *argv, int size, u16 *data)
-{
-       int ret;
-
-       ret = par->board->wait_for_rdy(par);
-       if (ret)
-               return ret;
-
-       auok190x_send_cmdargs_pixels_nowait(par, cmd, argc, argv, size, data);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(auok190x_send_cmdargs_pixels);
-
-/*
- * fbdefio callbacks - common on both controllers.
- */
-
-static void auok190xfb_dpy_first_io(struct fb_info *info)
-{
-       /* tell runtime-pm that we wish to use the device in a short time */
-       pm_runtime_get(info->device);
-}
-
-/* this is called back from the deferred io workqueue */
-static void auok190xfb_dpy_deferred_io(struct fb_info *info,
-                               struct list_head *pagelist)
-{
-       struct fb_deferred_io *fbdefio = info->fbdefio;
-       struct auok190xfb_par *par = info->par;
-       u16 line_length = info->fix.line_length;
-       u16 yres = info->var.yres;
-       u16 y1 = 0, h = 0;
-       int prev_index = -1;
-       struct page *cur;
-       int h_inc;
-       int threshold;
-
-       if (!list_empty(pagelist))
-               /* the device resume should've been requested through first_io,
-                * if the resume did not finish until now, wait for it.
-                */
-               pm_runtime_barrier(info->device);
-       else
-               /* We reached this via the fsync or some other way.
-                * In either case the first_io function did not run,
-                * so we runtime_resume the device here synchronously.
-                */
-               pm_runtime_get_sync(info->device);
-
-       /* Do a full screen update every n updates to prevent
-        * excessive darkening of the Sipix display.
-        * If we do this, there is no need to walk the pages.
-        */
-       if (par->need_refresh(par)) {
-               par->update_all(par);
-               goto out;
-       }
-
-       /* height increment is fixed per page */
-       h_inc = DIV_ROUND_UP(PAGE_SIZE , line_length);
-
-       /* calculate number of pages from pixel height */
-       threshold = par->consecutive_threshold / h_inc;
-       if (threshold < 1)
-               threshold = 1;
-
-       /* walk the written page list and swizzle the data */
-       list_for_each_entry(cur, &fbdefio->pagelist, lru) {
-               if (prev_index < 0) {
-                       /* just starting so assign first page */
-                       y1 = (cur->index << PAGE_SHIFT) / line_length;
-                       h = h_inc;
-               } else if ((cur->index - prev_index) <= threshold) {
-                       /* page is within our threshold for single updates */
-                       h += h_inc * (cur->index - prev_index);
-               } else {
-                       /* page not consecutive, issue previous update first */
-                       par->update_partial(par, y1, y1 + h);
-
-                       /* start over with our non consecutive page */
-                       y1 = (cur->index << PAGE_SHIFT) / line_length;
-                       h = h_inc;
-               }
-               prev_index = cur->index;
-       }
-
-       /* if we still have any pages to update we do so now */
-       if (h >= yres)
-               /* its a full screen update, just do it */
-               par->update_all(par);
-       else
-               par->update_partial(par, y1, min((u16) (y1 + h), yres));
-
-out:
-       pm_runtime_mark_last_busy(info->device);
-       pm_runtime_put_autosuspend(info->device);
-}
-
-/*
- * framebuffer operations
- */
-
-/*
- * this is the slow path from userspace. they can seek and write to
- * the fb. it's inefficient to do anything less than a full screen draw
- */
-static ssize_t auok190xfb_write(struct fb_info *info, const char __user *buf,
-                               size_t count, loff_t *ppos)
-{
-       struct auok190xfb_par *par = info->par;
-       unsigned long p = *ppos;
-       void *dst;
-       int err = 0;
-       unsigned long total_size;
-
-       if (info->state != FBINFO_STATE_RUNNING)
-               return -EPERM;
-
-       total_size = info->fix.smem_len;
-
-       if (p > total_size)
-               return -EFBIG;
-
-       if (count > total_size) {
-               err = -EFBIG;
-               count = total_size;
-       }
-
-       if (count + p > total_size) {
-               if (!err)
-                       err = -ENOSPC;
-
-               count = total_size - p;
-       }
-
-       dst = (void *)(info->screen_base + p);
-
-       if (copy_from_user(dst, buf, count))
-               err = -EFAULT;
-
-       if  (!err)
-               *ppos += count;
-
-       par->update_all(par);
-
-       return (err) ? err : count;
-}
-
-static void auok190xfb_fillrect(struct fb_info *info,
-                                  const struct fb_fillrect *rect)
-{
-       struct auok190xfb_par *par = info->par;
-
-       sys_fillrect(info, rect);
-
-       par->update_all(par);
-}
-
-static void auok190xfb_copyarea(struct fb_info *info,
-                                  const struct fb_copyarea *area)
-{
-       struct auok190xfb_par *par = info->par;
-
-       sys_copyarea(info, area);
-
-       par->update_all(par);
-}
-
-static void auok190xfb_imageblit(struct fb_info *info,
-                               const struct fb_image *image)
-{
-       struct auok190xfb_par *par = info->par;
-
-       sys_imageblit(info, image);
-
-       par->update_all(par);
-}
-
-static int auok190xfb_check_var(struct fb_var_screeninfo *var,
-                                  struct fb_info *info)
-{
-       struct device *dev = info->device;
-       struct auok190xfb_par *par = info->par;
-       struct panel_info *panel = &panel_table[par->resolution];
-       int size;
-
-       /*
-        * Color depth
-        */
-
-       if (var->bits_per_pixel == 8 && var->grayscale == 1) {
-               /*
-                * For 8-bit grayscale, R, G, and B offset are equal.
-                */
-               var->red.length = 8;
-               var->red.offset = 0;
-               var->red.msb_right = 0;
-
-               var->green.length = 8;
-               var->green.offset = 0;
-               var->green.msb_right = 0;
-
-               var->blue.length = 8;
-               var->blue.offset = 0;
-               var->blue.msb_right = 0;
-
-               var->transp.length = 0;
-               var->transp.offset = 0;
-               var->transp.msb_right = 0;
-       } else if (var->bits_per_pixel == 16) {
-               var->red.length = 5;
-               var->red.offset = 11;
-               var->red.msb_right = 0;
-
-               var->green.length = 6;
-               var->green.offset = 5;
-               var->green.msb_right = 0;
-
-               var->blue.length = 5;
-               var->blue.offset = 0;
-               var->blue.msb_right = 0;
-
-               var->transp.length = 0;
-               var->transp.offset = 0;
-               var->transp.msb_right = 0;
-       } else {
-               dev_warn(dev, "unsupported color mode (bits: %d, grayscale: %d)\n",
-                       info->var.bits_per_pixel, info->var.grayscale);
-               return -EINVAL;
-       }
-
-       /*
-        * Dimensions
-        */
-
-       switch (var->rotate) {
-       case FB_ROTATE_UR:
-       case FB_ROTATE_UD:
-               var->xres = panel->w;
-               var->yres = panel->h;
-               break;
-       case FB_ROTATE_CW:
-       case FB_ROTATE_CCW:
-               var->xres = panel->h;
-               var->yres = panel->w;
-               break;
-       default:
-               dev_dbg(dev, "Invalid rotation request\n");
-               return -EINVAL;
-       }
-
-       var->xres_virtual = var->xres;
-       var->yres_virtual = var->yres;
-
-       /*
-        *  Memory limit
-        */
-
-       size = var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8;
-       if (size > info->fix.smem_len) {
-               dev_err(dev, "Memory limit exceeded, requested %dK\n",
-                       size >> 10);
-               return -ENOMEM;
-       }
-
-       return 0;
-}
-
-static int auok190xfb_set_fix(struct fb_info *info)
-{
-       struct fb_fix_screeninfo *fix = &info->fix;
-       struct fb_var_screeninfo *var = &info->var;
-
-       fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
-
-       fix->type = FB_TYPE_PACKED_PIXELS;
-       fix->accel = FB_ACCEL_NONE;
-       fix->visual = (var->grayscale) ? FB_VISUAL_STATIC_PSEUDOCOLOR
-                                      : FB_VISUAL_TRUECOLOR;
-       fix->xpanstep = 0;
-       fix->ypanstep = 0;
-       fix->ywrapstep = 0;
-
-       return 0;
-}
-
-static int auok190xfb_set_par(struct fb_info *info)
-{
-       struct auok190xfb_par *par = info->par;
-
-       par->rotation = info->var.rotate;
-       auok190xfb_set_fix(info);
-
-       /* reinit the controller to honor the rotation */
-       par->init(par);
-
-       /* wait for init to complete */
-       par->board->wait_for_rdy(par);
-
-       return 0;
-}
-
-static struct fb_ops auok190xfb_ops = {
-       .owner          = THIS_MODULE,
-       .fb_read        = fb_sys_read,
-       .fb_write       = auok190xfb_write,
-       .fb_fillrect    = auok190xfb_fillrect,
-       .fb_copyarea    = auok190xfb_copyarea,
-       .fb_imageblit   = auok190xfb_imageblit,
-       .fb_check_var   = auok190xfb_check_var,
-       .fb_set_par     = auok190xfb_set_par,
-};
-
-/*
- * Controller-functions common to both K1900 and K1901
- */
-
-static int auok190x_read_temperature(struct auok190xfb_par *par)
-{
-       struct device *dev = par->info->device;
-       u16 data[4];
-       int temp;
-
-       pm_runtime_get_sync(dev);
-
-       mutex_lock(&(par->io_lock));
-
-       auok190x_read_cmdargs(par, AUOK190X_CMD_READ_VERSION, 4, data);
-
-       mutex_unlock(&(par->io_lock));
-
-       pm_runtime_mark_last_busy(dev);
-       pm_runtime_put_autosuspend(dev);
-
-       /* sanitize and split of half-degrees for now */
-       temp = ((data[0] & AUOK190X_VERSION_TEMP_MASK) >> 1);
-
-       /* handle positive and negative temperatures */
-       if (temp >= 201)
-               return (255 - temp + 1) * (-1);
-       else
-               return temp;
-}
-
-static void auok190x_identify(struct auok190xfb_par *par)
-{
-       struct device *dev = par->info->device;
-       u16 data[4];
-
-       pm_runtime_get_sync(dev);
-
-       mutex_lock(&(par->io_lock));
-
-       auok190x_read_cmdargs(par, AUOK190X_CMD_READ_VERSION, 4, data);
-
-       mutex_unlock(&(par->io_lock));
-
-       par->epd_type = data[1] & AUOK190X_VERSION_TEMP_MASK;
-
-       par->panel_size_int = AUOK190X_VERSION_SIZE_INT(data[2]);
-       par->panel_size_float = AUOK190X_VERSION_SIZE_FLOAT(data[2]);
-       par->panel_model = AUOK190X_VERSION_MODEL(data[2]);
-
-       par->tcon_version = AUOK190X_VERSION_TCON(data[3]);
-       par->lut_version = AUOK190X_VERSION_LUT(data[3]);
-
-       dev_dbg(dev, "panel %d.%din, model 0x%x, EPD 0x%x TCON-rev 0x%x, LUT-rev 0x%x",
-               par->panel_size_int, par->panel_size_float, par->panel_model,
-               par->epd_type, par->tcon_version, par->lut_version);
-
-       pm_runtime_mark_last_busy(dev);
-       pm_runtime_put_autosuspend(dev);
-}
-
-/*
- * Sysfs functions
- */
-
-static ssize_t update_mode_show(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       struct fb_info *info = dev_get_drvdata(dev);
-       struct auok190xfb_par *par = info->par;
-
-       return sprintf(buf, "%d\n", par->update_mode);
-}
-
-static ssize_t update_mode_store(struct device *dev,
-                                struct device_attribute *attr,
-                                const char *buf, size_t count)
-{
-       struct fb_info *info = dev_get_drvdata(dev);
-       struct auok190xfb_par *par = info->par;
-       int mode, ret;
-
-       ret = kstrtoint(buf, 10, &mode);
-       if (ret)
-               return ret;
-
-       par->update_mode = mode;
-
-       /* if we enter a better mode, do a full update */
-       if (par->last_mode > 1 && mode < par->last_mode)
-               par->update_all(par);
-
-       return count;
-}
-
-static ssize_t flash_show(struct device *dev, struct device_attribute *attr,
-                         char *buf)
-{
-       struct fb_info *info = dev_get_drvdata(dev);
-       struct auok190xfb_par *par = info->par;
-
-       return sprintf(buf, "%d\n", par->flash);
-}
-
-static ssize_t flash_store(struct device *dev, struct device_attribute *attr,
-                          const char *buf, size_t count)
-{
-       struct fb_info *info = dev_get_drvdata(dev);
-       struct auok190xfb_par *par = info->par;
-       int flash, ret;
-
-       ret = kstrtoint(buf, 10, &flash);
-       if (ret)
-               return ret;
-
-       if (flash > 0)
-               par->flash = 1;
-       else
-               par->flash = 0;
-
-       return count;
-}
-
-static ssize_t temp_show(struct device *dev, struct device_attribute *attr,
-                        char *buf)
-{
-       struct fb_info *info = dev_get_drvdata(dev);
-       struct auok190xfb_par *par = info->par;
-       int temp;
-
-       temp = auok190x_read_temperature(par);
-       return sprintf(buf, "%d\n", temp);
-}
-
-static DEVICE_ATTR_RW(update_mode);
-static DEVICE_ATTR_RW(flash);
-static DEVICE_ATTR(temp, 0644, temp_show, NULL);
-
-static struct attribute *auok190x_attributes[] = {
-       &dev_attr_update_mode.attr,
-       &dev_attr_flash.attr,
-       &dev_attr_temp.attr,
-       NULL
-};
-
-static const struct attribute_group auok190x_attr_group = {
-       .attrs          = auok190x_attributes,
-};
-
-static int auok190x_power(struct auok190xfb_par *par, bool on)
-{
-       struct auok190x_board *board = par->board;
-       int ret;
-
-       if (on) {
-               /* We should maintain POWER up for at least 80ms before set
-                * RST_N and SLP_N to high (TCON spec 20100803_v35 p59)
-                */
-               ret = regulator_enable(par->regulator);
-               if (ret)
-                       return ret;
-
-               msleep(200);
-               gpio_set_value(board->gpio_nrst, 1);
-               gpio_set_value(board->gpio_nsleep, 1);
-               msleep(200);
-       } else {
-               regulator_disable(par->regulator);
-               gpio_set_value(board->gpio_nrst, 0);
-               gpio_set_value(board->gpio_nsleep, 0);
-       }
-
-       return 0;
-}
-
-/*
- * Recovery - powercycle the controller
- */
-
-static void auok190x_recover(struct auok190xfb_par *par)
-{
-       struct device *dev = par->info->device;
-
-       auok190x_power(par, 0);
-       msleep(100);
-       auok190x_power(par, 1);
-
-       /* after powercycling the device, it's always active */
-       pm_runtime_set_active(dev);
-       par->standby = 0;
-
-       par->init(par);
-
-       /* wait for init to complete */
-       par->board->wait_for_rdy(par);
-}
-
-/*
- * Power-management
- */
-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);
-       struct auok190xfb_par *par = info->par;
-       struct auok190x_board *board = par->board;
-       u16 standby_param;
-
-       /* take and keep the lock until we are resumed, as the controller
-        * will never reach the non-busy state when in standby mode
-        */
-       mutex_lock(&(par->io_lock));
-
-       if (par->standby) {
-               dev_warn(dev, "already in standby, runtime-pm pairing mismatch\n");
-               mutex_unlock(&(par->io_lock));
-               return 0;
-       }
-
-       /* according to runtime_pm.txt runtime_suspend only means, that the
-        * device will not process data and will not communicate with the CPU
-        * As we hold the lock, this stays true even without standby
-        */
-       if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) {
-               dev_dbg(dev, "runtime suspend without standby\n");
-               goto finish;
-       } else if (board->quirks & AUOK190X_QUIRK_STANDBYPARAM) {
-               /* for some TCON versions STANDBY expects a parameter (0) but
-                * it seems the real tcon version has to be determined yet.
-                */
-               dev_dbg(dev, "runtime suspend with additional empty param\n");
-               standby_param = 0;
-               auok190x_send_cmdargs(par, AUOK190X_CMD_STANDBY, 1,
-                                     &standby_param);
-       } else {
-               dev_dbg(dev, "runtime suspend without param\n");
-               auok190x_send_command(par, AUOK190X_CMD_STANDBY);
-       }
-
-       msleep(64);
-
-finish:
-       par->standby = 1;
-
-       return 0;
-}
-
-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);
-       struct auok190xfb_par *par = info->par;
-       struct auok190x_board *board = par->board;
-
-       if (!par->standby) {
-               dev_warn(dev, "not in standby, runtime-pm pairing mismatch\n");
-               return 0;
-       }
-
-       if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) {
-               dev_dbg(dev, "runtime resume without standby\n");
-       } else {
-               /* when in standby, controller is always busy
-                * and only accepts the wakeup command
-                */
-               dev_dbg(dev, "runtime resume from standby\n");
-               auok190x_send_command_nowait(par, AUOK190X_CMD_WAKEUP);
-
-               msleep(160);
-
-               /* wait for the controller to be ready and release the lock */
-               board->wait_for_rdy(par);
-       }
-
-       par->standby = 0;
-
-       mutex_unlock(&(par->io_lock));
-
-       return 0;
-}
-
-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);
-       struct auok190xfb_par *par = info->par;
-       struct auok190x_board *board = par->board;
-       int ret;
-
-       dev_dbg(dev, "suspend\n");
-       if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) {
-               /* suspend via powering off the ic */
-               dev_dbg(dev, "suspend with broken standby\n");
-
-               auok190x_power(par, 0);
-       } else {
-               dev_dbg(dev, "suspend using sleep\n");
-
-               /* the sleep state can only be entered from the standby state.
-                * pm_runtime_get_noresume gets called before the suspend call.
-                * So the devices usage count is >0 but it is not necessarily
-                * active.
-                */
-               if (!pm_runtime_status_suspended(dev)) {
-                       ret = auok190x_runtime_suspend(dev);
-                       if (ret < 0) {
-                               dev_err(dev, "auok190x_runtime_suspend failed with %d\n",
-                                       ret);
-                               return ret;
-                       }
-                       par->manual_standby = 1;
-               }
-
-               gpio_direction_output(board->gpio_nsleep, 0);
-       }
-
-       msleep(100);
-
-       return 0;
-}
-
-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);
-       struct auok190xfb_par *par = info->par;
-       struct auok190x_board *board = par->board;
-
-       dev_dbg(dev, "resume\n");
-       if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) {
-               dev_dbg(dev, "resume with broken standby\n");
-
-               auok190x_power(par, 1);
-
-               par->init(par);
-       } else {
-               dev_dbg(dev, "resume from sleep\n");
-
-               /* device should be in runtime suspend when we were suspended
-                * and pm_runtime_put_sync gets called after this function.
-                * So there is no need to touch the standby mode here at all.
-                */
-               gpio_direction_output(board->gpio_nsleep, 1);
-               msleep(100);
-
-               /* an additional init call seems to be necessary after sleep */
-               auok190x_runtime_resume(dev);
-               par->init(par);
-
-               /* if we were runtime-suspended before, suspend again*/
-               if (!par->manual_standby)
-                       auok190x_runtime_suspend(dev);
-               else
-                       par->manual_standby = 0;
-       }
-
-       return 0;
-}
-
-const struct dev_pm_ops auok190x_pm = {
-       SET_RUNTIME_PM_OPS(auok190x_runtime_suspend, auok190x_runtime_resume,
-                          NULL)
-       SET_SYSTEM_SLEEP_PM_OPS(auok190x_suspend, auok190x_resume)
-};
-EXPORT_SYMBOL_GPL(auok190x_pm);
-
-/*
- * Common probe and remove code
- */
-
-int auok190x_common_probe(struct platform_device *pdev,
-                         struct auok190x_init_data *init)
-{
-       struct auok190x_board *board = init->board;
-       struct auok190xfb_par *par;
-       struct fb_info *info;
-       struct panel_info *panel;
-       int videomemorysize, ret;
-       unsigned char *videomemory;
-
-       /* check board contents */
-       if (!board->init || !board->cleanup || !board->wait_for_rdy
-           || !board->set_ctl || !board->set_hdb || !board->get_hdb
-           || !board->setup_irq)
-               return -EINVAL;
-
-       info = framebuffer_alloc(sizeof(struct auok190xfb_par), &pdev->dev);
-       if (!info)
-               return -ENOMEM;
-
-       par = info->par;
-       par->info = info;
-       par->board = board;
-       par->recover = auok190x_recover;
-       par->update_partial = init->update_partial;
-       par->update_all = init->update_all;
-       par->need_refresh = init->need_refresh;
-       par->init = init->init;
-
-       /* init update modes */
-       par->update_cnt = 0;
-       par->update_mode = -1;
-       par->last_mode = -1;
-       par->flash = 0;
-
-       par->regulator = regulator_get(info->device, "vdd");
-       if (IS_ERR(par->regulator)) {
-               ret = PTR_ERR(par->regulator);
-               dev_err(info->device, "Failed to get regulator: %d\n", ret);
-               goto err_reg;
-       }
-
-       ret = board->init(par);
-       if (ret) {
-               dev_err(info->device, "board init failed, %d\n", ret);
-               goto err_board;
-       }
-
-       ret = gpio_request(board->gpio_nsleep, "AUOK190x sleep");
-       if (ret) {
-               dev_err(info->device, "could not request sleep gpio, %d\n",
-                       ret);
-               goto err_gpio1;
-       }
-
-       ret = gpio_direction_output(board->gpio_nsleep, 0);
-       if (ret) {
-               dev_err(info->device, "could not set sleep gpio, %d\n", ret);
-               goto err_gpio2;
-       }
-
-       ret = gpio_request(board->gpio_nrst, "AUOK190x reset");
-       if (ret) {
-               dev_err(info->device, "could not request reset gpio, %d\n",
-                       ret);
-               goto err_gpio2;
-       }
-
-       ret = gpio_direction_output(board->gpio_nrst, 0);
-       if (ret) {
-               dev_err(info->device, "could not set reset gpio, %d\n", ret);
-               goto err_gpio3;
-       }
-
-       ret = auok190x_power(par, 1);
-       if (ret) {
-               dev_err(info->device, "could not power on the device, %d\n",
-                       ret);
-               goto err_gpio3;
-       }
-
-       mutex_init(&par->io_lock);
-
-       init_waitqueue_head(&par->waitq);
-
-       ret = par->board->setup_irq(par->info);
-       if (ret) {
-               dev_err(info->device, "could not setup ready-irq, %d\n", ret);
-               goto err_irq;
-       }
-
-       /* wait for init to complete */
-       par->board->wait_for_rdy(par);
-
-       /*
-        * From here on the controller can talk to us
-        */
-
-       /* initialise fix, var, resolution and rotation */
-
-       strlcpy(info->fix.id, init->id, 16);
-       info->var.bits_per_pixel = 8;
-       info->var.grayscale = 1;
-
-       panel = &panel_table[board->resolution];
-
-       par->resolution = board->resolution;
-       par->rotation = 0;
-
-       /* videomemory handling */
-
-       videomemorysize = roundup((panel->w * panel->h) * 2, PAGE_SIZE);
-       videomemory = vzalloc(videomemorysize);
-       if (!videomemory) {
-               ret = -ENOMEM;
-               goto err_irq;
-       }
-
-       info->screen_base = (char *)videomemory;
-       info->fix.smem_len = videomemorysize;
-
-       info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB;
-       info->fbops = &auok190xfb_ops;
-
-       ret = auok190xfb_check_var(&info->var, info);
-       if (ret)
-               goto err_defio;
-
-       auok190xfb_set_fix(info);
-
-       /* deferred io init */
-
-       info->fbdefio = devm_kzalloc(info->device,
-                                    sizeof(struct fb_deferred_io),
-                                    GFP_KERNEL);
-       if (!info->fbdefio) {
-               dev_err(info->device, "Failed to allocate memory\n");
-               ret = -ENOMEM;
-               goto err_defio;
-       }
-
-       dev_dbg(info->device, "targeting %d frames per second\n", board->fps);
-       info->fbdefio->delay = HZ / board->fps;
-       info->fbdefio->first_io = auok190xfb_dpy_first_io,
-       info->fbdefio->deferred_io = auok190xfb_dpy_deferred_io,
-       fb_deferred_io_init(info);
-
-       /* color map */
-
-       ret = fb_alloc_cmap(&info->cmap, 256, 0);
-       if (ret < 0) {
-               dev_err(info->device, "Failed to allocate colormap\n");
-               goto err_cmap;
-       }
-
-       /* controller init */
-
-       par->consecutive_threshold = 100;
-       par->init(par);
-       auok190x_identify(par);
-
-       platform_set_drvdata(pdev, info);
-
-       ret = register_framebuffer(info);
-       if (ret < 0)
-               goto err_regfb;
-
-       ret = sysfs_create_group(&info->device->kobj, &auok190x_attr_group);
-       if (ret)
-               goto err_sysfs;
-
-       dev_info(info->device, "fb%d: %dx%d using %dK of video memory\n",
-                info->node, info->var.xres, info->var.yres,
-                videomemorysize >> 10);
-
-       /* increase autosuspend_delay when we use alternative methods
-        * for runtime_pm
-        */
-       par->autosuspend_delay = (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN)
-                                       ? 1000 : 200;
-
-       pm_runtime_set_active(info->device);
-       pm_runtime_enable(info->device);
-       pm_runtime_set_autosuspend_delay(info->device, par->autosuspend_delay);
-       pm_runtime_use_autosuspend(info->device);
-
-       return 0;
-
-err_sysfs:
-       unregister_framebuffer(info);
-err_regfb:
-       fb_dealloc_cmap(&info->cmap);
-err_cmap:
-       fb_deferred_io_cleanup(info);
-err_defio:
-       vfree((void *)info->screen_base);
-err_irq:
-       auok190x_power(par, 0);
-err_gpio3:
-       gpio_free(board->gpio_nrst);
-err_gpio2:
-       gpio_free(board->gpio_nsleep);
-err_gpio1:
-       board->cleanup(par);
-err_board:
-       regulator_put(par->regulator);
-err_reg:
-       framebuffer_release(info);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(auok190x_common_probe);
-
-int  auok190x_common_remove(struct platform_device *pdev)
-{
-       struct fb_info *info = platform_get_drvdata(pdev);
-       struct auok190xfb_par *par = info->par;
-       struct auok190x_board *board = par->board;
-
-       pm_runtime_disable(info->device);
-
-       sysfs_remove_group(&info->device->kobj, &auok190x_attr_group);
-
-       unregister_framebuffer(info);
-
-       fb_dealloc_cmap(&info->cmap);
-
-       fb_deferred_io_cleanup(info);
-
-       vfree((void *)info->screen_base);
-
-       auok190x_power(par, 0);
-
-       gpio_free(board->gpio_nrst);
-       gpio_free(board->gpio_nsleep);
-
-       board->cleanup(par);
-
-       regulator_put(par->regulator);
-
-       framebuffer_release(info);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(auok190x_common_remove);
-
-MODULE_DESCRIPTION("Common code for AUO-K190X controllers");
-MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/auo_k190x.h b/drivers/video/fbdev/auo_k190x.h
deleted file mode 100644 (file)
index e35af1f..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Private common definitions for AUO-K190X framebuffer drivers
- *
- * Copyright (C) 2012 Heiko Stuebner <heiko@sntech.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/*
- * I80 interface specific defines
- */
-
-#define AUOK190X_I80_CS                        0x01
-#define AUOK190X_I80_DC                        0x02
-#define AUOK190X_I80_WR                        0x03
-#define AUOK190X_I80_OE                        0x04
-
-/*
- * AUOK190x commands, common to both controllers
- */
-
-#define AUOK190X_CMD_INIT              0x0000
-#define AUOK190X_CMD_STANDBY           0x0001
-#define AUOK190X_CMD_WAKEUP            0x0002
-#define AUOK190X_CMD_TCON_RESET                0x0003
-#define AUOK190X_CMD_DATA_STOP         0x1002
-#define AUOK190X_CMD_LUT_START         0x1003
-#define AUOK190X_CMD_DISP_REFRESH      0x1004
-#define AUOK190X_CMD_DISP_RESET                0x1005
-#define AUOK190X_CMD_PRE_DISPLAY_START 0x100D
-#define AUOK190X_CMD_PRE_DISPLAY_STOP  0x100F
-#define AUOK190X_CMD_FLASH_W           0x2000
-#define AUOK190X_CMD_FLASH_E           0x2001
-#define AUOK190X_CMD_FLASH_STS         0x2002
-#define AUOK190X_CMD_FRAMERATE         0x3000
-#define AUOK190X_CMD_READ_VERSION      0x4000
-#define AUOK190X_CMD_READ_STATUS       0x4001
-#define AUOK190X_CMD_READ_LUT          0x4003
-#define AUOK190X_CMD_DRIVERTIMING      0x5000
-#define AUOK190X_CMD_LBALANCE          0x5001
-#define AUOK190X_CMD_AGINGMODE         0x6000
-#define AUOK190X_CMD_AGINGEXIT         0x6001
-
-/*
- * Common settings for AUOK190X_CMD_INIT
- */
-
-#define AUOK190X_INIT_DATA_FILTER      (0 << 12)
-#define AUOK190X_INIT_DATA_BYPASS      (1 << 12)
-#define AUOK190X_INIT_INVERSE_WHITE    (0 << 9)
-#define AUOK190X_INIT_INVERSE_BLACK    (1 << 9)
-#define AUOK190X_INIT_SCAN_DOWN                (0 << 1)
-#define AUOK190X_INIT_SCAN_UP          (1 << 1)
-#define AUOK190X_INIT_SHIFT_LEFT       (0 << 0)
-#define AUOK190X_INIT_SHIFT_RIGHT      (1 << 0)
-
-/* Common bits to pixels
- *   Mode      15-12   11-8    7-4     3-0
- *   format0   4       3       2       1
- *   format1   3       4       1       2
- */
-
-#define AUOK190X_INIT_FORMAT0          0
-#define AUOK190X_INIT_FORMAT1          (1 << 6)
-
-/*
- * settings for AUOK190X_CMD_RESET
- */
-
-#define AUOK190X_RESET_TCON            (0 << 0)
-#define AUOK190X_RESET_NORMAL          (1 << 0)
-#define AUOK190X_RESET_PON             (1 << 1)
-
-/*
- * AUOK190X_CMD_VERSION
- */
-
-#define AUOK190X_VERSION_TEMP_MASK             (0x1ff)
-#define AUOK190X_VERSION_EPD_MASK              (0xff)
-#define AUOK190X_VERSION_SIZE_INT(_val)                ((_val & 0xfc00) >> 10)
-#define AUOK190X_VERSION_SIZE_FLOAT(_val)      ((_val & 0x3c0) >> 6)
-#define AUOK190X_VERSION_MODEL(_val)           (_val & 0x3f)
-#define AUOK190X_VERSION_LUT(_val)             (_val & 0xff)
-#define AUOK190X_VERSION_TCON(_val)            ((_val & 0xff00) >> 8)
-
-/*
- * update modes for CMD_PARTIALDISP on K1900 and CMD_DDMA on K1901
- */
-
-#define AUOK190X_UPDATE_MODE(_res)             ((_res & 0x7) << 12)
-#define AUOK190X_UPDATE_NONFLASH               (1 << 15)
-
-/*
- * track panel specific parameters for common init
- */
-
-struct auok190x_init_data {
-       char *id;
-       struct auok190x_board *board;
-
-       void (*update_partial)(struct auok190xfb_par *par, u16 y1, u16 y2);
-       void (*update_all)(struct auok190xfb_par *par);
-       bool (*need_refresh)(struct auok190xfb_par *par);
-       void (*init)(struct auok190xfb_par *par);
-};
-
-
-extern void auok190x_send_command_nowait(struct auok190xfb_par *par, u16 data);
-extern int auok190x_send_command(struct auok190xfb_par *par, u16 data);
-extern void auok190x_send_cmdargs_nowait(struct auok190xfb_par *par, u16 cmd,
-                                        int argc, u16 *argv);
-extern int auok190x_send_cmdargs(struct auok190xfb_par *par, u16 cmd,
-                                 int argc, u16 *argv);
-extern void auok190x_send_cmdargs_pixels_nowait(struct auok190xfb_par *par,
-                                               u16 cmd, int argc, u16 *argv,
-                                               int size, u16 *data);
-extern int auok190x_send_cmdargs_pixels(struct auok190xfb_par *par, u16 cmd,
-                                       int argc, u16 *argv, int size,
-                                       u16 *data);
-extern int auok190x_read_cmdargs(struct auok190xfb_par *par, u16 cmd,
-                                 int argc, u16 *argv);
-
-extern int auok190x_common_probe(struct platform_device *pdev,
-                                struct auok190x_init_data *init);
-extern int auok190x_common_remove(struct platform_device *pdev);
-
-extern const struct dev_pm_ops auok190x_pm;
index 487d5e336e1b6cdb9f1375577afbdb8fd8a8565d..82c20c6047b0e7020c7a678b557e59e488da87dd 100644 (file)
@@ -37,7 +37,7 @@ static struct page *fb_deferred_io_page(struct fb_info *info, unsigned long offs
 }
 
 /* this is to find and return the vmalloc-ed fb pages */
-static int fb_deferred_io_fault(struct vm_fault *vmf)
+static vm_fault_t fb_deferred_io_fault(struct vm_fault *vmf)
 {
        unsigned long offset;
        struct page *page;
@@ -90,7 +90,7 @@ int fb_deferred_io_fsync(struct file *file, loff_t start, loff_t end, int datasy
 EXPORT_SYMBOL_GPL(fb_deferred_io_fsync);
 
 /* vm_ops->page_mkwrite handler */
-static int fb_deferred_io_mkwrite(struct vm_fault *vmf)
+static vm_fault_t fb_deferred_io_mkwrite(struct vm_fault *vmf)
 {
        struct page *page = vmf->page;
        struct fb_info *info = vmf->vma->vm_private_data;
index f27697e07c55349442e985f90ecb030f3d5150b7..ee212be67dc65eaaffc205af89e0e27ec7a3d5b9 100644 (file)
@@ -495,10 +495,9 @@ static int modes_setup(struct mmpfb_info *fbi)
        /* put videomode list to info structure */
        videomodes = kcalloc(videomode_num, sizeof(struct fb_videomode),
                             GFP_KERNEL);
-       if (!videomodes) {
-               dev_err(fbi->dev, "can't malloc video modes\n");
+       if (!videomodes)
                return -ENOMEM;
-       }
+
        for (i = 0; i < videomode_num; i++)
                mmpmode_to_fbmode(&videomodes[i], &mmp_modes[i]);
        fb_videomode_to_modelist(videomodes, videomode_num, &info->modelist);
index b6f83d5df9fdeab329478d5ccfeb78610da9e532..fcdbb2df137f891e58bcdce792a3a3101daa73d1 100644 (file)
@@ -406,12 +406,10 @@ static int path_init(struct mmphw_path_plat *path_plat,
        dev_info(ctrl->dev, "%s: %s\n", __func__, config->name);
 
        /* init driver data */
-       path_info = kzalloc(sizeof(struct mmp_path_info), GFP_KERNEL);
-       if (!path_info) {
-               dev_err(ctrl->dev, "%s: unable to alloc path_info for %s\n",
-                               __func__, config->name);
+       path_info = kzalloc(sizeof(*path_info), GFP_KERNEL);
+       if (!path_info)
                return 0;
-       }
+
        path_info->name = config->name;
        path_info->id = path_plat->id;
        path_info->dev = ctrl->dev;
index 2e50120bcfae10431bdf2cfb576a43e3b7391fd6..fbeeed5afe350deff19eea67c1463ba5ba158fe6 100644 (file)
@@ -1548,7 +1548,7 @@ MODULE_PARM_DESC(noaccel,
                 "(default=0)");
 module_param(noscale, int, 0);
 MODULE_PARM_DESC(noscale,
-                "Disables screen scaleing. (0 or 1=disable) "
+                "Disables screen scaling. (0 or 1=disable) "
                 "(default=0, do scaling)");
 module_param(paneltweak, int, 0);
 MODULE_PARM_DESC(paneltweak,
index a4ee947006c77c5178161f52df2938db8a45c4cd..e8c748a0dfe25f5113a1fc7ebbbf94614fa88290 100644 (file)
@@ -197,3 +197,7 @@ static struct platform_driver ams_delta_panel_driver = {
 };
 
 module_platform_driver(ams_delta_panel_driver);
+
+MODULE_AUTHOR("Jonathan McDowell <noodles@earth.li>");
+MODULE_DESCRIPTION("LCD panel support for the Amstrad E3 (Delta) videophone");
+MODULE_LICENSE("GPL");
index 796f4634c4c6f157a24769bf1aa34758840c82ec..fd0ac997fb8cd963137ef56fb8a46142d926668e 100644 (file)
@@ -89,3 +89,7 @@ static struct platform_driver h3_panel_driver = {
 };
 
 module_platform_driver(h3_panel_driver);
+
+MODULE_AUTHOR("Imre Deak");
+MODULE_DESCRIPTION("LCD panel support for the TI OMAP H3 board");
+MODULE_LICENSE("GPL");
index 9d692f5b80253c039bc878599f2c082daca5ff54..db4ff1c6add9984596fd89608973c029a8a0db17 100644 (file)
@@ -66,3 +66,7 @@ static struct platform_driver htcherald_panel_driver = {
 };
 
 module_platform_driver(htcherald_panel_driver);
+
+MODULE_AUTHOR("Cory Maccarrone");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("LCD panel support for the HTC Herald");
index b284050f54717b132fdb1bd1f67eb44a19f7b0d3..1ea775f17bc1d73c3b81feca9736a7ee100fe2ee 100644 (file)
@@ -73,3 +73,7 @@ static struct platform_driver innovator1510_panel_driver = {
 };
 
 module_platform_driver(innovator1510_panel_driver);
+
+MODULE_AUTHOR("Imre Deak");
+MODULE_DESCRIPTION("LCD panel support for the TI OMAP1510 Innovator board");
+MODULE_LICENSE("GPL");
index 1841710e796f779453e1fda56fea2a45f78a71df..8d0cf68d2de330af489377f9a6b5c3700576f79d 100644 (file)
@@ -106,3 +106,7 @@ static struct platform_driver innovator1610_panel_driver = {
 };
 
 module_platform_driver(innovator1610_panel_driver);
+
+MODULE_AUTHOR("Imre Deak");
+MODULE_DESCRIPTION("LCD panel support for the TI OMAP1610 Innovator board");
+MODULE_LICENSE("GPL");
index b0be5771fe90ee6704fb0ec2882f2cc133162a62..9fc43a14957d23cec1673adab5e098451614db2d 100644 (file)
@@ -93,3 +93,7 @@ static struct platform_driver osk_panel_driver = {
 };
 
 module_platform_driver(osk_panel_driver);
+
+MODULE_AUTHOR("Imre Deak");
+MODULE_DESCRIPTION("LCD panel support for the TI OMAP OSK board");
+MODULE_LICENSE("GPL");
index cef96386cf8021e0b16118cb017175e00f3a07ed..a0e88864313146300bd78e00a82dfc2beed7f052 100644 (file)
@@ -59,3 +59,7 @@ static struct platform_driver palmte_panel_driver = {
 };
 
 module_platform_driver(palmte_panel_driver);
+
+MODULE_AUTHOR("Romain Goyet <r.goyet@gmail.com>, Laurent Gonzalez <palmte.linux@free.fr>");
+MODULE_DESCRIPTION("LCD panel support for the Palm Tungsten E");
+MODULE_LICENSE("GPL");
index 627f13dae5ad69011e5f5c7e0e783459d6b939ea..2c45375e456f413079aaa7815b2e39a4dea39e5e 100644 (file)
@@ -72,3 +72,7 @@ static struct platform_driver palmtt_panel_driver = {
 };
 
 module_platform_driver(palmtt_panel_driver);
+
+MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
+MODULE_DESCRIPTION("LCD panel support for Palm Tungsten|T");
+MODULE_LICENSE("GPL");
index c46d4db1f839ff83b23a5ae6278e60bad418f681..c99a15ab182633e3b71a5ecaa6f7127764500340 100644 (file)
@@ -66,3 +66,7 @@ static struct platform_driver palmz71_panel_driver = {
 };
 
 module_platform_driver(palmz71_panel_driver);
+
+MODULE_AUTHOR("Romain Goyet, Laurent Gonzalez, Marek Vasut");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("LCD panel support for the Palm Zire71");
index 3479a47a308208f3c414efde067f9cf8cfecd17c..585f39efcff674715575221ce6a3a6ab43c214eb 100644 (file)
@@ -1645,7 +1645,7 @@ static int omapfb_do_probe(struct platform_device *pdev,
                goto cleanup;
        }
 
-       fbdev = kzalloc(sizeof(struct omapfb_device), GFP_KERNEL);
+       fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL);
        if (fbdev == NULL) {
                dev_err(&pdev->dev,
                        "unable to allocate memory for device info\n");
index e6226aeed17ed7f75407170693bccb2d5fdabdc8..3bf154e676d1cc7cea1f812482fcf135a6d0b088 100644 (file)
@@ -5,6 +5,7 @@ menuconfig FB_OMAP2
         tristate "OMAP2+ frame buffer support"
         depends on FB
         depends on DRM_OMAP = n
+       depends on GPIOLIB
 
         select FB_OMAP2_DSS
        select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3
index bef4315300905a691c32373feb29e70ab1ff421e..87497a00241fdb0cb69882a94ca94d8df1bed91a 100644 (file)
@@ -387,8 +387,7 @@ static void dsicm_get_resolution(struct omap_dss_device *dssdev,
 static ssize_t dsicm_num_errors_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+       struct panel_drv_data *ddata = dev_get_drvdata(dev);
        struct omap_dss_device *in = ddata->in;
        u8 errors = 0;
        int r;
@@ -419,8 +418,7 @@ static ssize_t dsicm_num_errors_show(struct device *dev,
 static ssize_t dsicm_hw_revision_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+       struct panel_drv_data *ddata = dev_get_drvdata(dev);
        struct omap_dss_device *in = ddata->in;
        u8 id1, id2, id3;
        int r;
@@ -451,8 +449,7 @@ static ssize_t dsicm_store_ulps(struct device *dev,
                struct device_attribute *attr,
                const char *buf, size_t count)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+       struct panel_drv_data *ddata = dev_get_drvdata(dev);
        struct omap_dss_device *in = ddata->in;
        unsigned long t;
        int r;
@@ -486,8 +483,7 @@ static ssize_t dsicm_show_ulps(struct device *dev,
                struct device_attribute *attr,
                char *buf)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+       struct panel_drv_data *ddata = dev_get_drvdata(dev);
        unsigned t;
 
        mutex_lock(&ddata->lock);
@@ -501,8 +497,7 @@ static ssize_t dsicm_store_ulps_timeout(struct device *dev,
                struct device_attribute *attr,
                const char *buf, size_t count)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+       struct panel_drv_data *ddata = dev_get_drvdata(dev);
        struct omap_dss_device *in = ddata->in;
        unsigned long t;
        int r;
@@ -533,8 +528,7 @@ static ssize_t dsicm_show_ulps_timeout(struct device *dev,
                struct device_attribute *attr,
                char *buf)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+       struct panel_drv_data *ddata = dev_get_drvdata(dev);
        unsigned t;
 
        mutex_lock(&ddata->lock);
index c3d49e13643cd21504d7ffa62f1231d6a9a8ef38..76722a59f55e34c83ec948d77c2c0df5c936fa16 100644 (file)
@@ -2115,12 +2115,10 @@ static int of_get_pxafb_display(struct device *dev, struct device_node *disp,
        if (ret)
                s = "color-tft";
 
-       for (i = 0; lcd_types[i]; i++)
-               if (!strcmp(s, lcd_types[i]))
-                       break;
-       if (!i || !lcd_types[i]) {
+       i = match_string(lcd_types, -1, s);
+       if (i < 0) {
                dev_err(dev, "lcd-type %s is unknown\n", s);
-               return -EINVAL;
+               return i;
        }
        info->lcd_conn |= LCD_CONN_TYPE(i);
        info->lcd_conn |= LCD_CONN_WIDTH(bus_width);
index c20468362f11ce58a535ca9648b9397f6b6d6eef..c09d7426cd92505f9418d17ba852ea0aaef2fa0a 100644 (file)
@@ -1892,11 +1892,11 @@ static int savage_init_hw(struct savagefb_par *par)
        vga_out8(0x3d4, 0x66, par);
        cr66 = vga_in8(0x3d5, par);
        vga_out8(0x3d5, cr66 | 0x02, par);
-       mdelay(10);
+       usleep_range(10000, 11000);
 
        vga_out8(0x3d4, 0x66, par);
        vga_out8(0x3d5, cr66 & ~0x02, par);     /* clear reset flag */
-       mdelay(10);
+       usleep_range(10000, 11000);
 
 
        /*
@@ -1906,11 +1906,11 @@ static int savage_init_hw(struct savagefb_par *par)
        vga_out8(0x3d4, 0x3f, par);
        cr3f = vga_in8(0x3d5, par);
        vga_out8(0x3d5, cr3f | 0x08, par);
-       mdelay(10);
+       usleep_range(10000, 11000);
 
        vga_out8(0x3d4, 0x3f, par);
        vga_out8(0x3d5, cr3f & ~0x08, par);     /* clear reset flags */
-       mdelay(10);
+       usleep_range(10000, 11000);
 
        /* Savage ramdac speeds */
        par->numClocks = 4;
index c3a46506e47e2997122e54c36510f8aca8c2f066..dc46be38c9706f4b0ef8e562475de1dd08a02ef2 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/vmalloc.h>
 
 #include <video/sh_mobile_lcdc.h>
-#include <video/sh_mobile_meram.h>
 
 #include "sh_mobile_lcdcfb.h"
 
@@ -217,7 +216,6 @@ struct sh_mobile_lcdc_priv {
        struct notifier_block notifier;
        int started;
        int forced_fourcc; /* 2 channel LCDC must share fourcc setting */
-       struct sh_mobile_meram_info *meram_dev;
 };
 
 /* -----------------------------------------------------------------------------
@@ -346,16 +344,12 @@ static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv)
                if (priv->dot_clk)
                        clk_prepare_enable(priv->dot_clk);
                pm_runtime_get_sync(priv->dev);
-               if (priv->meram_dev && priv->meram_dev->pdev)
-                       pm_runtime_get_sync(&priv->meram_dev->pdev->dev);
        }
 }
 
 static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv)
 {
        if (atomic_sub_return(1, &priv->hw_usecnt) == -1) {
-               if (priv->meram_dev && priv->meram_dev->pdev)
-                       pm_runtime_put_sync(&priv->meram_dev->pdev->dev);
                pm_runtime_put(priv->dev);
                if (priv->dot_clk)
                        clk_disable_unprepare(priv->dot_clk);
@@ -1073,7 +1067,6 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 
 static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 {
-       struct sh_mobile_meram_info *mdev = priv->meram_dev;
        struct sh_mobile_lcdc_chan *ch;
        unsigned long tmp;
        int ret;
@@ -1106,9 +1099,6 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 
        /* Compute frame buffer base address and pitch for each channel. */
        for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
-               int pixelformat;
-               void *cache;
-
                ch = &priv->ch[k];
                if (!ch->enabled)
                        continue;
@@ -1117,45 +1107,6 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
                ch->base_addr_c = ch->dma_handle
                                + ch->xres_virtual * ch->yres_virtual;
                ch->line_size = ch->pitch;
-
-               /* Enable MERAM if possible. */
-               if (mdev == NULL || ch->cfg->meram_cfg == NULL)
-                       continue;
-
-               /* Free the allocated MERAM cache. */
-               if (ch->cache) {
-                       sh_mobile_meram_cache_free(mdev, ch->cache);
-                       ch->cache = NULL;
-               }
-
-               switch (ch->format->fourcc) {
-               case V4L2_PIX_FMT_NV12:
-               case V4L2_PIX_FMT_NV21:
-               case V4L2_PIX_FMT_NV16:
-               case V4L2_PIX_FMT_NV61:
-                       pixelformat = SH_MOBILE_MERAM_PF_NV;
-                       break;
-               case V4L2_PIX_FMT_NV24:
-               case V4L2_PIX_FMT_NV42:
-                       pixelformat = SH_MOBILE_MERAM_PF_NV24;
-                       break;
-               case V4L2_PIX_FMT_RGB565:
-               case V4L2_PIX_FMT_BGR24:
-               case V4L2_PIX_FMT_BGR32:
-               default:
-                       pixelformat = SH_MOBILE_MERAM_PF_RGB;
-                       break;
-               }
-
-               cache = sh_mobile_meram_cache_alloc(mdev, ch->cfg->meram_cfg,
-                                       ch->pitch, ch->yres, pixelformat,
-                                       &ch->line_size);
-               if (!IS_ERR(cache)) {
-                       sh_mobile_meram_cache_update(mdev, cache,
-                                       ch->base_addr_y, ch->base_addr_c,
-                                       &ch->base_addr_y, &ch->base_addr_c);
-                       ch->cache = cache;
-               }
        }
 
        for (k = 0; k < ARRAY_SIZE(priv->overlays); ++k) {
@@ -1223,13 +1174,6 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)
                }
 
                sh_mobile_lcdc_display_off(ch);
-
-               /* Free the MERAM cache. */
-               if (ch->cache) {
-                       sh_mobile_meram_cache_free(priv->meram_dev, ch->cache);
-                       ch->cache = NULL;
-               }
-
        }
 
        /* stop the lcdc */
@@ -1851,11 +1795,6 @@ static int sh_mobile_lcdc_pan(struct fb_var_screeninfo *var,
        base_addr_c = ch->dma_handle + ch->xres_virtual * ch->yres_virtual
                    + c_offset;
 
-       if (ch->cache)
-               sh_mobile_meram_cache_update(priv->meram_dev, ch->cache,
-                                            base_addr_y, base_addr_c,
-                                            &base_addr_y, &base_addr_c);
-
        ch->base_addr_y = base_addr_y;
        ch->base_addr_c = base_addr_c;
        ch->pan_y_offset = y_offset;
@@ -2149,10 +2088,8 @@ sh_mobile_lcdc_channel_fb_register(struct sh_mobile_lcdc_chan *ch)
        if (info->fbdefio) {
                ch->sglist = vmalloc(sizeof(struct scatterlist) *
                                     ch->fb_size >> PAGE_SHIFT);
-               if (!ch->sglist) {
-                       dev_err(ch->lcdc->dev, "cannot allocate sglist\n");
+               if (!ch->sglist)
                        return -ENOMEM;
-               }
        }
 
        info->bl_dev = ch->bl;
@@ -2354,8 +2291,7 @@ static int sh_mobile_lcdc_resume(struct device *dev)
 
 static int sh_mobile_lcdc_runtime_suspend(struct device *dev)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
+       struct sh_mobile_lcdc_priv *priv = dev_get_drvdata(dev);
 
        /* turn off LCDC hardware */
        lcdc_write(priv, _LDCNT1R, 0);
@@ -2365,8 +2301,7 @@ static int sh_mobile_lcdc_runtime_suspend(struct device *dev)
 
 static int sh_mobile_lcdc_runtime_resume(struct device *dev)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
+       struct sh_mobile_lcdc_priv *priv = dev_get_drvdata(dev);
 
        __sh_mobile_lcdc_start(priv);
 
@@ -2718,13 +2653,11 @@ static int sh_mobile_lcdc_probe(struct platform_device *pdev)
        }
 
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-       if (!priv) {
-               dev_err(&pdev->dev, "cannot allocate device data\n");
+       if (!priv)
                return -ENOMEM;
-       }
 
        priv->dev = &pdev->dev;
-       priv->meram_dev = pdata->meram_dev;
+
        for (i = 0; i < ARRAY_SIZE(priv->ch); i++)
                mutex_init(&priv->ch[i].open_lock);
        platform_set_drvdata(pdev, priv);
index cc52c74721fe98570e03d9195aa407265c13e12d..b8e47a8bd8abb57418f5a9bbad7eecadce8d074a 100644 (file)
@@ -61,7 +61,6 @@ struct sh_mobile_lcdc_chan {
        unsigned long *reg_offs;
        unsigned long ldmt1r_value;
        unsigned long enabled; /* ME and SE in LDCNT2R */
-       void *cache;
 
        struct mutex open_lock;         /* protects the use counter */
        int use_count;
diff --git a/drivers/video/fbdev/sh_mobile_meram.c b/drivers/video/fbdev/sh_mobile_meram.c
deleted file mode 100644 (file)
index baadfb2..0000000
+++ /dev/null
@@ -1,758 +0,0 @@
-/*
- * SuperH Mobile MERAM Driver for SuperH Mobile LCDC Driver
- *
- * Copyright (c) 2011  Damian Hobson-Garcia <dhobsong@igel.co.jp>
- *                      Takanari Hayama <taki@igel.co.jp>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/export.h>
-#include <linux/genalloc.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
-#include <linux/slab.h>
-
-#include <video/sh_mobile_meram.h>
-
-/* -----------------------------------------------------------------------------
- * MERAM registers
- */
-
-#define MEVCR1                 0x4
-#define MEVCR1_RST             (1 << 31)
-#define MEVCR1_WD              (1 << 30)
-#define MEVCR1_AMD1            (1 << 29)
-#define MEVCR1_AMD0            (1 << 28)
-#define MEQSEL1                        0x40
-#define MEQSEL2                        0x44
-
-#define MExxCTL                        0x400
-#define MExxCTL_BV             (1 << 31)
-#define MExxCTL_BSZ_SHIFT      28
-#define MExxCTL_MSAR_MASK      (0x7ff << MExxCTL_MSAR_SHIFT)
-#define MExxCTL_MSAR_SHIFT     16
-#define MExxCTL_NXT_MASK       (0x1f << MExxCTL_NXT_SHIFT)
-#define MExxCTL_NXT_SHIFT      11
-#define MExxCTL_WD1            (1 << 10)
-#define MExxCTL_WD0            (1 << 9)
-#define MExxCTL_WS             (1 << 8)
-#define MExxCTL_CB             (1 << 7)
-#define MExxCTL_WBF            (1 << 6)
-#define MExxCTL_WF             (1 << 5)
-#define MExxCTL_RF             (1 << 4)
-#define MExxCTL_CM             (1 << 3)
-#define MExxCTL_MD_READ                (1 << 0)
-#define MExxCTL_MD_WRITE       (2 << 0)
-#define MExxCTL_MD_ICB_WB      (3 << 0)
-#define MExxCTL_MD_ICB         (4 << 0)
-#define MExxCTL_MD_FB          (7 << 0)
-#define MExxCTL_MD_MASK                (7 << 0)
-#define MExxBSIZE              0x404
-#define MExxBSIZE_RCNT_SHIFT   28
-#define MExxBSIZE_YSZM1_SHIFT  16
-#define MExxBSIZE_XSZM1_SHIFT  0
-#define MExxMNCF               0x408
-#define MExxMNCF_KWBNM_SHIFT   28
-#define MExxMNCF_KRBNM_SHIFT   24
-#define MExxMNCF_BNM_SHIFT     16
-#define MExxMNCF_XBV           (1 << 15)
-#define MExxMNCF_CPL_YCBCR444  (1 << 12)
-#define MExxMNCF_CPL_YCBCR420  (2 << 12)
-#define MExxMNCF_CPL_YCBCR422  (3 << 12)
-#define MExxMNCF_CPL_MSK       (3 << 12)
-#define MExxMNCF_BL            (1 << 2)
-#define MExxMNCF_LNM_SHIFT     0
-#define MExxSARA               0x410
-#define MExxSARB               0x414
-#define MExxSBSIZE             0x418
-#define MExxSBSIZE_HDV         (1 << 31)
-#define MExxSBSIZE_HSZ16       (0 << 28)
-#define MExxSBSIZE_HSZ32       (1 << 28)
-#define MExxSBSIZE_HSZ64       (2 << 28)
-#define MExxSBSIZE_HSZ128      (3 << 28)
-#define MExxSBSIZE_SBSIZZ_SHIFT        0
-
-#define MERAM_MExxCTL_VAL(next, addr)  \
-       ((((next) << MExxCTL_NXT_SHIFT) & MExxCTL_NXT_MASK) | \
-        (((addr) << MExxCTL_MSAR_SHIFT) & MExxCTL_MSAR_MASK))
-#define        MERAM_MExxBSIZE_VAL(rcnt, yszm1, xszm1) \
-       (((rcnt) << MExxBSIZE_RCNT_SHIFT) | \
-        ((yszm1) << MExxBSIZE_YSZM1_SHIFT) | \
-        ((xszm1) << MExxBSIZE_XSZM1_SHIFT))
-
-static const unsigned long common_regs[] = {
-       MEVCR1,
-       MEQSEL1,
-       MEQSEL2,
-};
-#define MERAM_REGS_SIZE ARRAY_SIZE(common_regs)
-
-static const unsigned long icb_regs[] = {
-       MExxCTL,
-       MExxBSIZE,
-       MExxMNCF,
-       MExxSARA,
-       MExxSARB,
-       MExxSBSIZE,
-};
-#define ICB_REGS_SIZE ARRAY_SIZE(icb_regs)
-
-/*
- * sh_mobile_meram_icb - MERAM ICB information
- * @regs: Registers cache
- * @index: ICB index
- * @offset: MERAM block offset
- * @size: MERAM block size in KiB
- * @cache_unit: Bytes to cache per ICB
- * @pixelformat: Video pixel format of the data stored in the ICB
- * @current_reg: Which of Start Address Register A (0) or B (1) is in use
- */
-struct sh_mobile_meram_icb {
-       unsigned long regs[ICB_REGS_SIZE];
-       unsigned int index;
-       unsigned long offset;
-       unsigned int size;
-
-       unsigned int cache_unit;
-       unsigned int pixelformat;
-       unsigned int current_reg;
-};
-
-#define MERAM_ICB_NUM                  32
-
-struct sh_mobile_meram_fb_plane {
-       struct sh_mobile_meram_icb *marker;
-       struct sh_mobile_meram_icb *cache;
-};
-
-struct sh_mobile_meram_fb_cache {
-       unsigned int nplanes;
-       struct sh_mobile_meram_fb_plane planes[2];
-};
-
-/*
- * sh_mobile_meram_priv - MERAM device
- * @base: Registers base address
- * @meram: MERAM physical address
- * @regs: Registers cache
- * @lock: Protects used_icb and icbs
- * @used_icb: Bitmask of used ICBs
- * @icbs: ICBs
- * @pool: Allocation pool to manage the MERAM
- */
-struct sh_mobile_meram_priv {
-       void __iomem *base;
-       unsigned long meram;
-       unsigned long regs[MERAM_REGS_SIZE];
-
-       struct mutex lock;
-       unsigned long used_icb;
-       struct sh_mobile_meram_icb icbs[MERAM_ICB_NUM];
-
-       struct gen_pool *pool;
-};
-
-/* settings */
-#define MERAM_GRANULARITY              1024
-#define MERAM_SEC_LINE                 15
-#define MERAM_LINE_WIDTH               2048
-
-/* -----------------------------------------------------------------------------
- * Registers access
- */
-
-#define MERAM_ICB_OFFSET(base, idx, off)       ((base) + (off) + (idx) * 0x20)
-
-static inline void meram_write_icb(void __iomem *base, unsigned int idx,
-                                  unsigned int off, unsigned long val)
-{
-       iowrite32(val, MERAM_ICB_OFFSET(base, idx, off));
-}
-
-static inline unsigned long meram_read_icb(void __iomem *base, unsigned int idx,
-                                          unsigned int off)
-{
-       return ioread32(MERAM_ICB_OFFSET(base, idx, off));
-}
-
-static inline void meram_write_reg(void __iomem *base, unsigned int off,
-                                  unsigned long val)
-{
-       iowrite32(val, base + off);
-}
-
-static inline unsigned long meram_read_reg(void __iomem *base, unsigned int off)
-{
-       return ioread32(base + off);
-}
-
-/* -----------------------------------------------------------------------------
- * MERAM allocation and free
- */
-
-static unsigned long meram_alloc(struct sh_mobile_meram_priv *priv, size_t size)
-{
-       return gen_pool_alloc(priv->pool, size);
-}
-
-static void meram_free(struct sh_mobile_meram_priv *priv, unsigned long mem,
-                      size_t size)
-{
-       gen_pool_free(priv->pool, mem, size);
-}
-
-/* -----------------------------------------------------------------------------
- * LCDC cache planes allocation, init, cleanup and free
- */
-
-/* Allocate ICBs and MERAM for a plane. */
-static int meram_plane_alloc(struct sh_mobile_meram_priv *priv,
-                            struct sh_mobile_meram_fb_plane *plane,
-                            size_t size)
-{
-       unsigned long mem;
-       unsigned long idx;
-
-       idx = find_first_zero_bit(&priv->used_icb, 28);
-       if (idx == 28)
-               return -ENOMEM;
-       plane->cache = &priv->icbs[idx];
-
-       idx = find_next_zero_bit(&priv->used_icb, 32, 28);
-       if (idx == 32)
-               return -ENOMEM;
-       plane->marker = &priv->icbs[idx];
-
-       mem = meram_alloc(priv, size * 1024);
-       if (mem == 0)
-               return -ENOMEM;
-
-       __set_bit(plane->marker->index, &priv->used_icb);
-       __set_bit(plane->cache->index, &priv->used_icb);
-
-       plane->marker->offset = mem - priv->meram;
-       plane->marker->size = size;
-
-       return 0;
-}
-
-/* Free ICBs and MERAM for a plane. */
-static void meram_plane_free(struct sh_mobile_meram_priv *priv,
-                            struct sh_mobile_meram_fb_plane *plane)
-{
-       meram_free(priv, priv->meram + plane->marker->offset,
-                  plane->marker->size * 1024);
-
-       __clear_bit(plane->marker->index, &priv->used_icb);
-       __clear_bit(plane->cache->index, &priv->used_icb);
-}
-
-/* Is this a YCbCr(NV12, NV16 or NV24) colorspace? */
-static int is_nvcolor(int cspace)
-{
-       if (cspace == SH_MOBILE_MERAM_PF_NV ||
-           cspace == SH_MOBILE_MERAM_PF_NV24)
-               return 1;
-       return 0;
-}
-
-/* Set the next address to fetch. */
-static void meram_set_next_addr(struct sh_mobile_meram_priv *priv,
-                               struct sh_mobile_meram_fb_cache *cache,
-                               unsigned long base_addr_y,
-                               unsigned long base_addr_c)
-{
-       struct sh_mobile_meram_icb *icb = cache->planes[0].marker;
-       unsigned long target;
-
-       icb->current_reg ^= 1;
-       target = icb->current_reg ? MExxSARB : MExxSARA;
-
-       /* set the next address to fetch */
-       meram_write_icb(priv->base, cache->planes[0].cache->index, target,
-                       base_addr_y);
-       meram_write_icb(priv->base, cache->planes[0].marker->index, target,
-                       base_addr_y + cache->planes[0].marker->cache_unit);
-
-       if (cache->nplanes == 2) {
-               meram_write_icb(priv->base, cache->planes[1].cache->index,
-                               target, base_addr_c);
-               meram_write_icb(priv->base, cache->planes[1].marker->index,
-                               target, base_addr_c +
-                               cache->planes[1].marker->cache_unit);
-       }
-}
-
-/* Get the next ICB address. */
-static void
-meram_get_next_icb_addr(struct sh_mobile_meram_info *pdata,
-                       struct sh_mobile_meram_fb_cache *cache,
-                       unsigned long *icb_addr_y, unsigned long *icb_addr_c)
-{
-       struct sh_mobile_meram_icb *icb = cache->planes[0].marker;
-       unsigned long icb_offset;
-
-       if (pdata->addr_mode == SH_MOBILE_MERAM_MODE0)
-               icb_offset = 0x80000000 | (icb->current_reg << 29);
-       else
-               icb_offset = 0xc0000000 | (icb->current_reg << 23);
-
-       *icb_addr_y = icb_offset | (cache->planes[0].marker->index << 24);
-       if (cache->nplanes == 2)
-               *icb_addr_c = icb_offset
-                           | (cache->planes[1].marker->index << 24);
-}
-
-#define MERAM_CALC_BYTECOUNT(x, y) \
-       (((x) * (y) + (MERAM_LINE_WIDTH - 1)) & ~(MERAM_LINE_WIDTH - 1))
-
-/* Initialize MERAM. */
-static int meram_plane_init(struct sh_mobile_meram_priv *priv,
-                           struct sh_mobile_meram_fb_plane *plane,
-                           unsigned int xres, unsigned int yres,
-                           unsigned int *out_pitch)
-{
-       struct sh_mobile_meram_icb *marker = plane->marker;
-       unsigned long total_byte_count = MERAM_CALC_BYTECOUNT(xres, yres);
-       unsigned long bnm;
-       unsigned int lcdc_pitch;
-       unsigned int xpitch;
-       unsigned int line_cnt;
-       unsigned int save_lines;
-
-       /* adjust pitch to 1024, 2048, 4096 or 8192 */
-       lcdc_pitch = (xres - 1) | 1023;
-       lcdc_pitch = lcdc_pitch | (lcdc_pitch >> 1);
-       lcdc_pitch = lcdc_pitch | (lcdc_pitch >> 2);
-       lcdc_pitch += 1;
-
-       /* derive settings */
-       if (lcdc_pitch == 8192 && yres >= 1024) {
-               lcdc_pitch = xpitch = MERAM_LINE_WIDTH;
-               line_cnt = total_byte_count >> 11;
-               *out_pitch = xres;
-               save_lines = plane->marker->size / 16 / MERAM_SEC_LINE;
-               save_lines *= MERAM_SEC_LINE;
-       } else {
-               xpitch = xres;
-               line_cnt = yres;
-               *out_pitch = lcdc_pitch;
-               save_lines = plane->marker->size / (lcdc_pitch >> 10) / 2;
-               save_lines &= 0xff;
-       }
-       bnm = (save_lines - 1) << 16;
-
-       /* TODO: we better to check if we have enough MERAM buffer size */
-
-       /* set up ICB */
-       meram_write_icb(priv->base, plane->cache->index,  MExxBSIZE,
-                       MERAM_MExxBSIZE_VAL(0x0, line_cnt - 1, xpitch - 1));
-       meram_write_icb(priv->base, plane->marker->index, MExxBSIZE,
-                       MERAM_MExxBSIZE_VAL(0xf, line_cnt - 1, xpitch - 1));
-
-       meram_write_icb(priv->base, plane->cache->index,  MExxMNCF, bnm);
-       meram_write_icb(priv->base, plane->marker->index, MExxMNCF, bnm);
-
-       meram_write_icb(priv->base, plane->cache->index,  MExxSBSIZE, xpitch);
-       meram_write_icb(priv->base, plane->marker->index, MExxSBSIZE, xpitch);
-
-       /* save a cache unit size */
-       plane->cache->cache_unit = xres * save_lines;
-       plane->marker->cache_unit = xres * save_lines;
-
-       /*
-        * Set MERAM for framebuffer
-        *
-        * we also chain the cache_icb and the marker_icb.
-        * we also split the allocated MERAM buffer between two ICBs.
-        */
-       meram_write_icb(priv->base, plane->cache->index, MExxCTL,
-                       MERAM_MExxCTL_VAL(plane->marker->index, marker->offset)
-                       | MExxCTL_WD1 | MExxCTL_WD0 | MExxCTL_WS | MExxCTL_CM |
-                       MExxCTL_MD_FB);
-       meram_write_icb(priv->base, plane->marker->index, MExxCTL,
-                       MERAM_MExxCTL_VAL(plane->cache->index, marker->offset +
-                                         plane->marker->size / 2) |
-                       MExxCTL_WD1 | MExxCTL_WD0 | MExxCTL_WS | MExxCTL_CM |
-                       MExxCTL_MD_FB);
-
-       return 0;
-}
-
-static void meram_plane_cleanup(struct sh_mobile_meram_priv *priv,
-                               struct sh_mobile_meram_fb_plane *plane)
-{
-       /* disable ICB */
-       meram_write_icb(priv->base, plane->cache->index,  MExxCTL,
-                       MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF);
-       meram_write_icb(priv->base, plane->marker->index, MExxCTL,
-                       MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF);
-
-       plane->cache->cache_unit = 0;
-       plane->marker->cache_unit = 0;
-}
-
-/* -----------------------------------------------------------------------------
- * MERAM operations
- */
-
-unsigned long sh_mobile_meram_alloc(struct sh_mobile_meram_info *pdata,
-                                   size_t size)
-{
-       struct sh_mobile_meram_priv *priv = pdata->priv;
-
-       return meram_alloc(priv, size);
-}
-EXPORT_SYMBOL_GPL(sh_mobile_meram_alloc);
-
-void sh_mobile_meram_free(struct sh_mobile_meram_info *pdata, unsigned long mem,
-                         size_t size)
-{
-       struct sh_mobile_meram_priv *priv = pdata->priv;
-
-       meram_free(priv, mem, size);
-}
-EXPORT_SYMBOL_GPL(sh_mobile_meram_free);
-
-/* Allocate memory for the ICBs and mark them as used. */
-static struct sh_mobile_meram_fb_cache *
-meram_cache_alloc(struct sh_mobile_meram_priv *priv,
-                 const struct sh_mobile_meram_cfg *cfg,
-                 int pixelformat)
-{
-       unsigned int nplanes = is_nvcolor(pixelformat) ? 2 : 1;
-       struct sh_mobile_meram_fb_cache *cache;
-       int ret;
-
-       cache = kzalloc(sizeof(*cache), GFP_KERNEL);
-       if (cache == NULL)
-               return ERR_PTR(-ENOMEM);
-
-       cache->nplanes = nplanes;
-
-       ret = meram_plane_alloc(priv, &cache->planes[0],
-                               cfg->icb[0].meram_size);
-       if (ret < 0)
-               goto error;
-
-       cache->planes[0].marker->current_reg = 1;
-       cache->planes[0].marker->pixelformat = pixelformat;
-
-       if (cache->nplanes == 1)
-               return cache;
-
-       ret = meram_plane_alloc(priv, &cache->planes[1],
-                               cfg->icb[1].meram_size);
-       if (ret < 0) {
-               meram_plane_free(priv, &cache->planes[0]);
-               goto error;
-       }
-
-       return cache;
-
-error:
-       kfree(cache);
-       return ERR_PTR(-ENOMEM);
-}
-
-void *sh_mobile_meram_cache_alloc(struct sh_mobile_meram_info *pdata,
-                                 const struct sh_mobile_meram_cfg *cfg,
-                                 unsigned int xres, unsigned int yres,
-                                 unsigned int pixelformat, unsigned int *pitch)
-{
-       struct sh_mobile_meram_fb_cache *cache;
-       struct sh_mobile_meram_priv *priv = pdata->priv;
-       struct platform_device *pdev = pdata->pdev;
-       unsigned int nplanes = is_nvcolor(pixelformat) ? 2 : 1;
-       unsigned int out_pitch;
-
-       if (priv == NULL)
-               return ERR_PTR(-ENODEV);
-
-       if (pixelformat != SH_MOBILE_MERAM_PF_NV &&
-           pixelformat != SH_MOBILE_MERAM_PF_NV24 &&
-           pixelformat != SH_MOBILE_MERAM_PF_RGB)
-               return ERR_PTR(-EINVAL);
-
-       dev_dbg(&pdev->dev, "registering %dx%d (%s)", xres, yres,
-               !pixelformat ? "yuv" : "rgb");
-
-       /* we can't handle wider than 8192px */
-       if (xres > 8192) {
-               dev_err(&pdev->dev, "width exceeding the limit (> 8192).");
-               return ERR_PTR(-EINVAL);
-       }
-
-       if (cfg->icb[0].meram_size == 0)
-               return ERR_PTR(-EINVAL);
-
-       if (nplanes == 2 && cfg->icb[1].meram_size == 0)
-               return ERR_PTR(-EINVAL);
-
-       mutex_lock(&priv->lock);
-
-       /* We now register the ICBs and allocate the MERAM regions. */
-       cache = meram_cache_alloc(priv, cfg, pixelformat);
-       if (IS_ERR(cache)) {
-               dev_err(&pdev->dev, "MERAM allocation failed (%ld).",
-                       PTR_ERR(cache));
-               goto err;
-       }
-
-       /* initialize MERAM */
-       meram_plane_init(priv, &cache->planes[0], xres, yres, &out_pitch);
-       *pitch = out_pitch;
-       if (pixelformat == SH_MOBILE_MERAM_PF_NV)
-               meram_plane_init(priv, &cache->planes[1],
-                                xres, (yres + 1) / 2, &out_pitch);
-       else if (pixelformat == SH_MOBILE_MERAM_PF_NV24)
-               meram_plane_init(priv, &cache->planes[1],
-                                2 * xres, (yres + 1) / 2, &out_pitch);
-
-err:
-       mutex_unlock(&priv->lock);
-       return cache;
-}
-EXPORT_SYMBOL_GPL(sh_mobile_meram_cache_alloc);
-
-void
-sh_mobile_meram_cache_free(struct sh_mobile_meram_info *pdata, void *data)
-{
-       struct sh_mobile_meram_fb_cache *cache = data;
-       struct sh_mobile_meram_priv *priv = pdata->priv;
-
-       mutex_lock(&priv->lock);
-
-       /* Cleanup and free. */
-       meram_plane_cleanup(priv, &cache->planes[0]);
-       meram_plane_free(priv, &cache->planes[0]);
-
-       if (cache->nplanes == 2) {
-               meram_plane_cleanup(priv, &cache->planes[1]);
-               meram_plane_free(priv, &cache->planes[1]);
-       }
-
-       kfree(cache);
-
-       mutex_unlock(&priv->lock);
-}
-EXPORT_SYMBOL_GPL(sh_mobile_meram_cache_free);
-
-void
-sh_mobile_meram_cache_update(struct sh_mobile_meram_info *pdata, void *data,
-                            unsigned long base_addr_y,
-                            unsigned long base_addr_c,
-                            unsigned long *icb_addr_y,
-                            unsigned long *icb_addr_c)
-{
-       struct sh_mobile_meram_fb_cache *cache = data;
-       struct sh_mobile_meram_priv *priv = pdata->priv;
-
-       mutex_lock(&priv->lock);
-
-       meram_set_next_addr(priv, cache, base_addr_y, base_addr_c);
-       meram_get_next_icb_addr(pdata, cache, icb_addr_y, icb_addr_c);
-
-       mutex_unlock(&priv->lock);
-}
-EXPORT_SYMBOL_GPL(sh_mobile_meram_cache_update);
-
-/* -----------------------------------------------------------------------------
- * Power management
- */
-
-#ifdef CONFIG_PM
-static int sh_mobile_meram_suspend(struct device *dev)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-       struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev);
-       unsigned int i, j;
-
-       for (i = 0; i < MERAM_REGS_SIZE; i++)
-               priv->regs[i] = meram_read_reg(priv->base, common_regs[i]);
-
-       for (i = 0; i < 32; i++) {
-               if (!test_bit(i, &priv->used_icb))
-                       continue;
-               for (j = 0; j < ICB_REGS_SIZE; j++) {
-                       priv->icbs[i].regs[j] =
-                               meram_read_icb(priv->base, i, icb_regs[j]);
-                       /* Reset ICB on resume */
-                       if (icb_regs[j] == MExxCTL)
-                               priv->icbs[i].regs[j] |=
-                                       MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF;
-               }
-       }
-       return 0;
-}
-
-static int sh_mobile_meram_resume(struct device *dev)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-       struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev);
-       unsigned int i, j;
-
-       for (i = 0; i < 32; i++) {
-               if (!test_bit(i, &priv->used_icb))
-                       continue;
-               for (j = 0; j < ICB_REGS_SIZE; j++)
-                       meram_write_icb(priv->base, i, icb_regs[j],
-                                       priv->icbs[i].regs[j]);
-       }
-
-       for (i = 0; i < MERAM_REGS_SIZE; i++)
-               meram_write_reg(priv->base, common_regs[i], priv->regs[i]);
-       return 0;
-}
-#endif /* CONFIG_PM */
-
-static UNIVERSAL_DEV_PM_OPS(sh_mobile_meram_dev_pm_ops,
-                           sh_mobile_meram_suspend,
-                           sh_mobile_meram_resume, NULL);
-
-/* -----------------------------------------------------------------------------
- * Probe/remove and driver init/exit
- */
-
-static int sh_mobile_meram_probe(struct platform_device *pdev)
-{
-       struct sh_mobile_meram_priv *priv;
-       struct sh_mobile_meram_info *pdata = pdev->dev.platform_data;
-       struct resource *regs;
-       struct resource *meram;
-       unsigned int i;
-       int error;
-
-       if (!pdata) {
-               dev_err(&pdev->dev, "no platform data defined\n");
-               return -EINVAL;
-       }
-
-       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       meram = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-       if (regs == NULL || meram == NULL) {
-               dev_err(&pdev->dev, "cannot get platform resources\n");
-               return -ENOENT;
-       }
-
-       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-       if (!priv) {
-               dev_err(&pdev->dev, "cannot allocate device data\n");
-               return -ENOMEM;
-       }
-
-       /* Initialize private data. */
-       mutex_init(&priv->lock);
-       priv->used_icb = pdata->reserved_icbs;
-
-       for (i = 0; i < MERAM_ICB_NUM; ++i)
-               priv->icbs[i].index = i;
-
-       pdata->priv = priv;
-       pdata->pdev = pdev;
-
-       /* Request memory regions and remap the registers. */
-       if (!request_mem_region(regs->start, resource_size(regs), pdev->name)) {
-               dev_err(&pdev->dev, "MERAM registers region already claimed\n");
-               error = -EBUSY;
-               goto err_req_regs;
-       }
-
-       if (!request_mem_region(meram->start, resource_size(meram),
-                               pdev->name)) {
-               dev_err(&pdev->dev, "MERAM memory region already claimed\n");
-               error = -EBUSY;
-               goto err_req_meram;
-       }
-
-       priv->base = ioremap_nocache(regs->start, resource_size(regs));
-       if (!priv->base) {
-               dev_err(&pdev->dev, "ioremap failed\n");
-               error = -EFAULT;
-               goto err_ioremap;
-       }
-
-       priv->meram = meram->start;
-
-       /* Create and initialize the MERAM memory pool. */
-       priv->pool = gen_pool_create(ilog2(MERAM_GRANULARITY), -1);
-       if (priv->pool == NULL) {
-               error = -ENOMEM;
-               goto err_genpool;
-       }
-
-       error = gen_pool_add(priv->pool, meram->start, resource_size(meram),
-                            -1);
-       if (error < 0)
-               goto err_genpool;
-
-       /* initialize ICB addressing mode */
-       if (pdata->addr_mode == SH_MOBILE_MERAM_MODE1)
-               meram_write_reg(priv->base, MEVCR1, MEVCR1_AMD1);
-
-       platform_set_drvdata(pdev, priv);
-       pm_runtime_enable(&pdev->dev);
-
-       dev_info(&pdev->dev, "sh_mobile_meram initialized.");
-
-       return 0;
-
-err_genpool:
-       if (priv->pool)
-               gen_pool_destroy(priv->pool);
-       iounmap(priv->base);
-err_ioremap:
-       release_mem_region(meram->start, resource_size(meram));
-err_req_meram:
-       release_mem_region(regs->start, resource_size(regs));
-err_req_regs:
-       mutex_destroy(&priv->lock);
-       kfree(priv);
-
-       return error;
-}
-
-
-static int sh_mobile_meram_remove(struct platform_device *pdev)
-{
-       struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev);
-       struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       struct resource *meram = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-
-       pm_runtime_disable(&pdev->dev);
-
-       gen_pool_destroy(priv->pool);
-
-       iounmap(priv->base);
-       release_mem_region(meram->start, resource_size(meram));
-       release_mem_region(regs->start, resource_size(regs));
-
-       mutex_destroy(&priv->lock);
-
-       kfree(priv);
-
-       return 0;
-}
-
-static struct platform_driver sh_mobile_meram_driver = {
-       .driver = {
-               .name           = "sh_mobile_meram",
-               .pm             = &sh_mobile_meram_dev_pm_ops,
-       },
-       .probe          = sh_mobile_meram_probe,
-       .remove         = sh_mobile_meram_remove,
-};
-
-module_platform_driver(sh_mobile_meram_driver);
-
-MODULE_DESCRIPTION("SuperH Mobile MERAM driver");
-MODULE_AUTHOR("Damian Hobson-Garcia / Takanari Hayama");
-MODULE_LICENSE("GPL v2");
index 7f4e908330bf0509014612a1fa2a3bf4be1e2e7c..812a36cb60c3efa932a7d305a7d111a5cd49ed3a 100644 (file)
@@ -836,7 +836,7 @@ static void xxxfb_remove(struct pci_dev *dev)
  *     @dev: PCI device
  *     @msg: the suspend event code.
  *
- *      See Documentation/power/admin-guide/devices.rst for more information
+ *      See Documentation/driver-api/pm/devices.rst for more information
  */
 static int xxxfb_suspend(struct pci_dev *dev, pm_message_t msg)
 {
@@ -851,7 +851,7 @@ static int xxxfb_suspend(struct pci_dev *dev, pm_message_t msg)
  *     xxxfb_resume - Optional but recommended function. Resume the device.
  *     @dev: PCI device
  *
- *      See Documentation/power/admin-guide/devices.rst for more information
+ *      See Documentation/driver-api/pm/devices.rst for more information
  */
 static int xxxfb_resume(struct pci_dev *dev)
 {
@@ -915,7 +915,7 @@ static void __exit xxxfb_exit(void)
  *     @dev: platform device
  *     @msg: the suspend event code.
  *
- *      See Documentation/power/admin-guide/devices.rst for more information
+ *      See Documentation/driver-api/pm/devices.rst for more information
  */
 static int xxxfb_suspend(struct platform_device *dev, pm_message_t msg)
 {
@@ -930,7 +930,7 @@ static int xxxfb_suspend(struct platform_device *dev, pm_message_t msg)
  *     xxxfb_resume - Optional but recommended function. Resume the device.
  *     @dev: platform device
  *
- *      See Documentation/power/admin-guide/devices.rst for more information
+ *      See Documentation/driver-api/pm/devices.rst for more information
  */
 static int xxxfb_resume(struct platform_dev *dev)
 {
index 6f0a19501c6a8d959e1f4a994e705934808d4c77..dde52d0274168dde174a3cafb16cb9ba532ecb97 100644 (file)
@@ -1932,8 +1932,7 @@ static int sm501fb_probe(struct platform_device *pdev)
        int ret;
 
        /* allocate our framebuffers */
-
-       info = kzalloc(sizeof(struct sm501fb_info), GFP_KERNEL);
+       info = kzalloc(sizeof(*info), GFP_KERNEL);
        if (!info) {
                dev_err(dev, "failed to allocate state\n");
                return -ENOMEM;
index 275dbbbd6b81227ac690028588ac24c7691ffe8a..649d2ca5516ead7cfa521401fec9ac661849b1f7 100644 (file)
 #include <linux/console.h>
 #include <linux/timer.h>
 
+#ifdef CONFIG_X86
+#include <asm/olpc.h>
+#else
+#define machine_is_olpc(x) 0
+#endif
+
 #include "debug.h"
 
 #include "viafbdev.h"
index 22450908306c3f77b454a6396d82c6363f60943d..48969c6445998a43fbfdd2654e539bf5c4a3a63c 100644 (file)
@@ -20,7 +20,6 @@
  */
 
 #include <linux/via-core.h>
-#include <asm/olpc.h>
 #include "global.h"
 #include "via_clock.h"
 
index 77774d8abf94dff3bb24d94552630a9ecb63c754..b041eb27a9bff7aac488968306c83102b6c4edfd 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/platform_device.h>
 #include <linux/list.h>
 #include <linux/pm.h>
-#include <asm/olpc.h>
 
 /*
  * The default port config.
index bf269fa43977e6d7a83dda2269b2d191a08221ef..3d0efdbaea58086c476a2914ade60bdcc7e7f723 100644 (file)
@@ -25,7 +25,7 @@
 
 #include <linux/kernel.h>
 #include <linux/via-core.h>
-#include <asm/olpc.h>
+
 #include "via_clock.h"
 #include "global.h"
 #include "debug.h"
index 52f577b0669b00a737168d117483c3cc9a9beac9..d2f785068ef4bb97fbc7228a684eae00d0688280 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/stat.h>
 #include <linux/via-core.h>
 #include <linux/via_i2c.h>
-#include <asm/olpc.h>
 
 #define _MASTER_FILE
 #include "global.h"
index b563a4499cc86346572e23e1257e57cf034c5dc6..705aebd74e560cd8d125cee28537e9734dabe518 100644 (file)
@@ -578,6 +578,8 @@ static void virtio_pci_remove(struct pci_dev *pci_dev)
        struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
        struct device *dev = get_device(&vp_dev->vdev.dev);
 
+       pci_disable_sriov(pci_dev);
+
        unregister_virtio_device(&vp_dev->vdev);
 
        if (vp_dev->ioaddr)
@@ -589,6 +591,33 @@ static void virtio_pci_remove(struct pci_dev *pci_dev)
        put_device(dev);
 }
 
+static int virtio_pci_sriov_configure(struct pci_dev *pci_dev, int num_vfs)
+{
+       struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
+       struct virtio_device *vdev = &vp_dev->vdev;
+       int ret;
+
+       if (!(vdev->config->get_status(vdev) & VIRTIO_CONFIG_S_DRIVER_OK))
+               return -EBUSY;
+
+       if (!__virtio_test_bit(vdev, VIRTIO_F_SR_IOV))
+               return -EINVAL;
+
+       if (pci_vfs_assigned(pci_dev))
+               return -EPERM;
+
+       if (num_vfs == 0) {
+               pci_disable_sriov(pci_dev);
+               return 0;
+       }
+
+       ret = pci_enable_sriov(pci_dev, num_vfs);
+       if (ret < 0)
+               return ret;
+
+       return num_vfs;
+}
+
 static struct pci_driver virtio_pci_driver = {
        .name           = "virtio-pci",
        .id_table       = virtio_pci_id_table,
@@ -597,6 +626,7 @@ static struct pci_driver virtio_pci_driver = {
 #ifdef CONFIG_PM_SLEEP
        .driver.pm      = &virtio_pci_pm_ops,
 #endif
+       .sriov_configure = virtio_pci_sriov_configure,
 };
 
 module_pci_driver(virtio_pci_driver);
index 2555d80f6eec4b4a78860b46f453092051b50a24..07571daccfec13581a7e5ce59c242de4e2ef1bb6 100644 (file)
@@ -153,14 +153,28 @@ static u64 vp_get_features(struct virtio_device *vdev)
        return features;
 }
 
+static void vp_transport_features(struct virtio_device *vdev, u64 features)
+{
+       struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+       struct pci_dev *pci_dev = vp_dev->pci_dev;
+
+       if ((features & BIT_ULL(VIRTIO_F_SR_IOV)) &&
+                       pci_find_ext_capability(pci_dev, PCI_EXT_CAP_ID_SRIOV))
+               __virtio_set_bit(vdev, VIRTIO_F_SR_IOV);
+}
+
 /* virtio config->finalize_features() implementation */
 static int vp_finalize_features(struct virtio_device *vdev)
 {
        struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+       u64 features = vdev->features;
 
        /* Give virtio_ring a chance to accept features. */
        vring_transport_features(vdev);
 
+       /* Give virtio_pci a chance to accept features. */
+       vp_transport_features(vdev, features);
+
        if (!__virtio_test_bit(vdev, VIRTIO_F_VERSION_1)) {
                dev_err(&vdev->dev, "virtio: device uses modern interface "
                        "but does not have VIRTIO_F_VERSION_1\n");
index 57a27c42b5aca07bf40d649025047fa758b3df5c..56df483de619cc44ca8c25c2b7daf6f3783de937 100644 (file)
@@ -168,7 +168,7 @@ config BINFMT_MISC
          will automatically feed it to the correct interpreter.
 
          You can do other nice things, too. Read the file
-         <file:Documentation/binfmt_misc.txt> to learn how to use this
+         <file:Documentation/admin-guide/binfmt-misc.rst> to learn how to use this
          feature, <file:Documentation/admin-guide/java.rst> for information about how
          to include Java support. and <file:Documentation/admin-guide/mono.rst> for
           information about how to include Mono-based .NET support.
index 8dbd36f5e5811626ff71806d62c983e7ea35e288..c836c425ca94587e381fc9c9a867594717d88cd6 100644 (file)
@@ -199,7 +199,7 @@ adfs_adfs2unix_time(struct timespec *tv, struct inode *inode)
        return;
 
  cur_time:
-       *tv = current_time(inode);
+       *tv = timespec64_to_timespec(current_time(inode));
        return;
 
  too_early:
@@ -242,6 +242,7 @@ adfs_unix2adfs_time(struct inode *inode, unsigned int secs)
 struct inode *
 adfs_iget(struct super_block *sb, struct object_info *obj)
 {
+       struct timespec ts;
        struct inode *inode;
 
        inode = new_inode(sb);
@@ -270,7 +271,9 @@ adfs_iget(struct super_block *sb, struct object_info *obj)
        ADFS_I(inode)->stamped   = ((obj->loadaddr & 0xfff00000) == 0xfff00000);
 
        inode->i_mode    = adfs_atts2mode(sb, inode);
-       adfs_adfs2unix_time(&inode->i_mtime, inode);
+       ts = timespec64_to_timespec(inode->i_mtime);
+       adfs_adfs2unix_time(&ts, inode);
+       inode->i_mtime = timespec_to_timespec64(ts);
        inode->i_atime = inode->i_mtime;
        inode->i_ctime = inode->i_mtime;
 
index 532acae25453268477d7bc3e7a399e6e4a0c2ad8..546874057bd3594bd0997d37b8801fd866461077 100644 (file)
@@ -5,7 +5,7 @@
 
 afs-cache-$(CONFIG_AFS_FSCACHE) := cache.o
 
-kafs-objs := \
+kafs-y := \
        $(afs-cache-y) \
        addr_list.o \
        callback.o \
@@ -21,7 +21,6 @@ kafs-objs := \
        main.o \
        misc.o \
        mntpt.o \
-       proc.o \
        rotate.o \
        rxrpc.o \
        security.o \
@@ -34,4 +33,5 @@ kafs-objs := \
        write.o \
        xattr.o
 
+kafs-$(CONFIG_PROC_FS) += proc.o
 obj-$(CONFIG_AFS_FS)  := kafs.o
index 2c46c46f3a6d2ed362b2de1e8106044a80caedfb..025a9a5e1c32c29c4daf3cd40aba8537475af250 100644 (file)
@@ -215,7 +215,7 @@ struct afs_addr_list *afs_dns_query(struct afs_cell *cell, time64_t *_expiry)
        _enter("%s", cell->name);
 
        ret = dns_query("afsdb", cell->name, cell->name_len,
-                       "ipv4", &vllist, _expiry);
+                       "", &vllist, _expiry);
        if (ret < 0)
                return ERR_PTR(ret);
 
index 571437dcb252842578b92a6f3b5b60a574703b94..5f261fbf2182b22a47fc93b7c6fee35f113e0097 100644 (file)
 #include <linux/sched.h>
 #include "internal.h"
 
+/*
+ * Create volume and callback interests on a server.
+ */
+static struct afs_cb_interest *afs_create_interest(struct afs_server *server,
+                                                  struct afs_vnode *vnode)
+{
+       struct afs_vol_interest *new_vi, *vi;
+       struct afs_cb_interest *new;
+       struct hlist_node **pp;
+
+       new_vi = kzalloc(sizeof(struct afs_vol_interest), GFP_KERNEL);
+       if (!new_vi)
+               return NULL;
+
+       new = kzalloc(sizeof(struct afs_cb_interest), GFP_KERNEL);
+       if (!new) {
+               kfree(new_vi);
+               return NULL;
+       }
+
+       new_vi->usage = 1;
+       new_vi->vid = vnode->volume->vid;
+       INIT_HLIST_NODE(&new_vi->srv_link);
+       INIT_HLIST_HEAD(&new_vi->cb_interests);
+
+       refcount_set(&new->usage, 1);
+       new->sb = vnode->vfs_inode.i_sb;
+       new->vid = vnode->volume->vid;
+       new->server = afs_get_server(server);
+       INIT_HLIST_NODE(&new->cb_vlink);
+
+       write_lock(&server->cb_break_lock);
+
+       for (pp = &server->cb_volumes.first; *pp; pp = &(*pp)->next) {
+               vi = hlist_entry(*pp, struct afs_vol_interest, srv_link);
+               if (vi->vid < new_vi->vid)
+                       continue;
+               if (vi->vid > new_vi->vid)
+                       break;
+               vi->usage++;
+               goto found_vi;
+       }
+
+       new_vi->srv_link.pprev = pp;
+       new_vi->srv_link.next = *pp;
+       if (*pp)
+               (*pp)->pprev = &new_vi->srv_link.next;
+       *pp = &new_vi->srv_link;
+       vi = new_vi;
+       new_vi = NULL;
+found_vi:
+
+       new->vol_interest = vi;
+       hlist_add_head(&new->cb_vlink, &vi->cb_interests);
+
+       write_unlock(&server->cb_break_lock);
+       kfree(new_vi);
+       return new;
+}
+
 /*
  * Set up an interest-in-callbacks record for a volume on a server and
  * register it with the server.
@@ -77,20 +137,10 @@ again:
        }
 
        if (!cbi) {
-               new = kzalloc(sizeof(struct afs_cb_interest), GFP_KERNEL);
+               new = afs_create_interest(server, vnode);
                if (!new)
                        return -ENOMEM;
 
-               refcount_set(&new->usage, 1);
-               new->sb = vnode->vfs_inode.i_sb;
-               new->vid = vnode->volume->vid;
-               new->server = afs_get_server(server);
-               INIT_LIST_HEAD(&new->cb_link);
-
-               write_lock(&server->cb_break_lock);
-               list_add_tail(&new->cb_link, &server->cb_interests);
-               write_unlock(&server->cb_break_lock);
-
                write_lock(&slist->lock);
                if (!entry->cb_interest) {
                        entry->cb_interest = afs_get_cb_interest(new);
@@ -126,11 +176,22 @@ again:
  */
 void afs_put_cb_interest(struct afs_net *net, struct afs_cb_interest *cbi)
 {
+       struct afs_vol_interest *vi;
+
        if (cbi && refcount_dec_and_test(&cbi->usage)) {
-               if (!list_empty(&cbi->cb_link)) {
+               if (!hlist_unhashed(&cbi->cb_vlink)) {
                        write_lock(&cbi->server->cb_break_lock);
-                       list_del_init(&cbi->cb_link);
+
+                       hlist_del_init(&cbi->cb_vlink);
+                       vi = cbi->vol_interest;
+                       cbi->vol_interest = NULL;
+                       if (--vi->usage == 0)
+                               hlist_del(&vi->srv_link);
+                       else
+                               vi = NULL;
+
                        write_unlock(&cbi->server->cb_break_lock);
+                       kfree(vi);
                        afs_put_server(net, cbi->server);
                }
                kfree(cbi);
@@ -182,20 +243,34 @@ void afs_break_callback(struct afs_vnode *vnode)
 static void afs_break_one_callback(struct afs_server *server,
                                   struct afs_fid *fid)
 {
+       struct afs_vol_interest *vi;
        struct afs_cb_interest *cbi;
        struct afs_iget_data data;
        struct afs_vnode *vnode;
        struct inode *inode;
 
        read_lock(&server->cb_break_lock);
+       hlist_for_each_entry(vi, &server->cb_volumes, srv_link) {
+               if (vi->vid < fid->vid)
+                       continue;
+               if (vi->vid > fid->vid) {
+                       vi = NULL;
+                       break;
+               }
+               //atomic_inc(&vi->usage);
+               break;
+       }
+
+       /* TODO: Find all matching volumes if we couldn't match the server and
+        * break them anyway.
+        */
+       if (!vi)
+               goto out;
 
        /* Step through all interested superblocks.  There may be more than one
         * because of cell aliasing.
         */
-       list_for_each_entry(cbi, &server->cb_interests, cb_link) {
-               if (cbi->vid != fid->vid)
-                       continue;
-
+       hlist_for_each_entry(cbi, &vi->cb_interests, cb_vlink) {
                if (fid->vnode == 0 && fid->unique == 0) {
                        /* The callback break applies to an entire volume. */
                        struct afs_super_info *as = AFS_FS_S(cbi->sb);
@@ -217,6 +292,7 @@ static void afs_break_one_callback(struct afs_server *server,
                }
        }
 
+out:
        read_unlock(&server->cb_break_lock);
 }
 
index fdf4c36cff79ead65acf11a36b99614db924fe9b..f3d0bef16d78b99291c28e39fc266fa59098572d 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/dns_resolver.h>
 #include <linux/sched.h>
 #include <linux/inet.h>
+#include <linux/namei.h>
 #include <keys/rxrpc-type.h>
 #include "internal.h"
 
@@ -341,8 +342,8 @@ int afs_cell_init(struct afs_net *net, const char *rootcell)
 
        /* install the new cell */
        write_seqlock(&net->cells_lock);
-       old_root = net->ws_cell;
-       net->ws_cell = new_root;
+       old_root = rcu_access_pointer(net->ws_cell);
+       rcu_assign_pointer(net->ws_cell, new_root);
        write_sequnlock(&net->cells_lock);
 
        afs_put_cell(net, old_root);
@@ -528,12 +529,14 @@ static int afs_activate_cell(struct afs_net *net, struct afs_cell *cell)
                                             NULL, 0,
                                             cell, 0, true);
 #endif
-       ret = afs_proc_cell_setup(net, cell);
+       ret = afs_proc_cell_setup(cell);
        if (ret < 0)
                return ret;
-       spin_lock(&net->proc_cells_lock);
+
+       mutex_lock(&net->proc_cells_lock);
        list_add_tail(&cell->proc_link, &net->proc_cells);
-       spin_unlock(&net->proc_cells_lock);
+       afs_dynroot_mkdir(net, cell);
+       mutex_unlock(&net->proc_cells_lock);
        return 0;
 }
 
@@ -544,11 +547,12 @@ static void afs_deactivate_cell(struct afs_net *net, struct afs_cell *cell)
 {
        _enter("%s", cell->name);
 
-       afs_proc_cell_remove(net, cell);
+       afs_proc_cell_remove(cell);
 
-       spin_lock(&net->proc_cells_lock);
+       mutex_lock(&net->proc_cells_lock);
        list_del_init(&cell->proc_link);
-       spin_unlock(&net->proc_cells_lock);
+       afs_dynroot_rmdir(net, cell);
+       mutex_unlock(&net->proc_cells_lock);
 
 #ifdef CONFIG_AFS_FSCACHE
        fscache_relinquish_cookie(cell->cache, NULL, false);
@@ -755,8 +759,8 @@ void afs_cell_purge(struct afs_net *net)
        _enter("");
 
        write_seqlock(&net->cells_lock);
-       ws = net->ws_cell;
-       net->ws_cell = NULL;
+       ws = rcu_access_pointer(net->ws_cell);
+       RCU_INIT_POINTER(net->ws_cell, NULL);
        write_sequnlock(&net->cells_lock);
        afs_put_cell(net, ws);
 
index 238fd28cfdd2cabae2fbf1530ed923be387c5517..9e51d6fe7e8f975f34f877217a28a8e99bcfa5e4 100644 (file)
@@ -526,7 +526,7 @@ static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work)
        nifs = 0;
        ifs = kcalloc(32, sizeof(*ifs), GFP_KERNEL);
        if (ifs) {
-               nifs = afs_get_ipv4_interfaces(ifs, 32, false);
+               nifs = afs_get_ipv4_interfaces(call->net, ifs, 32, false);
                if (nifs < 0) {
                        kfree(ifs);
                        ifs = NULL;
index 983f3946ab576927850bd62e84308cf565de456f..174e843f06330187e3da4d5f1132493511dd4f5b 100644 (file)
@@ -1,4 +1,4 @@
-/* dir.c: AFS dynamic root handling
+/* AFS dynamic root handling
  *
  * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
@@ -46,7 +46,7 @@ static int afs_probe_cell_name(struct dentry *dentry)
                return 0;
        }
 
-       ret = dns_query("afsdb", name, len, "ipv4", NULL, NULL);
+       ret = dns_query("afsdb", name, len, "", NULL, NULL);
        if (ret == -ENODATA)
                ret = -EDESTADDRREQ;
        return ret;
@@ -207,3 +207,125 @@ const struct dentry_operations afs_dynroot_dentry_operations = {
        .d_release      = afs_d_release,
        .d_automount    = afs_d_automount,
 };
+
+/*
+ * Create a manually added cell mount directory.
+ * - The caller must hold net->proc_cells_lock
+ */
+int afs_dynroot_mkdir(struct afs_net *net, struct afs_cell *cell)
+{
+       struct super_block *sb = net->dynroot_sb;
+       struct dentry *root, *subdir;
+       int ret;
+
+       if (!sb || atomic_read(&sb->s_active) == 0)
+               return 0;
+
+       /* Let the ->lookup op do the creation */
+       root = sb->s_root;
+       inode_lock(root->d_inode);
+       subdir = lookup_one_len(cell->name, root, cell->name_len);
+       if (IS_ERR(subdir)) {
+               ret = PTR_ERR(subdir);
+               goto unlock;
+       }
+
+       /* Note that we're retaining an extra ref on the dentry */
+       subdir->d_fsdata = (void *)1UL;
+       ret = 0;
+unlock:
+       inode_unlock(root->d_inode);
+       return ret;
+}
+
+/*
+ * Remove a manually added cell mount directory.
+ * - The caller must hold net->proc_cells_lock
+ */
+void afs_dynroot_rmdir(struct afs_net *net, struct afs_cell *cell)
+{
+       struct super_block *sb = net->dynroot_sb;
+       struct dentry *root, *subdir;
+
+       if (!sb || atomic_read(&sb->s_active) == 0)
+               return;
+
+       root = sb->s_root;
+       inode_lock(root->d_inode);
+
+       /* Don't want to trigger a lookup call, which will re-add the cell */
+       subdir = try_lookup_one_len(cell->name, root, cell->name_len);
+       if (IS_ERR_OR_NULL(subdir)) {
+               _debug("lookup %ld", PTR_ERR(subdir));
+               goto no_dentry;
+       }
+
+       _debug("rmdir %pd %u", subdir, d_count(subdir));
+
+       if (subdir->d_fsdata) {
+               _debug("unpin %u", d_count(subdir));
+               subdir->d_fsdata = NULL;
+               dput(subdir);
+       }
+       dput(subdir);
+no_dentry:
+       inode_unlock(root->d_inode);
+       _leave("");
+}
+
+/*
+ * Populate a newly created dynamic root with cell names.
+ */
+int afs_dynroot_populate(struct super_block *sb)
+{
+       struct afs_cell *cell;
+       struct afs_net *net = afs_sb2net(sb);
+       int ret;
+
+       if (mutex_lock_interruptible(&net->proc_cells_lock) < 0)
+               return -ERESTARTSYS;
+
+       net->dynroot_sb = sb;
+       list_for_each_entry(cell, &net->proc_cells, proc_link) {
+               ret = afs_dynroot_mkdir(net, cell);
+               if (ret < 0)
+                       goto error;
+       }
+
+       ret = 0;
+out:
+       mutex_unlock(&net->proc_cells_lock);
+       return ret;
+
+error:
+       net->dynroot_sb = NULL;
+       goto out;
+}
+
+/*
+ * When a dynamic root that's in the process of being destroyed, depopulate it
+ * of pinned directories.
+ */
+void afs_dynroot_depopulate(struct super_block *sb)
+{
+       struct afs_net *net = afs_sb2net(sb);
+       struct dentry *root = sb->s_root, *subdir, *tmp;
+
+       /* Prevent more subdirs from being created */
+       mutex_lock(&net->proc_cells_lock);
+       if (net->dynroot_sb == sb)
+               net->dynroot_sb = NULL;
+       mutex_unlock(&net->proc_cells_lock);
+
+       inode_lock(root->d_inode);
+
+       /* Remove all the pins for dirs created for manually added cells */
+       list_for_each_entry_safe(subdir, tmp, &root->d_subdirs, d_child) {
+               if (subdir->d_fsdata) {
+                       subdir->d_fsdata = NULL;
+                       dput(subdir);
+               }
+       }
+
+       inode_unlock(root->d_inode);
+}
index b273e1d60478c3c9f89a84a7b85fb6325a9a2c84..50929cb91732f5adec19706788e6a31aeb8beb03 100644 (file)
@@ -72,7 +72,7 @@ void afs_update_inode_from_status(struct afs_vnode *vnode,
                                  const afs_dataversion_t *expected_version,
                                  u8 flags)
 {
-       struct timespec t;
+       struct timespec64 t;
        umode_t mode;
 
        t.tv_sec = status->mtime_client;
@@ -138,10 +138,6 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call,
        u64 data_version, size;
        u32 type, abort_code;
        u8 flags = 0;
-       int ret;
-
-       if (vnode)
-               write_seqlock(&vnode->cb_lock);
 
        abort_code = ntohl(xdr->abort_code);
 
@@ -154,8 +150,7 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call,
                         * case.
                         */
                        status->abort_code = abort_code;
-                       ret = 0;
-                       goto out;
+                       return 0;
                }
 
                pr_warn("Unknown AFSFetchStatus version %u\n", ntohl(xdr->if_version));
@@ -164,8 +159,7 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call,
 
        if (abort_code != 0 && inline_error) {
                status->abort_code = abort_code;
-               ret = 0;
-               goto out;
+               return 0;
        }
 
        type = ntohl(xdr->type);
@@ -235,17 +229,35 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call,
                                             flags);
        }
 
-       ret = 0;
-
-out:
-       if (vnode)
-               write_sequnlock(&vnode->cb_lock);
-       return ret;
+       return 0;
 
 bad:
        xdr_dump_bad(*_bp);
-       ret = afs_protocol_error(call, -EBADMSG);
-       goto out;
+       return afs_protocol_error(call, -EBADMSG);
+}
+
+/*
+ * Decode the file status.  We need to lock the target vnode if we're going to
+ * update its status so that stat() sees the attributes update atomically.
+ */
+static int afs_decode_status(struct afs_call *call,
+                            const __be32 **_bp,
+                            struct afs_file_status *status,
+                            struct afs_vnode *vnode,
+                            const afs_dataversion_t *expected_version,
+                            struct afs_read *read_req)
+{
+       int ret;
+
+       if (!vnode)
+               return xdr_decode_AFSFetchStatus(call, _bp, status, vnode,
+                                                expected_version, read_req);
+
+       write_seqlock(&vnode->cb_lock);
+       ret = xdr_decode_AFSFetchStatus(call, _bp, status, vnode,
+                                       expected_version, read_req);
+       write_sequnlock(&vnode->cb_lock);
+       return ret;
 }
 
 /*
@@ -387,8 +399,8 @@ static int afs_deliver_fs_fetch_status_vnode(struct afs_call *call)
 
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
-       if (xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode,
-                                     &call->expected_version, NULL) < 0)
+       if (afs_decode_status(call, &bp, &vnode->status, vnode,
+                             &call->expected_version, NULL) < 0)
                return afs_protocol_error(call, -EBADMSG);
        xdr_decode_AFSCallBack(call, vnode, &bp);
        if (call->reply[1])
@@ -568,8 +580,8 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
                        return ret;
 
                bp = call->buffer;
-               if (xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode,
-                                             &vnode->status.data_version, req) < 0)
+               if (afs_decode_status(call, &bp, &vnode->status, vnode,
+                                     &vnode->status.data_version, req) < 0)
                        return afs_protocol_error(call, -EBADMSG);
                xdr_decode_AFSCallBack(call, vnode, &bp);
                if (call->reply[1])
@@ -721,9 +733,9 @@ static int afs_deliver_fs_create_vnode(struct afs_call *call)
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
        xdr_decode_AFSFid(&bp, call->reply[1]);
-       if (xdr_decode_AFSFetchStatus(call, &bp, call->reply[2], NULL, NULL, NULL) < 0 ||
-           xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode,
-                                     &call->expected_version, NULL) < 0)
+       if (afs_decode_status(call, &bp, call->reply[2], NULL, NULL, NULL) < 0 ||
+           afs_decode_status(call, &bp, &vnode->status, vnode,
+                             &call->expected_version, NULL) < 0)
                return afs_protocol_error(call, -EBADMSG);
        xdr_decode_AFSCallBack_raw(&bp, call->reply[3]);
        /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
@@ -827,8 +839,8 @@ static int afs_deliver_fs_remove(struct afs_call *call)
 
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
-       if (xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode,
-                                     &call->expected_version, NULL) < 0)
+       if (afs_decode_status(call, &bp, &vnode->status, vnode,
+                             &call->expected_version, NULL) < 0)
                return afs_protocol_error(call, -EBADMSG);
        /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
 
@@ -917,9 +929,9 @@ static int afs_deliver_fs_link(struct afs_call *call)
 
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
-       if (xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode, NULL, NULL) < 0 ||
-           xdr_decode_AFSFetchStatus(call, &bp, &dvnode->status, dvnode,
-                                     &call->expected_version, NULL) < 0)
+       if (afs_decode_status(call, &bp, &vnode->status, vnode, NULL, NULL) < 0 ||
+           afs_decode_status(call, &bp, &dvnode->status, dvnode,
+                             &call->expected_version, NULL) < 0)
                return afs_protocol_error(call, -EBADMSG);
        /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
 
@@ -1004,9 +1016,9 @@ static int afs_deliver_fs_symlink(struct afs_call *call)
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
        xdr_decode_AFSFid(&bp, call->reply[1]);
-       if (xdr_decode_AFSFetchStatus(call, &bp, call->reply[2], NULL, NULL, NULL) ||
-           xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode,
-                                     &call->expected_version, NULL) < 0)
+       if (afs_decode_status(call, &bp, call->reply[2], NULL, NULL, NULL) ||
+           afs_decode_status(call, &bp, &vnode->status, vnode,
+                             &call->expected_version, NULL) < 0)
                return afs_protocol_error(call, -EBADMSG);
        /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
 
@@ -1110,12 +1122,12 @@ static int afs_deliver_fs_rename(struct afs_call *call)
 
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
-       if (xdr_decode_AFSFetchStatus(call, &bp, &orig_dvnode->status, orig_dvnode,
-                                     &call->expected_version, NULL) < 0)
+       if (afs_decode_status(call, &bp, &orig_dvnode->status, orig_dvnode,
+                             &call->expected_version, NULL) < 0)
                return afs_protocol_error(call, -EBADMSG);
        if (new_dvnode != orig_dvnode &&
-           xdr_decode_AFSFetchStatus(call, &bp, &new_dvnode->status, new_dvnode,
-                                     &call->expected_version_2, NULL) < 0)
+           afs_decode_status(call, &bp, &new_dvnode->status, new_dvnode,
+                             &call->expected_version_2, NULL) < 0)
                return afs_protocol_error(call, -EBADMSG);
        /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
 
@@ -1219,8 +1231,8 @@ static int afs_deliver_fs_store_data(struct afs_call *call)
 
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
-       if (xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode,
-                                     &call->expected_version, NULL) < 0)
+       if (afs_decode_status(call, &bp, &vnode->status, vnode,
+                             &call->expected_version, NULL) < 0)
                return afs_protocol_error(call, -EBADMSG);
        /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
 
@@ -1395,8 +1407,8 @@ static int afs_deliver_fs_store_status(struct afs_call *call)
 
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
-       if (xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode,
-                                     &call->expected_version, NULL) < 0)
+       if (afs_decode_status(call, &bp, &vnode->status, vnode,
+                             &call->expected_version, NULL) < 0)
                return afs_protocol_error(call, -EBADMSG);
        /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
 
@@ -2097,8 +2109,8 @@ static int afs_deliver_fs_fetch_status(struct afs_call *call)
 
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
-       xdr_decode_AFSFetchStatus(call, &bp, status, vnode,
-                                 &call->expected_version, NULL);
+       afs_decode_status(call, &bp, status, vnode,
+                         &call->expected_version, NULL);
        callback[call->count].version   = ntohl(bp[0]);
        callback[call->count].expiry    = ntohl(bp[1]);
        callback[call->count].type      = ntohl(bp[2]);
@@ -2209,9 +2221,9 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
 
                bp = call->buffer;
                statuses = call->reply[1];
-               if (xdr_decode_AFSFetchStatus(call, &bp, &statuses[call->count],
-                                             call->count == 0 ? vnode : NULL,
-                                             NULL, NULL) < 0)
+               if (afs_decode_status(call, &bp, &statuses[call->count],
+                                     call->count == 0 ? vnode : NULL,
+                                     NULL, NULL) < 0)
                        return afs_protocol_error(call, -EBADMSG);
 
                call->count++;
index e3f8a46663dbade0149d44e0d543bb7f171170a7..9778df1357179d14238cfa52e7394886206a1f1d 100644 (file)
@@ -22,6 +22,8 @@
 #include <linux/backing-dev.h>
 #include <linux/uuid.h>
 #include <net/net_namespace.h>
+#include <net/netns/generic.h>
+#include <net/sock.h>
 #include <net/af_rxrpc.h>
 
 #include "afs.h"
@@ -40,7 +42,8 @@ struct afs_mount_params {
        afs_voltype_t           type;           /* type of volume requested */
        int                     volnamesz;      /* size of volume name */
        const char              *volname;       /* name of volume to mount */
-       struct afs_net          *net;           /* Network namespace in effect */
+       struct net              *net_ns;        /* Network namespace in effect */
+       struct afs_net          *net;           /* the AFS net namespace stuff */
        struct afs_cell         *cell;          /* cell in which to find volume */
        struct afs_volume       *volume;        /* volume record */
        struct key              *key;           /* key to use for secure mounting */
@@ -189,7 +192,7 @@ struct afs_read {
  * - there's one superblock per volume
  */
 struct afs_super_info {
-       struct afs_net          *net;           /* Network namespace */
+       struct net              *net_ns;        /* Network namespace */
        struct afs_cell         *cell;          /* The cell in which the volume resides */
        struct afs_volume       *volume;        /* volume record */
        bool                    dyn_root;       /* True if dynamic root */
@@ -210,7 +213,6 @@ struct afs_sysnames {
        char                    *subs[AFS_NR_SYSNAME];
        refcount_t              usage;
        unsigned short          nr;
-       short                   error;
        char                    blank[1];
 };
 
@@ -218,6 +220,7 @@ struct afs_sysnames {
  * AFS network namespace record.
  */
 struct afs_net {
+       struct net              *net;           /* Backpointer to the owning net namespace */
        struct afs_uuid         uuid;
        bool                    live;           /* F if this namespace is being removed */
 
@@ -231,13 +234,13 @@ struct afs_net {
 
        /* Cell database */
        struct rb_root          cells;
-       struct afs_cell         *ws_cell;
+       struct afs_cell __rcu   *ws_cell;
        struct work_struct      cells_manager;
        struct timer_list       cells_timer;
        atomic_t                cells_outstanding;
        seqlock_t               cells_lock;
 
-       spinlock_t              proc_cells_lock;
+       struct mutex            proc_cells_lock;
        struct list_head        proc_cells;
 
        /* Known servers.  Theoretically each fileserver can only be in one
@@ -261,6 +264,7 @@ struct afs_net {
        struct mutex            lock_manager_mutex;
 
        /* Misc */
+       struct super_block      *dynroot_sb;    /* Dynamic root mount superblock */
        struct proc_dir_entry   *proc_afs;      /* /proc/net/afs directory */
        struct afs_sysnames     *sysnames;
        rwlock_t                sysnames_lock;
@@ -280,7 +284,6 @@ struct afs_net {
 };
 
 extern const char afs_init_sysname[];
-extern struct afs_net __afs_net;// Dummy AFS network namespace; TODO: replace with real netns
 
 enum afs_cell_state {
        AFS_CELL_UNSET,
@@ -404,16 +407,27 @@ struct afs_server {
        rwlock_t                fs_lock;        /* access lock */
 
        /* callback promise management */
-       struct list_head        cb_interests;   /* List of superblocks using this server */
+       struct hlist_head       cb_volumes;     /* List of volume interests on this server */
        unsigned                cb_s_break;     /* Break-everything counter. */
        rwlock_t                cb_break_lock;  /* Volume finding lock */
 };
 
+/*
+ * Volume collation in the server's callback interest list.
+ */
+struct afs_vol_interest {
+       struct hlist_node       srv_link;       /* Link in server->cb_volumes */
+       struct hlist_head       cb_interests;   /* List of callback interests on the server */
+       afs_volid_t             vid;            /* Volume ID to match */
+       unsigned int            usage;
+};
+
 /*
  * Interest by a superblock on a server.
  */
 struct afs_cb_interest {
-       struct list_head        cb_link;        /* Link in server->cb_interests */
+       struct hlist_node       cb_vlink;       /* Link in vol_interest->cb_interests */
+       struct afs_vol_interest *vol_interest;
        struct afs_server       *server;        /* Server on which this interest resides */
        struct super_block      *sb;            /* Superblock on which inodes reside */
        afs_volid_t             vid;            /* Volume ID to match */
@@ -720,6 +734,10 @@ extern const struct inode_operations afs_dynroot_inode_operations;
 extern const struct dentry_operations afs_dynroot_dentry_operations;
 
 extern struct inode *afs_try_auto_mntpt(struct dentry *, struct inode *);
+extern int afs_dynroot_mkdir(struct afs_net *, struct afs_cell *);
+extern void afs_dynroot_rmdir(struct afs_net *, struct afs_cell *);
+extern int afs_dynroot_populate(struct super_block *);
+extern void afs_dynroot_depopulate(struct super_block *);
 
 /*
  * file.c
@@ -806,34 +824,36 @@ extern int afs_drop_inode(struct inode *);
  * main.c
  */
 extern struct workqueue_struct *afs_wq;
+extern int afs_net_id;
 
-static inline struct afs_net *afs_d2net(struct dentry *dentry)
+static inline struct afs_net *afs_net(struct net *net)
 {
-       return &__afs_net;
+       return net_generic(net, afs_net_id);
 }
 
-static inline struct afs_net *afs_i2net(struct inode *inode)
+static inline struct afs_net *afs_sb2net(struct super_block *sb)
 {
-       return &__afs_net;
+       return afs_net(AFS_FS_S(sb)->net_ns);
 }
 
-static inline struct afs_net *afs_v2net(struct afs_vnode *vnode)
+static inline struct afs_net *afs_d2net(struct dentry *dentry)
 {
-       return &__afs_net;
+       return afs_sb2net(dentry->d_sb);
 }
 
-static inline struct afs_net *afs_sock2net(struct sock *sk)
+static inline struct afs_net *afs_i2net(struct inode *inode)
 {
-       return &__afs_net;
+       return afs_sb2net(inode->i_sb);
 }
 
-static inline struct afs_net *afs_get_net(struct afs_net *net)
+static inline struct afs_net *afs_v2net(struct afs_vnode *vnode)
 {
-       return net;
+       return afs_i2net(&vnode->vfs_inode);
 }
 
-static inline void afs_put_net(struct afs_net *net)
+static inline struct afs_net *afs_sock2net(struct sock *sk)
 {
+       return net_generic(sock_net(sk), afs_net_id);
 }
 
 static inline void __afs_stat(atomic_t *s)
@@ -861,16 +881,25 @@ extern void afs_mntpt_kill_timer(void);
 /*
  * netdevices.c
  */
-extern int afs_get_ipv4_interfaces(struct afs_interface *, size_t, bool);
+extern int afs_get_ipv4_interfaces(struct afs_net *, struct afs_interface *,
+                                  size_t, bool);
 
 /*
  * proc.c
  */
+#ifdef CONFIG_PROC_FS
 extern int __net_init afs_proc_init(struct afs_net *);
 extern void __net_exit afs_proc_cleanup(struct afs_net *);
-extern int afs_proc_cell_setup(struct afs_net *, struct afs_cell *);
-extern void afs_proc_cell_remove(struct afs_net *, struct afs_cell *);
+extern int afs_proc_cell_setup(struct afs_cell *);
+extern void afs_proc_cell_remove(struct afs_cell *);
 extern void afs_put_sysnames(struct afs_sysnames *);
+#else
+static inline int afs_proc_init(struct afs_net *net) { return 0; }
+static inline void afs_proc_cleanup(struct afs_net *net) {}
+static inline int afs_proc_cell_setup(struct afs_cell *cell) { return 0; }
+static inline void afs_proc_cell_remove(struct afs_cell *cell) {}
+static inline void afs_put_sysnames(struct afs_sysnames *sysnames) {}
+#endif
 
 /*
  * rotate.c
@@ -1002,7 +1031,7 @@ extern bool afs_annotate_server_list(struct afs_server_list *, struct afs_server
  * super.c
  */
 extern int __init afs_fs_init(void);
-extern void __exit afs_fs_exit(void);
+extern void afs_fs_exit(void);
 
 /*
  * vlclient.c
index d7560168b3bf7fa8887fa77cd7bd982e06af49f0..e84fe822a960714c8b274435dddbb66f4ba3275a 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/completion.h>
 #include <linux/sched.h>
 #include <linux/random.h>
+#include <linux/proc_fs.h>
 #define CREATE_TRACE_POINTS
 #include "internal.h"
 
@@ -32,7 +33,7 @@ module_param(rootcell, charp, 0);
 MODULE_PARM_DESC(rootcell, "root AFS cell name and VL server IP addr list");
 
 struct workqueue_struct *afs_wq;
-struct afs_net __afs_net;
+static struct proc_dir_entry *afs_proc_symlink;
 
 #if defined(CONFIG_ALPHA)
 const char afs_init_sysname[] = "alpha_linux26";
@@ -67,11 +68,13 @@ const char afs_init_sysname[] = "unknown_linux26";
 /*
  * Initialise an AFS network namespace record.
  */
-static int __net_init afs_net_init(struct afs_net *net)
+static int __net_init afs_net_init(struct net *net_ns)
 {
        struct afs_sysnames *sysnames;
+       struct afs_net *net = afs_net(net_ns);
        int ret;
 
+       net->net = net_ns;
        net->live = true;
        generate_random_uuid((unsigned char *)&net->uuid);
 
@@ -83,7 +86,7 @@ static int __net_init afs_net_init(struct afs_net *net)
        INIT_WORK(&net->cells_manager, afs_manage_cells);
        timer_setup(&net->cells_timer, afs_cells_timer, 0);
 
-       spin_lock_init(&net->proc_cells_lock);
+       mutex_init(&net->proc_cells_lock);
        INIT_LIST_HEAD(&net->proc_cells);
 
        seqlock_init(&net->fs_lock);
@@ -142,8 +145,10 @@ error_sysnames:
 /*
  * Clean up and destroy an AFS network namespace record.
  */
-static void __net_exit afs_net_exit(struct afs_net *net)
+static void __net_exit afs_net_exit(struct net *net_ns)
 {
+       struct afs_net *net = afs_net(net_ns);
+
        net->live = false;
        afs_cell_purge(net);
        afs_purge_servers(net);
@@ -152,6 +157,13 @@ static void __net_exit afs_net_exit(struct afs_net *net)
        afs_put_sysnames(net->sysnames);
 }
 
+static struct pernet_operations afs_net_ops = {
+       .init   = afs_net_init,
+       .exit   = afs_net_exit,
+       .id     = &afs_net_id,
+       .size   = sizeof(struct afs_net),
+};
+
 /*
  * initialise the AFS client FS module
  */
@@ -178,7 +190,7 @@ static int __init afs_init(void)
                goto error_cache;
 #endif
 
-       ret = afs_net_init(&__afs_net);
+       ret = register_pernet_subsys(&afs_net_ops);
        if (ret < 0)
                goto error_net;
 
@@ -187,10 +199,18 @@ static int __init afs_init(void)
        if (ret < 0)
                goto error_fs;
 
+       afs_proc_symlink = proc_symlink("fs/afs", NULL, "../self/net/afs");
+       if (IS_ERR(afs_proc_symlink)) {
+               ret = PTR_ERR(afs_proc_symlink);
+               goto error_proc;
+       }
+
        return ret;
 
+error_proc:
+       afs_fs_exit();
 error_fs:
-       afs_net_exit(&__afs_net);
+       unregister_pernet_subsys(&afs_net_ops);
 error_net:
 #ifdef CONFIG_AFS_FSCACHE
        fscache_unregister_netfs(&afs_cache_netfs);
@@ -219,8 +239,9 @@ static void __exit afs_exit(void)
 {
        printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 unregistering.\n");
 
+       proc_remove(afs_proc_symlink);
        afs_fs_exit();
-       afs_net_exit(&__afs_net);
+       unregister_pernet_subsys(&afs_net_ops);
 #ifdef CONFIG_AFS_FSCACHE
        fscache_unregister_netfs(&afs_cache_netfs);
 #endif
index 50bd5bb1c4fb1b4b91c25980f5f1452509c540e6..2a009d1939d7ffbd4047818b9f0bf0da3ffabc85 100644 (file)
@@ -17,8 +17,8 @@
  * - maxbufs must be at least 1
  * - returns the number of interface records in the buffer
  */
-int afs_get_ipv4_interfaces(struct afs_interface *bufs, size_t maxbufs,
-                           bool wantloopback)
+int afs_get_ipv4_interfaces(struct afs_net *net, struct afs_interface *bufs,
+                           size_t maxbufs, bool wantloopback)
 {
        struct net_device *dev;
        struct in_device *idev;
@@ -27,7 +27,7 @@ int afs_get_ipv4_interfaces(struct afs_interface *bufs, size_t maxbufs,
        ASSERT(maxbufs > 0);
 
        rtnl_lock();
-       for_each_netdev(&init_net, dev) {
+       for_each_netdev(net->net, dev) {
                if (dev->type == ARPHRD_LOOPBACK && !wantloopback)
                        continue;
                idev = __in_dev_get_rtnl(dev);
index 3aad32762989434798e02e6cf365a8211b8348c9..0c3285c8db95b4ec6457fdfe759e1997c9c69a7f 100644 (file)
 #include <linux/uaccess.h>
 #include "internal.h"
 
-static inline struct afs_net *afs_proc2net(struct file *f)
+static inline struct afs_net *afs_seq2net(struct seq_file *m)
 {
-       return &__afs_net;
+       return afs_net(seq_file_net(m));
 }
 
-static inline struct afs_net *afs_seq2net(struct seq_file *m)
+static inline struct afs_net *afs_seq2net_single(struct seq_file *m)
 {
-       return &__afs_net; // TODO: use seq_file_net(m)
+       return afs_net(seq_file_single_net(m));
 }
 
-static int afs_proc_cells_open(struct inode *inode, struct file *file);
-static void *afs_proc_cells_start(struct seq_file *p, loff_t *pos);
-static void *afs_proc_cells_next(struct seq_file *p, void *v, loff_t *pos);
-static void afs_proc_cells_stop(struct seq_file *p, void *v);
-static int afs_proc_cells_show(struct seq_file *m, void *v);
-static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf,
-                                   size_t size, loff_t *_pos);
-
-static const struct seq_operations afs_proc_cells_ops = {
-       .start  = afs_proc_cells_start,
-       .next   = afs_proc_cells_next,
-       .stop   = afs_proc_cells_stop,
-       .show   = afs_proc_cells_show,
-};
-
-static const struct file_operations afs_proc_cells_fops = {
-       .open           = afs_proc_cells_open,
-       .read           = seq_read,
-       .write          = afs_proc_cells_write,
-       .llseek         = seq_lseek,
-       .release        = seq_release,
-};
-
-static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf,
-                                     size_t size, loff_t *_pos);
-static ssize_t afs_proc_rootcell_write(struct file *file,
-                                      const char __user *buf,
-                                      size_t size, loff_t *_pos);
-
-static const struct file_operations afs_proc_rootcell_fops = {
-       .read           = afs_proc_rootcell_read,
-       .write          = afs_proc_rootcell_write,
-       .llseek         = no_llseek,
-};
-
-static void *afs_proc_cell_volumes_start(struct seq_file *p, loff_t *pos);
-static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v,
-                                       loff_t *pos);
-static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v);
-static int afs_proc_cell_volumes_show(struct seq_file *m, void *v);
-
-static const struct seq_operations afs_proc_cell_volumes_ops = {
-       .start  = afs_proc_cell_volumes_start,
-       .next   = afs_proc_cell_volumes_next,
-       .stop   = afs_proc_cell_volumes_stop,
-       .show   = afs_proc_cell_volumes_show,
-};
-
-static void *afs_proc_cell_vlservers_start(struct seq_file *p, loff_t *pos);
-static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v,
-                                         loff_t *pos);
-static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v);
-static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v);
-
-static const struct seq_operations afs_proc_cell_vlservers_ops = {
-       .start  = afs_proc_cell_vlservers_start,
-       .next   = afs_proc_cell_vlservers_next,
-       .stop   = afs_proc_cell_vlservers_stop,
-       .show   = afs_proc_cell_vlservers_show,
-};
-
-static void *afs_proc_servers_start(struct seq_file *p, loff_t *pos);
-static void *afs_proc_servers_next(struct seq_file *p, void *v,
-                                       loff_t *pos);
-static void afs_proc_servers_stop(struct seq_file *p, void *v);
-static int afs_proc_servers_show(struct seq_file *m, void *v);
-
-static const struct seq_operations afs_proc_servers_ops = {
-       .start  = afs_proc_servers_start,
-       .next   = afs_proc_servers_next,
-       .stop   = afs_proc_servers_stop,
-       .show   = afs_proc_servers_show,
-};
-
-static int afs_proc_sysname_open(struct inode *inode, struct file *file);
-static int afs_proc_sysname_release(struct inode *inode, struct file *file);
-static void *afs_proc_sysname_start(struct seq_file *p, loff_t *pos);
-static void *afs_proc_sysname_next(struct seq_file *p, void *v,
-                                       loff_t *pos);
-static void afs_proc_sysname_stop(struct seq_file *p, void *v);
-static int afs_proc_sysname_show(struct seq_file *m, void *v);
-static ssize_t afs_proc_sysname_write(struct file *file,
-                                     const char __user *buf,
-                                     size_t size, loff_t *_pos);
-
-static const struct seq_operations afs_proc_sysname_ops = {
-       .start  = afs_proc_sysname_start,
-       .next   = afs_proc_sysname_next,
-       .stop   = afs_proc_sysname_stop,
-       .show   = afs_proc_sysname_show,
-};
-
-static const struct file_operations afs_proc_sysname_fops = {
-       .open           = afs_proc_sysname_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = afs_proc_sysname_release,
-       .write          = afs_proc_sysname_write,
-};
-
-static int afs_proc_stats_show(struct seq_file *m, void *v);
-
 /*
- * initialise the /proc/fs/afs/ directory
+ * Display the list of cells known to the namespace.
  */
-int afs_proc_init(struct afs_net *net)
+static int afs_proc_cells_show(struct seq_file *m, void *v)
 {
-       _enter("");
-
-       net->proc_afs = proc_mkdir("fs/afs", NULL);
-       if (!net->proc_afs)
-               goto error_dir;
+       struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link);
+       struct afs_net *net = afs_seq2net(m);
 
-       if (!proc_create("cells", 0644, net->proc_afs, &afs_proc_cells_fops) ||
-           !proc_create("rootcell", 0644, net->proc_afs, &afs_proc_rootcell_fops) ||
-           !proc_create_seq("servers", 0644, net->proc_afs, &afs_proc_servers_ops) ||
-           !proc_create_single("stats", 0644, net->proc_afs, afs_proc_stats_show) ||
-           !proc_create("sysname", 0644, net->proc_afs, &afs_proc_sysname_fops))
-               goto error_tree;
+       if (v == &net->proc_cells) {
+               /* display header on line 1 */
+               seq_puts(m, "USE NAME\n");
+               return 0;
+       }
 
-       _leave(" = 0");
+       /* display one cell per line on subsequent lines */
+       seq_printf(m, "%3u %s\n", atomic_read(&cell->usage), cell->name);
        return 0;
-
-error_tree:
-       proc_remove(net->proc_afs);
-error_dir:
-       _leave(" = -ENOMEM");
-       return -ENOMEM;
-}
-
-/*
- * clean up the /proc/fs/afs/ directory
- */
-void afs_proc_cleanup(struct afs_net *net)
-{
-       proc_remove(net->proc_afs);
-       net->proc_afs = NULL;
-}
-
-/*
- * open "/proc/fs/afs/cells" which provides a summary of extant cells
- */
-static int afs_proc_cells_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &afs_proc_cells_ops);
 }
 
-/*
- * set up the iterator to start reading from the cells list and return the
- * first item
- */
 static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos)
        __acquires(rcu)
 {
-       struct afs_net *net = afs_seq2net(m);
-
        rcu_read_lock();
-       return seq_list_start_head(&net->proc_cells, *_pos);
+       return seq_list_start_head(&afs_seq2net(m)->proc_cells, *_pos);
 }
 
-/*
- * move to next cell in cells list
- */
 static void *afs_proc_cells_next(struct seq_file *m, void *v, loff_t *pos)
 {
-       struct afs_net *net = afs_seq2net(m);
-
-       return seq_list_next(v, &net->proc_cells, pos);
+       return seq_list_next(v, &afs_seq2net(m)->proc_cells, pos);
 }
 
-/*
- * clean up after reading from the cells list
- */
 static void afs_proc_cells_stop(struct seq_file *m, void *v)
        __releases(rcu)
 {
        rcu_read_unlock();
 }
 
-/*
- * display a header line followed by a load of cell lines
- */
-static int afs_proc_cells_show(struct seq_file *m, void *v)
-{
-       struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link);
-       struct afs_net *net = afs_seq2net(m);
-
-       if (v == &net->proc_cells) {
-               /* display header on line 1 */
-               seq_puts(m, "USE NAME\n");
-               return 0;
-       }
-
-       /* display one cell per line on subsequent lines */
-       seq_printf(m, "%3u %s\n", atomic_read(&cell->usage), cell->name);
-       return 0;
-}
+static const struct seq_operations afs_proc_cells_ops = {
+       .start  = afs_proc_cells_start,
+       .next   = afs_proc_cells_next,
+       .stop   = afs_proc_cells_stop,
+       .show   = afs_proc_cells_show,
+};
 
 /*
  * handle writes to /proc/fs/afs/cells
  * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]"
  */
-static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf,
-                                   size_t size, loff_t *_pos)
+static int afs_proc_cells_write(struct file *file, char *buf, size_t size)
 {
-       struct afs_net *net = afs_proc2net(file);
-       char *kbuf, *name, *args;
+       struct seq_file *m = file->private_data;
+       struct afs_net *net = afs_seq2net(m);
+       char *name, *args;
        int ret;
 
-       /* start by dragging the command into memory */
-       if (size <= 1 || size >= PAGE_SIZE)
-               return -EINVAL;
-
-       kbuf = memdup_user_nul(buf, size);
-       if (IS_ERR(kbuf))
-               return PTR_ERR(kbuf);
-
        /* trim to first NL */
-       name = memchr(kbuf, '\n', size);
+       name = memchr(buf, '\n', size);
        if (name)
                *name = 0;
 
        /* split into command, name and argslist */
-       name = strchr(kbuf, ' ');
+       name = strchr(buf, ' ');
        if (!name)
                goto inval;
        do {
@@ -269,9 +107,9 @@ static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf,
                goto inval;
 
        /* determine command to perform */
-       _debug("cmd=%s name=%s args=%s", kbuf, name, args);
+       _debug("cmd=%s name=%s args=%s", buf, name, args);
 
-       if (strcmp(kbuf, "add") == 0) {
+       if (strcmp(buf, "add") == 0) {
                struct afs_cell *cell;
 
                cell = afs_lookup_cell(net, name, strlen(name), args, true);
@@ -287,10 +125,9 @@ static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf,
                goto inval;
        }
 
-       ret = size;
+       ret = 0;
 
 done:
-       kfree(kbuf);
        _leave(" = %d", ret);
        return ret;
 
@@ -300,200 +137,136 @@ inval:
        goto done;
 }
 
-static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf,
-                                     size_t size, loff_t *_pos)
+/*
+ * Display the name of the current workstation cell.
+ */
+static int afs_proc_rootcell_show(struct seq_file *m, void *v)
 {
        struct afs_cell *cell;
-       struct afs_net *net = afs_proc2net(file);
-       unsigned int seq = 0;
-       char name[AFS_MAXCELLNAME + 1];
-       int len;
-
-       if (*_pos > 0)
-               return 0;
-       if (!net->ws_cell)
-               return 0;
-
-       rcu_read_lock();
-       do {
-               read_seqbegin_or_lock(&net->cells_lock, &seq);
-               len = 0;
-               cell = rcu_dereference_raw(net->ws_cell);
-               if (cell) {
-                       len = cell->name_len;
-                       memcpy(name, cell->name, len);
-               }
-       } while (need_seqretry(&net->cells_lock, seq));
-       done_seqretry(&net->cells_lock, seq);
-       rcu_read_unlock();
-
-       if (!len)
-               return 0;
-
-       name[len++] = '\n';
-       if (len > size)
-               len = size;
-       if (copy_to_user(buf, name, len) != 0)
-               return -EFAULT;
-       *_pos = 1;
-       return len;
+       struct afs_net *net;
+
+       net = afs_seq2net_single(m);
+       if (rcu_access_pointer(net->ws_cell)) {
+               rcu_read_lock();
+               cell = rcu_dereference(net->ws_cell);
+               if (cell)
+                       seq_printf(m, "%s\n", cell->name);
+               rcu_read_unlock();
+       }
+       return 0;
 }
 
 /*
- * handle writes to /proc/fs/afs/rootcell
- * - to initialize rootcell: echo "cell.name:192.168.231.14"
+ * Set the current workstation cell and optionally supply its list of volume
+ * location servers.
+ *
+ *     echo "cell.name:192.168.231.14" >/proc/fs/afs/rootcell
  */
-static ssize_t afs_proc_rootcell_write(struct file *file,
-                                      const char __user *buf,
-                                      size_t size, loff_t *_pos)
+static int afs_proc_rootcell_write(struct file *file, char *buf, size_t size)
 {
-       struct afs_net *net = afs_proc2net(file);
-       char *kbuf, *s;
+       struct seq_file *m = file->private_data;
+       struct afs_net *net = afs_seq2net_single(m);
+       char *s;
        int ret;
 
-       /* start by dragging the command into memory */
-       if (size <= 1 || size >= PAGE_SIZE)
-               return -EINVAL;
-
-       kbuf = memdup_user_nul(buf, size);
-       if (IS_ERR(kbuf))
-               return PTR_ERR(kbuf);
-
        ret = -EINVAL;
-       if (kbuf[0] == '.')
+       if (buf[0] == '.')
                goto out;
-       if (memchr(kbuf, '/', size))
+       if (memchr(buf, '/', size))
                goto out;
 
        /* trim to first NL */
-       s = memchr(kbuf, '\n', size);
+       s = memchr(buf, '\n', size);
        if (s)
                *s = 0;
 
        /* determine command to perform */
-       _debug("rootcell=%s", kbuf);
+       _debug("rootcell=%s", buf);
 
-       ret = afs_cell_init(net, kbuf);
-       if (ret >= 0)
-               ret = size;     /* consume everything, always */
+       ret = afs_cell_init(net, buf);
 
 out:
-       kfree(kbuf);
        _leave(" = %d", ret);
        return ret;
 }
 
+static const char afs_vol_types[3][3] = {
+       [AFSVL_RWVOL]   = "RW",
+       [AFSVL_ROVOL]   = "RO",
+       [AFSVL_BACKVOL] = "BK",
+};
+
 /*
- * initialise /proc/fs/afs/<cell>/
+ * Display the list of volumes known to a cell.
  */
-int afs_proc_cell_setup(struct afs_net *net, struct afs_cell *cell)
+static int afs_proc_cell_volumes_show(struct seq_file *m, void *v)
 {
-       struct proc_dir_entry *dir;
-
-       _enter("%p{%s},%p", cell, cell->name, net->proc_afs);
+       struct afs_cell *cell = PDE_DATA(file_inode(m->file));
+       struct afs_volume *vol = list_entry(v, struct afs_volume, proc_link);
 
-       dir = proc_mkdir(cell->name, net->proc_afs);
-       if (!dir)
-               goto error_dir;
+       /* Display header on line 1 */
+       if (v == &cell->proc_volumes) {
+               seq_puts(m, "USE VID      TY\n");
+               return 0;
+       }
 
-       if (!proc_create_seq_data("vlservers", 0, dir,
-                       &afs_proc_cell_vlservers_ops, cell))
-               goto error_tree;
-       if (!proc_create_seq_data("volumes", 0, dir, &afs_proc_cell_volumes_ops,
-                       cell))
-               goto error_tree;
+       seq_printf(m, "%3d %08x %s\n",
+                  atomic_read(&vol->usage), vol->vid,
+                  afs_vol_types[vol->type]);
 
-       _leave(" = 0");
        return 0;
-
-error_tree:
-       remove_proc_subtree(cell->name, net->proc_afs);
-error_dir:
-       _leave(" = -ENOMEM");
-       return -ENOMEM;
 }
 
-/*
- * remove /proc/fs/afs/<cell>/
- */
-void afs_proc_cell_remove(struct afs_net *net, struct afs_cell *cell)
-{
-       _enter("");
-
-       remove_proc_subtree(cell->name, net->proc_afs);
-
-       _leave("");
-}
-
-/*
- * set up the iterator to start reading from the cells list and return the
- * first item
- */
 static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos)
        __acquires(cell->proc_lock)
 {
        struct afs_cell *cell = PDE_DATA(file_inode(m->file));
 
-       _enter("cell=%p pos=%Ld", cell, *_pos);
-
        read_lock(&cell->proc_lock);
        return seq_list_start_head(&cell->proc_volumes, *_pos);
 }
 
-/*
- * move to next cell in cells list
- */
-static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v,
+static void *afs_proc_cell_volumes_next(struct seq_file *m, void *v,
                                        loff_t *_pos)
 {
-       struct afs_cell *cell = PDE_DATA(file_inode(p->file));
+       struct afs_cell *cell = PDE_DATA(file_inode(m->file));
 
-       _enter("cell=%p pos=%Ld", cell, *_pos);
        return seq_list_next(v, &cell->proc_volumes, _pos);
 }
 
-/*
- * clean up after reading from the cells list
- */
-static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v)
+static void afs_proc_cell_volumes_stop(struct seq_file *m, void *v)
        __releases(cell->proc_lock)
 {
-       struct afs_cell *cell = PDE_DATA(file_inode(p->file));
+       struct afs_cell *cell = PDE_DATA(file_inode(m->file));
 
        read_unlock(&cell->proc_lock);
 }
 
-static const char afs_vol_types[3][3] = {
-       [AFSVL_RWVOL]   = "RW",
-       [AFSVL_ROVOL]   = "RO",
-       [AFSVL_BACKVOL] = "BK",
+static const struct seq_operations afs_proc_cell_volumes_ops = {
+       .start  = afs_proc_cell_volumes_start,
+       .next   = afs_proc_cell_volumes_next,
+       .stop   = afs_proc_cell_volumes_stop,
+       .show   = afs_proc_cell_volumes_show,
 };
 
 /*
- * display a header line followed by a load of volume lines
+ * Display the list of Volume Location servers we're using for a cell.
  */
-static int afs_proc_cell_volumes_show(struct seq_file *m, void *v)
+static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)
 {
-       struct afs_cell *cell = PDE_DATA(file_inode(m->file));
-       struct afs_volume *vol = list_entry(v, struct afs_volume, proc_link);
+       struct sockaddr_rxrpc *addr = v;
 
-       /* Display header on line 1 */
-       if (v == &cell->proc_volumes) {
-               seq_puts(m, "USE VID      TY\n");
+       /* display header on line 1 */
+       if (v == (void *)1) {
+               seq_puts(m, "ADDRESS\n");
                return 0;
        }
 
-       seq_printf(m, "%3d %08x %s\n",
-                  atomic_read(&vol->usage), vol->vid,
-                  afs_vol_types[vol->type]);
-
+       /* display one cell per line on subsequent lines */
+       seq_printf(m, "%pISp\n", &addr->transport);
        return 0;
 }
 
-/*
- * set up the iterator to start reading from the cells list and return the
- * first item
- */
 static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos)
        __acquires(rcu)
 {
@@ -516,14 +289,11 @@ static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos)
        return alist->addrs + pos;
 }
 
-/*
- * move to next cell in cells list
- */
-static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v,
+static void *afs_proc_cell_vlservers_next(struct seq_file *m, void *v,
                                          loff_t *_pos)
 {
        struct afs_addr_list *alist;
-       struct afs_cell *cell = PDE_DATA(file_inode(p->file));
+       struct afs_cell *cell = PDE_DATA(file_inode(m->file));
        loff_t pos;
 
        alist = rcu_dereference(cell->vl_addrs);
@@ -536,161 +306,145 @@ static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v,
        return alist->addrs + pos;
 }
 
-/*
- * clean up after reading from the cells list
- */
-static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v)
+static void afs_proc_cell_vlservers_stop(struct seq_file *m, void *v)
        __releases(rcu)
 {
        rcu_read_unlock();
 }
 
+static const struct seq_operations afs_proc_cell_vlservers_ops = {
+       .start  = afs_proc_cell_vlservers_start,
+       .next   = afs_proc_cell_vlservers_next,
+       .stop   = afs_proc_cell_vlservers_stop,
+       .show   = afs_proc_cell_vlservers_show,
+};
+
 /*
- * display a header line followed by a load of volume lines
+ * Display the list of fileservers we're using within a namespace.
  */
-static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)
+static int afs_proc_servers_show(struct seq_file *m, void *v)
 {
-       struct sockaddr_rxrpc *addr = v;
+       struct afs_server *server;
+       struct afs_addr_list *alist;
+       int i;
 
-       /* display header on line 1 */
-       if (v == (void *)1) {
-               seq_puts(m, "ADDRESS\n");
+       if (v == SEQ_START_TOKEN) {
+               seq_puts(m, "UUID                                 USE ADDR\n");
                return 0;
        }
 
-       /* display one cell per line on subsequent lines */
-       seq_printf(m, "%pISp\n", &addr->transport);
+       server = list_entry(v, struct afs_server, proc_link);
+       alist = rcu_dereference(server->addresses);
+       seq_printf(m, "%pU %3d %pISpc%s\n",
+                  &server->uuid,
+                  atomic_read(&server->usage),
+                  &alist->addrs[0].transport,
+                  alist->index == 0 ? "*" : "");
+       for (i = 1; i < alist->nr_addrs; i++)
+               seq_printf(m, "                                         %pISpc%s\n",
+                          &alist->addrs[i].transport,
+                          alist->index == i ? "*" : "");
        return 0;
 }
 
-/*
- * Set up the iterator to start reading from the server list and return the
- * first item.
- */
 static void *afs_proc_servers_start(struct seq_file *m, loff_t *_pos)
        __acquires(rcu)
 {
-       struct afs_net *net = afs_seq2net(m);
-
        rcu_read_lock();
-       return seq_hlist_start_head_rcu(&net->fs_proc, *_pos);
+       return seq_hlist_start_head_rcu(&afs_seq2net(m)->fs_proc, *_pos);
 }
 
-/*
- * move to next cell in cells list
- */
 static void *afs_proc_servers_next(struct seq_file *m, void *v, loff_t *_pos)
 {
-       struct afs_net *net = afs_seq2net(m);
-
-       return seq_hlist_next_rcu(v, &net->fs_proc, _pos);
+       return seq_hlist_next_rcu(v, &afs_seq2net(m)->fs_proc, _pos);
 }
 
-/*
- * clean up after reading from the cells list
- */
-static void afs_proc_servers_stop(struct seq_file *p, void *v)
+static void afs_proc_servers_stop(struct seq_file *m, void *v)
        __releases(rcu)
 {
        rcu_read_unlock();
 }
 
+static const struct seq_operations afs_proc_servers_ops = {
+       .start  = afs_proc_servers_start,
+       .next   = afs_proc_servers_next,
+       .stop   = afs_proc_servers_stop,
+       .show   = afs_proc_servers_show,
+};
+
 /*
- * display a header line followed by a load of volume lines
+ * Display the list of strings that may be substituted for the @sys pathname
+ * macro.
  */
-static int afs_proc_servers_show(struct seq_file *m, void *v)
+static int afs_proc_sysname_show(struct seq_file *m, void *v)
 {
-       struct afs_server *server;
-       struct afs_addr_list *alist;
-
-       if (v == SEQ_START_TOKEN) {
-               seq_puts(m, "UUID                                 USE ADDR\n");
-               return 0;
-       }
+       struct afs_net *net = afs_seq2net(m);
+       struct afs_sysnames *sysnames = net->sysnames;
+       unsigned int i = (unsigned long)v - 1;
 
-       server = list_entry(v, struct afs_server, proc_link);
-       alist = rcu_dereference(server->addresses);
-       seq_printf(m, "%pU %3d %pISp\n",
-                  &server->uuid,
-                  atomic_read(&server->usage),
-                  &alist->addrs[alist->index].transport);
+       if (i < sysnames->nr)
+               seq_printf(m, "%s\n", sysnames->subs[i]);
        return 0;
 }
 
-void afs_put_sysnames(struct afs_sysnames *sysnames)
+static void *afs_proc_sysname_start(struct seq_file *m, loff_t *pos)
+       __acquires(&net->sysnames_lock)
 {
-       int i;
+       struct afs_net *net = afs_seq2net(m);
+       struct afs_sysnames *names;
 
-       if (sysnames && refcount_dec_and_test(&sysnames->usage)) {
-               for (i = 0; i < sysnames->nr; i++)
-                       if (sysnames->subs[i] != afs_init_sysname &&
-                           sysnames->subs[i] != sysnames->blank)
-                               kfree(sysnames->subs[i]);
-       }
+       read_lock(&net->sysnames_lock);
+
+       names = net->sysnames;
+       if (*pos >= names->nr)
+               return NULL;
+       return (void *)(unsigned long)(*pos + 1);
 }
 
-/*
- * Handle opening of /proc/fs/afs/sysname.  If it is opened for writing, we
- * assume the caller wants to change the substitution list and we allocate a
- * buffer to hold the list.
- */
-static int afs_proc_sysname_open(struct inode *inode, struct file *file)
+static void *afs_proc_sysname_next(struct seq_file *m, void *v, loff_t *pos)
 {
-       struct afs_sysnames *sysnames;
-       struct seq_file *m;
-       int ret;
-
-       ret = seq_open(file, &afs_proc_sysname_ops);
-       if (ret < 0)
-               return ret;
+       struct afs_net *net = afs_seq2net(m);
+       struct afs_sysnames *names = net->sysnames;
 
-       if (file->f_mode & FMODE_WRITE) {
-               sysnames = kzalloc(sizeof(*sysnames), GFP_KERNEL);
-               if (!sysnames) {
-                       seq_release(inode, file);
-                       return -ENOMEM;
-               }
+       *pos += 1;
+       if (*pos >= names->nr)
+               return NULL;
+       return (void *)(unsigned long)(*pos + 1);
+}
 
-               refcount_set(&sysnames->usage, 1);
-               m = file->private_data;
-               m->private = sysnames;
-       }
+static void afs_proc_sysname_stop(struct seq_file *m, void *v)
+       __releases(&net->sysnames_lock)
+{
+       struct afs_net *net = afs_seq2net(m);
 
-       return 0;
+       read_unlock(&net->sysnames_lock);
 }
 
+static const struct seq_operations afs_proc_sysname_ops = {
+       .start  = afs_proc_sysname_start,
+       .next   = afs_proc_sysname_next,
+       .stop   = afs_proc_sysname_stop,
+       .show   = afs_proc_sysname_show,
+};
+
 /*
- * Handle writes to /proc/fs/afs/sysname to set the @sys substitution.
+ * Allow the @sys substitution to be configured.
  */
-static ssize_t afs_proc_sysname_write(struct file *file,
-                                     const char __user *buf,
-                                     size_t size, loff_t *_pos)
+static int afs_proc_sysname_write(struct file *file, char *buf, size_t size)
 {
-       struct afs_sysnames *sysnames;
+       struct afs_sysnames *sysnames, *kill;
        struct seq_file *m = file->private_data;
-       char *kbuf = NULL, *s, *p, *sub;
+       struct afs_net *net = afs_seq2net(m);
+       char *s, *p, *sub;
        int ret, len;
 
-       sysnames = m->private;
+       sysnames = kzalloc(sizeof(*sysnames), GFP_KERNEL);
        if (!sysnames)
-               return -EINVAL;
-       if (sysnames->error)
-               return sysnames->error;
-
-       if (size >= PAGE_SIZE - 1) {
-               sysnames->error = -EINVAL;
-               return -EINVAL;
-       }
-       if (size == 0)
-               return 0;
-
-       kbuf = memdup_user_nul(buf, size);
-       if (IS_ERR(kbuf))
-               return PTR_ERR(kbuf);
-
-       inode_lock(file_inode(file));
+               return -ENOMEM;
+       refcount_set(&sysnames->usage, 1);
+       kill = sysnames;
 
-       p = kbuf;
+       p = buf;
        while ((s = strsep(&p, " \t\n"))) {
                len = strlen(s);
                if (len == 0)
@@ -731,85 +485,36 @@ static ssize_t afs_proc_sysname_write(struct file *file,
                sysnames->nr++;
        }
 
-       ret = size;     /* consume everything, always */
+       if (sysnames->nr == 0) {
+               sysnames->subs[0] = sysnames->blank;
+               sysnames->nr++;
+       }
+
+       write_lock(&net->sysnames_lock);
+       kill = net->sysnames;
+       net->sysnames = sysnames;
+       write_unlock(&net->sysnames_lock);
+       ret = 0;
 out:
-       inode_unlock(file_inode(file));
-       kfree(kbuf);
+       afs_put_sysnames(kill);
        return ret;
 
 invalid:
        ret = -EINVAL;
 error:
-       sysnames->error = ret;
        goto out;
 }
 
-static int afs_proc_sysname_release(struct inode *inode, struct file *file)
+void afs_put_sysnames(struct afs_sysnames *sysnames)
 {
-       struct afs_sysnames *sysnames, *kill = NULL;
-       struct seq_file *m = file->private_data;
-       struct afs_net *net = afs_seq2net(m);
+       int i;
 
-       sysnames = m->private;
-       if (sysnames) {
-               if (!sysnames->error) {
-                       kill = sysnames;
-                       if (sysnames->nr == 0) {
-                               sysnames->subs[0] = sysnames->blank;
-                               sysnames->nr++;
-                       }
-                       write_lock(&net->sysnames_lock);
-                       kill = net->sysnames;
-                       net->sysnames = sysnames;
-                       write_unlock(&net->sysnames_lock);
-               }
-               afs_put_sysnames(kill);
+       if (sysnames && refcount_dec_and_test(&sysnames->usage)) {
+               for (i = 0; i < sysnames->nr; i++)
+                       if (sysnames->subs[i] != afs_init_sysname &&
+                           sysnames->subs[i] != sysnames->blank)
+                               kfree(sysnames->subs[i]);
        }
-
-       return seq_release(inode, file);
-}
-
-static void *afs_proc_sysname_start(struct seq_file *m, loff_t *pos)
-       __acquires(&net->sysnames_lock)
-{
-       struct afs_net *net = afs_seq2net(m);
-       struct afs_sysnames *names = net->sysnames;
-
-       read_lock(&net->sysnames_lock);
-
-       if (*pos >= names->nr)
-               return NULL;
-       return (void *)(unsigned long)(*pos + 1);
-}
-
-static void *afs_proc_sysname_next(struct seq_file *m, void *v, loff_t *pos)
-{
-       struct afs_net *net = afs_seq2net(m);
-       struct afs_sysnames *names = net->sysnames;
-
-       *pos += 1;
-       if (*pos >= names->nr)
-               return NULL;
-       return (void *)(unsigned long)(*pos + 1);
-}
-
-static void afs_proc_sysname_stop(struct seq_file *m, void *v)
-       __releases(&net->sysnames_lock)
-{
-       struct afs_net *net = afs_seq2net(m);
-
-       read_unlock(&net->sysnames_lock);
-}
-
-static int afs_proc_sysname_show(struct seq_file *m, void *v)
-{
-       struct afs_net *net = afs_seq2net(m);
-       struct afs_sysnames *sysnames = net->sysnames;
-       unsigned int i = (unsigned long)v - 1;
-
-       if (i < sysnames->nr)
-               seq_printf(m, "%s\n", sysnames->subs[i]);
-       return 0;
 }
 
 /*
@@ -817,7 +522,7 @@ static int afs_proc_sysname_show(struct seq_file *m, void *v)
  */
 static int afs_proc_stats_show(struct seq_file *m, void *v)
 {
-       struct afs_net *net = afs_seq2net(m);
+       struct afs_net *net = afs_seq2net_single(m);
 
        seq_puts(m, "kAFS statistics\n");
 
@@ -842,3 +547,101 @@ static int afs_proc_stats_show(struct seq_file *m, void *v)
                   atomic_long_read(&net->n_store_bytes));
        return 0;
 }
+
+/*
+ * initialise /proc/fs/afs/<cell>/
+ */
+int afs_proc_cell_setup(struct afs_cell *cell)
+{
+       struct proc_dir_entry *dir;
+       struct afs_net *net = cell->net;
+
+       _enter("%p{%s},%p", cell, cell->name, net->proc_afs);
+
+       dir = proc_net_mkdir(net->net, cell->name, net->proc_afs);
+       if (!dir)
+               goto error_dir;
+
+       if (!proc_create_net_data("vlservers", 0444, dir,
+                                 &afs_proc_cell_vlservers_ops,
+                                 sizeof(struct seq_net_private),
+                                 cell) ||
+           !proc_create_net_data("volumes", 0444, dir,
+                                 &afs_proc_cell_volumes_ops,
+                                 sizeof(struct seq_net_private),
+                                 cell))
+               goto error_tree;
+
+       _leave(" = 0");
+       return 0;
+
+error_tree:
+       remove_proc_subtree(cell->name, net->proc_afs);
+error_dir:
+       _leave(" = -ENOMEM");
+       return -ENOMEM;
+}
+
+/*
+ * remove /proc/fs/afs/<cell>/
+ */
+void afs_proc_cell_remove(struct afs_cell *cell)
+{
+       struct afs_net *net = cell->net;
+
+       _enter("");
+       remove_proc_subtree(cell->name, net->proc_afs);
+       _leave("");
+}
+
+/*
+ * initialise the /proc/fs/afs/ directory
+ */
+int afs_proc_init(struct afs_net *net)
+{
+       struct proc_dir_entry *p;
+
+       _enter("");
+
+       p = proc_net_mkdir(net->net, "afs", net->net->proc_net);
+       if (!p)
+               goto error_dir;
+
+       if (!proc_create_net_data_write("cells", 0644, p,
+                                       &afs_proc_cells_ops,
+                                       afs_proc_cells_write,
+                                       sizeof(struct seq_net_private),
+                                       NULL) ||
+           !proc_create_net_single_write("rootcell", 0644, p,
+                                         afs_proc_rootcell_show,
+                                         afs_proc_rootcell_write,
+                                         NULL) ||
+           !proc_create_net("servers", 0444, p, &afs_proc_servers_ops,
+                            sizeof(struct seq_net_private)) ||
+           !proc_create_net_single("stats", 0444, p, afs_proc_stats_show, NULL) ||
+           !proc_create_net_data_write("sysname", 0644, p,
+                                       &afs_proc_sysname_ops,
+                                       afs_proc_sysname_write,
+                                       sizeof(struct seq_net_private),
+                                       NULL))
+               goto error_tree;
+
+       net->proc_afs = p;
+       _leave(" = 0");
+       return 0;
+
+error_tree:
+       proc_remove(p);
+error_dir:
+       _leave(" = -ENOMEM");
+       return -ENOMEM;
+}
+
+/*
+ * clean up the /proc/fs/afs/ directory
+ */
+void afs_proc_cleanup(struct afs_net *net)
+{
+       proc_remove(net->proc_afs);
+       net->proc_afs = NULL;
+}
index 08735948f15d4caec78be59d5e1c4623591e92d4..a1b18082991b2088711a2bca42f173fa951e49e8 100644 (file)
@@ -46,7 +46,7 @@ int afs_open_socket(struct afs_net *net)
 
        _enter("");
 
-       ret = sock_create_kern(&init_net, AF_RXRPC, SOCK_DGRAM, PF_INET6, &socket);
+       ret = sock_create_kern(net->net, AF_RXRPC, SOCK_DGRAM, PF_INET6, &socket);
        if (ret < 0)
                goto error_1;
 
index 3af4625e2f8cc7049185048a602826c53a169c03..1d329e6981d515c06bb5b711a1e3880226c2cce8 100644 (file)
@@ -228,7 +228,7 @@ static struct afs_server *afs_alloc_server(struct afs_net *net,
        server->flags = (1UL << AFS_SERVER_FL_NEW);
        server->update_at = ktime_get_real_seconds() + afs_server_update_delay;
        rwlock_init(&server->fs_lock);
-       INIT_LIST_HEAD(&server->cb_interests);
+       INIT_HLIST_HEAD(&server->cb_volumes);
        rwlock_init(&server->cb_break_lock);
 
        afs_inc_servers_outstanding(net);
index 9e5d7966621c4abaa5cdc51f278a1a05a7e6afac..4d3e274207fb7aa05aa320b957a03911984cf67d 100644 (file)
@@ -48,6 +48,8 @@ struct file_system_type afs_fs_type = {
 };
 MODULE_ALIAS_FS("afs");
 
+int afs_net_id;
+
 static const struct super_operations afs_super_ops = {
        .statfs         = afs_statfs,
        .alloc_inode    = afs_alloc_inode,
@@ -117,7 +119,7 @@ int __init afs_fs_init(void)
 /*
  * clean up the filesystem
  */
-void __exit afs_fs_exit(void)
+void afs_fs_exit(void)
 {
        _enter("");
 
@@ -351,14 +353,19 @@ static int afs_test_super(struct super_block *sb, void *data)
        struct afs_super_info *as1 = data;
        struct afs_super_info *as = AFS_FS_S(sb);
 
-       return (as->net == as1->net &&
+       return (as->net_ns == as1->net_ns &&
                as->volume &&
-               as->volume->vid == as1->volume->vid);
+               as->volume->vid == as1->volume->vid &&
+               !as->dyn_root);
 }
 
 static int afs_dynroot_test_super(struct super_block *sb, void *data)
 {
-       return false;
+       struct afs_super_info *as1 = data;
+       struct afs_super_info *as = AFS_FS_S(sb);
+
+       return (as->net_ns == as1->net_ns &&
+               as->dyn_root);
 }
 
 static int afs_set_super(struct super_block *sb, void *data)
@@ -418,10 +425,14 @@ static int afs_fill_super(struct super_block *sb,
        if (!sb->s_root)
                goto error;
 
-       if (params->dyn_root)
+       if (as->dyn_root) {
                sb->s_d_op = &afs_dynroot_dentry_operations;
-       else
+               ret = afs_dynroot_populate(sb);
+               if (ret < 0)
+                       goto error;
+       } else {
                sb->s_d_op = &afs_fs_dentry_operations;
+       }
 
        _leave(" = 0");
        return 0;
@@ -437,7 +448,7 @@ static struct afs_super_info *afs_alloc_sbi(struct afs_mount_params *params)
 
        as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL);
        if (as) {
-               as->net = afs_get_net(params->net);
+               as->net_ns = get_net(params->net_ns);
                if (params->dyn_root)
                        as->dyn_root = true;
                else
@@ -450,12 +461,31 @@ static void afs_destroy_sbi(struct afs_super_info *as)
 {
        if (as) {
                afs_put_volume(as->cell, as->volume);
-               afs_put_cell(as->net, as->cell);
-               afs_put_net(as->net);
+               afs_put_cell(afs_net(as->net_ns), as->cell);
+               put_net(as->net_ns);
                kfree(as);
        }
 }
 
+static void afs_kill_super(struct super_block *sb)
+{
+       struct afs_super_info *as = AFS_FS_S(sb);
+       struct afs_net *net = afs_net(as->net_ns);
+
+       if (as->dyn_root)
+               afs_dynroot_depopulate(sb);
+       
+       /* Clear the callback interests (which will do ilookup5) before
+        * deactivating the superblock.
+        */
+       if (as->volume)
+               afs_clear_callback_interests(net, as->volume->servers);
+       kill_anon_super(sb);
+       if (as->volume)
+               afs_deactivate_volume(as->volume);
+       afs_destroy_sbi(as);
+}
+
 /*
  * get an AFS superblock
  */
@@ -472,12 +502,13 @@ static struct dentry *afs_mount(struct file_system_type *fs_type,
        _enter(",,%s,%p", dev_name, options);
 
        memset(&params, 0, sizeof(params));
-       params.net = &__afs_net;
 
        ret = -EINVAL;
        if (current->nsproxy->net_ns != &init_net)
                goto error;
-
+       params.net_ns = current->nsproxy->net_ns;
+       params.net = afs_net(params.net_ns);
+       
        /* parse the options and device name */
        if (options) {
                ret = afs_parse_options(&params, options, &dev_name);
@@ -563,21 +594,6 @@ error:
        return ERR_PTR(ret);
 }
 
-static void afs_kill_super(struct super_block *sb)
-{
-       struct afs_super_info *as = AFS_FS_S(sb);
-
-       /* Clear the callback interests (which will do ilookup5) before
-        * deactivating the superblock.
-        */
-       if (as->volume)
-               afs_clear_callback_interests(as->net, as->volume->servers);
-       kill_anon_super(sb);
-       if (as->volume)
-               afs_deactivate_volume(as->volume);
-       afs_destroy_sbi(as);
-}
-
 /*
  * Initialise an inode cache slab element prior to any use.  Note that
  * afs_alloc_inode() *must* reset anything that could incorrectly leak from one
index 134e5b635d643da8868b477a0990e5d3cdb4077e..e1d20124ec0e8698a1e8a5940537ff45f2e57d2c 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -1661,7 +1661,7 @@ static int aio_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync,
        if (mask && !(mask & req->events))
                return 0;
 
-       mask = file->f_op->poll_mask(file, req->events);
+       mask = file->f_op->poll_mask(file, req->events) & req->events;
        if (!mask)
                return 0;
 
@@ -1719,7 +1719,7 @@ static ssize_t aio_poll(struct aio_kiocb *aiocb, struct iocb *iocb)
 
        spin_lock_irq(&ctx->ctx_lock);
        spin_lock(&req->head->lock);
-       mask = req->file->f_op->poll_mask(req->file, req->events);
+       mask = req->file->f_op->poll_mask(req->file, req->events) & req->events;
        if (!mask) {
                __add_wait_queue(req->head, &req->wait);
                list_add_tail(&aiocb->ki_list, &ctx->active_reqs);
index d0b4d34878fbab70059b364ae6eb0d7c3a118abe..e3d53bf1224008858c7cd95c620b8a0eca0f8a48 100644 (file)
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -183,14 +183,14 @@ void setattr_copy(struct inode *inode, const struct iattr *attr)
        if (ia_valid & ATTR_GID)
                inode->i_gid = attr->ia_gid;
        if (ia_valid & ATTR_ATIME)
-               inode->i_atime = timespec_trunc(attr->ia_atime,
-                                               inode->i_sb->s_time_gran);
+               inode->i_atime = timespec64_trunc(attr->ia_atime,
+                                                 inode->i_sb->s_time_gran);
        if (ia_valid & ATTR_MTIME)
-               inode->i_mtime = timespec_trunc(attr->ia_mtime,
-                                               inode->i_sb->s_time_gran);
+               inode->i_mtime = timespec64_trunc(attr->ia_mtime,
+                                                 inode->i_sb->s_time_gran);
        if (ia_valid & ATTR_CTIME)
-               inode->i_ctime = timespec_trunc(attr->ia_ctime,
-                                               inode->i_sb->s_time_gran);
+               inode->i_ctime = timespec64_trunc(attr->ia_ctime,
+                                                 inode->i_sb->s_time_gran);
        if (ia_valid & ATTR_MODE) {
                umode_t mode = attr->ia_mode;
 
@@ -227,7 +227,7 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
        struct inode *inode = dentry->d_inode;
        umode_t mode = inode->i_mode;
        int error;
-       struct timespec now;
+       struct timespec64 now;
        unsigned int ia_valid = attr->ia_valid;
 
        WARN_ON_ONCE(!inode_is_locked(inode));
index 213b51dbbb607251d0f5c131843cc6af68ce3f6d..125e8bbd22a250e3ea1c7710f29f942f7eaef150 100644 (file)
@@ -126,7 +126,7 @@ static int bad_inode_fiemap(struct inode *inode,
        return -EIO;
 }
 
-static int bad_inode_update_time(struct inode *inode, struct timespec *time,
+static int bad_inode_update_time(struct inode *inode, struct timespec64 *time,
                                 int flags)
 {
        return -EIO;
index 16f2dfe8c2f742e4264bf60bc96562d5a6e8292d..aff7eec8f327f3bd16f8685ed1eaf8c40dc59465 100644 (file)
@@ -389,7 +389,7 @@ Version 0.4 (2001-10-28)
        (fs/nls/Config.in)
 
 * Added Configure.help entries for CONFIG_BEFS_FS and CONFIG_DEBUG_BEFS
-       (Documentation/Configure.help)
+       (currently at fs/befs/Kconfig)
 
 2001-08-??
 ==========
index 070b6184642d140bbc25868ced5a3d443d6f6acd..0ac456b52bddb62e9c817d61bccc886c7c8cde85 100644 (file)
@@ -1621,8 +1621,8 @@ static int fill_files_note(struct memelfnote *note)
        if (size >= MAX_FILE_NOTE_SIZE) /* paranoia check */
                return -EINVAL;
        size = round_up(size, PAGE_SIZE);
-       data = vmalloc(size);
-       if (!data)
+       data = kvmalloc(size, GFP_KERNEL);
+       if (ZERO_OR_NULL_PTR(data))
                return -ENOMEM;
 
        start_end_ofs = data + 2;
@@ -1639,7 +1639,7 @@ static int fill_files_note(struct memelfnote *note)
                filename = file_path(file, name_curpos, remaining);
                if (IS_ERR(filename)) {
                        if (PTR_ERR(filename) == -ENAMETOOLONG) {
-                               vfree(data);
+                               kvfree(data);
                                size = size * 5 / 4;
                                goto alloc;
                        }
@@ -1932,7 +1932,7 @@ static void free_note_info(struct elf_note_info *info)
                kfree(t);
        }
        kfree(info->psinfo.data);
-       vfree(info->files.data);
+       kvfree(info->files.data);
 }
 
 #else
@@ -2148,7 +2148,7 @@ static void free_note_info(struct elf_note_info *info)
 
        /* Free data possibly allocated by fill_files_note(): */
        if (info->notes_files)
-               vfree(info->notes_files->data);
+               kvfree(info->notes_files->data);
 
        kfree(info->prstatus);
        kfree(info->psinfo);
@@ -2294,8 +2294,9 @@ static int elf_core_dump(struct coredump_params *cprm)
 
        if (segs - 1 > ULONG_MAX / sizeof(*vma_filesz))
                goto end_coredump;
-       vma_filesz = vmalloc(array_size(sizeof(*vma_filesz), (segs - 1)));
-       if (!vma_filesz)
+       vma_filesz = kvmalloc(array_size(sizeof(*vma_filesz), (segs - 1)),
+                             GFP_KERNEL);
+       if (ZERO_OR_NULL_PTR(vma_filesz))
                goto end_coredump;
 
        for (i = 0, vma = first_vma(current, gate_vma); vma != NULL;
@@ -2402,7 +2403,7 @@ end_coredump:
 cleanup:
        free_note_info(&info);
        kfree(shdr4extnum);
-       vfree(vma_filesz);
+       kvfree(vma_filesz);
        kfree(phdr4note);
        kfree(elf);
 out:
index 4de1915632611a5b4ebb99f74e996a07d13c8e03..4b5fff31ef279eb739a37ccba610eaf7a6a98787 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 1997 Richard Günther
  *
  * binfmt_misc detects binaries via a magic or filename extension and invokes
- * a specified wrapper. See Documentation/binfmt_misc.txt for more details.
+ * a specified wrapper. See Documentation/admin-guide/binfmt-misc.rst for more details.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index f4bf7874c24a4d63609a30a966d14f9db0a323e0..118346aceea9607ff98410df2764614f24f4505d 100644 (file)
@@ -3197,7 +3197,7 @@ int btrfs_merge_bio_hook(struct page *page, unsigned long offset,
                         size_t size, struct bio *bio,
                         unsigned long bio_flags);
 void btrfs_set_range_writeback(void *private_data, u64 start, u64 end);
-int btrfs_page_mkwrite(struct vm_fault *vmf);
+vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf);
 int btrfs_readpage(struct file *file, struct page *page);
 void btrfs_evict_inode(struct inode *inode);
 int btrfs_write_inode(struct inode *inode, struct writeback_control *wbc);
index 51fc015c7d2c69bd198e94c3ffc4b2ef267f7ef2..cce6087d6880fa4c1673dbc8aab0026fc62391f4 100644 (file)
@@ -4542,7 +4542,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                        offset_in_extent = em_start - em->start;
                em_end = extent_map_end(em);
                em_len = em_end - em_start;
-               disko = 0;
+               disko = em->block_start + offset_in_extent;
                flags = 0;
 
                /*
@@ -4565,8 +4565,6 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                        u64 bytenr = em->block_start -
                                (em->start - em->orig_start);
 
-                       disko = em->block_start + offset_in_extent;
-
                        /*
                         * As btrfs supports shared space, this information
                         * can be exported to userspace tools via
index f660ba1e5e58ef30f5c72555d7408b686e507e0e..51e77d72068af0ba3f9ffdfd624409c00d51978e 100644 (file)
@@ -1842,16 +1842,16 @@ out:
 
 static void update_time_for_write(struct inode *inode)
 {
-       struct timespec now;
+       struct timespec64 now;
 
        if (IS_NOCMTIME(inode))
                return;
 
        now = current_time(inode);
-       if (!timespec_equal(&inode->i_mtime, &now))
+       if (!timespec64_equal(&inode->i_mtime, &now))
                inode->i_mtime = now;
 
-       if (!timespec_equal(&inode->i_ctime, &now))
+       if (!timespec64_equal(&inode->i_ctime, &now))
                inode->i_ctime = now;
 
        if (IS_I_VERSION(inode))
index 89b2082017830942e040063a2ca000d1a10f75df..e9482f0db9d08ffd79a117f0d6f08b6eb94cae99 100644 (file)
@@ -5745,7 +5745,7 @@ static struct inode *new_simple_dir(struct super_block *s,
        inode->i_mtime = current_time(inode);
        inode->i_atime = inode->i_mtime;
        inode->i_ctime = inode->i_mtime;
-       BTRFS_I(inode)->i_otime = inode->i_mtime;
+       BTRFS_I(inode)->i_otime = timespec64_to_timespec(inode->i_mtime);
 
        return inode;
 }
@@ -6094,7 +6094,7 @@ static int btrfs_dirty_inode(struct inode *inode)
  * This is a copy of file_update_time.  We need this so we can return error on
  * ENOSPC for updating the inode in the case of file write and mmap writes.
  */
-static int btrfs_update_time(struct inode *inode, struct timespec *now,
+static int btrfs_update_time(struct inode *inode, struct timespec64 *now,
                             int flags)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
@@ -6349,7 +6349,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
        inode->i_mtime = current_time(inode);
        inode->i_atime = inode->i_mtime;
        inode->i_ctime = inode->i_mtime;
-       BTRFS_I(inode)->i_otime = inode->i_mtime;
+       BTRFS_I(inode)->i_otime = timespec64_to_timespec(inode->i_mtime);
 
        inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0],
                                  struct btrfs_inode_item);
@@ -8872,7 +8872,7 @@ again:
  * beyond EOF, then the page is guaranteed safe against truncation until we
  * unlock the page.
  */
-int btrfs_page_mkwrite(struct vm_fault *vmf)
+vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf)
 {
        struct page *page = vmf->page;
        struct inode *inode = file_inode(vmf->vma->vm_file);
@@ -8884,7 +8884,8 @@ int btrfs_page_mkwrite(struct vm_fault *vmf)
        char *kaddr;
        unsigned long zero_start;
        loff_t size;
-       int ret;
+       vm_fault_t ret;
+       int ret2;
        int reserved = 0;
        u64 reserved_space;
        u64 page_start;
@@ -8906,17 +8907,14 @@ int btrfs_page_mkwrite(struct vm_fault *vmf)
         * end up waiting indefinitely to get a lock on the page currently
         * being processed by btrfs_page_mkwrite() function.
         */
-       ret = btrfs_delalloc_reserve_space(inode, &data_reserved, page_start,
+       ret2 = btrfs_delalloc_reserve_space(inode, &data_reserved, page_start,
                                           reserved_space);
-       if (!ret) {
-               ret = file_update_time(vmf->vma->vm_file);
+       if (!ret2) {
+               ret2 = file_update_time(vmf->vma->vm_file);
                reserved = 1;
        }
-       if (ret) {
-               if (ret == -ENOMEM)
-                       ret = VM_FAULT_OOM;
-               else /* -ENOSPC, -EIO, etc */
-                       ret = VM_FAULT_SIGBUS;
+       if (ret2) {
+               ret = vmf_error(ret2);
                if (reserved)
                        goto out;
                goto out_noreserve;
@@ -8975,15 +8973,15 @@ again:
                          EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG,
                          0, 0, &cached_state);
 
-       ret = btrfs_set_extent_delalloc(inode, page_start, end, 0,
+       ret2 = btrfs_set_extent_delalloc(inode, page_start, end, 0,
                                        &cached_state, 0);
-       if (ret) {
+       if (ret2) {
                unlock_extent_cached(io_tree, page_start, page_end,
                                     &cached_state);
                ret = VM_FAULT_SIGBUS;
                goto out_unlock;
        }
-       ret = 0;
+       ret2 = 0;
 
        /* page is wholly or partially inside EOF */
        if (page_start + PAGE_SIZE > size)
@@ -9008,7 +9006,7 @@ again:
        unlock_extent_cached(io_tree, page_start, page_end, &cached_state);
 
 out_unlock:
-       if (!ret) {
+       if (!ret2) {
                btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE, true);
                sb_end_pagefault(inode->i_sb);
                extent_changeset_free(data_reserved);
@@ -9437,7 +9435,7 @@ static int btrfs_rename_exchange(struct inode *old_dir,
        struct btrfs_root *dest = BTRFS_I(new_dir)->root;
        struct inode *new_inode = new_dentry->d_inode;
        struct inode *old_inode = old_dentry->d_inode;
-       struct timespec ctime = current_time(old_inode);
+       struct timespec64 ctime = current_time(old_inode);
        struct dentry *parent;
        u64 old_ino = btrfs_ino(BTRFS_I(old_inode));
        u64 new_ino = btrfs_ino(BTRFS_I(new_inode));
index d29992f7dc6356b2de853f5dde76cebedc3e30d0..c2837a32d689de9a7d5d3bfc96d7d861cd221dfb 100644 (file)
@@ -562,7 +562,7 @@ static noinline int create_subvol(struct inode *dir,
        struct btrfs_root *root = BTRFS_I(dir)->root;
        struct btrfs_root *new_root;
        struct btrfs_block_rsv block_rsv;
-       struct timespec cur_time = current_time(dir);
+       struct timespec64 cur_time = current_time(dir);
        struct inode *inode;
        int ret;
        int err;
@@ -2438,6 +2438,10 @@ static int btrfs_search_path_in_tree_user(struct inode *inode,
                        }
 
                        temp_inode = btrfs_iget(sb, &key2, root, NULL);
+                       if (IS_ERR(temp_inode)) {
+                               ret = PTR_ERR(temp_inode);
+                               goto out;
+                       }
                        ret = inode_permission(temp_inode, MAY_READ | MAY_EXEC);
                        iput(temp_inode);
                        if (ret) {
@@ -5391,7 +5395,7 @@ static long _btrfs_ioctl_set_received_subvol(struct file *file,
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_root_item *root_item = &root->root_item;
        struct btrfs_trans_handle *trans;
-       struct timespec ct = current_time(inode);
+       struct timespec64 ct = current_time(inode);
        int ret = 0;
        int received_uuid_changed;
 
index 6db3bda44aa55f4be73c554d9f4fc961dc290841..c451285976acbf0dd91202dfe9644eeb03e4ef53 100644 (file)
@@ -485,9 +485,9 @@ void btrfs_update_root_times(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root)
 {
        struct btrfs_root_item *item = &root->root_item;
-       struct timespec ct;
+       struct timespec64 ct;
 
-       ktime_get_real_ts(&ct);
+       ktime_get_real_ts64(&ct);
        spin_lock(&root->root_item_lock);
        btrfs_set_root_ctransid(item, trans->transid);
        btrfs_set_stack_timespec_sec(&item->ctime, ct.tv_sec);
index a5900586201056f0c7429a35ad1b2255c917f40a..5723060364776d1fd3e3e1e09bdfc09d4bb7eadb 100644 (file)
@@ -2799,7 +2799,7 @@ static int scrub_extent(struct scrub_ctx *sctx, struct map_lookup *map,
                        have_csum = scrub_find_csum(sctx, logical, csum);
                        if (have_csum == 0)
                                ++sctx->stat.no_csum;
-                       if (sctx->is_dev_replace && !have_csum) {
+                       if (0 && sctx->is_dev_replace && !have_csum) {
                                ret = copy_nocow_pages(sctx, logical, l,
                                                       mirror_num,
                                                      physical_for_dev_replace);
index 4485eae41e88ad7a487c5bb2e8aa58f950cf7e36..ff5f6c719976699429599d780d71feec2868aa8f 100644 (file)
@@ -1422,7 +1422,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
        struct dentry *dentry;
        struct extent_buffer *tmp;
        struct extent_buffer *old;
-       struct timespec cur_time;
+       struct timespec64 cur_time;
        int ret = 0;
        u64 to_reserve = 0;
        u64 index = 0;
index c9cb2f33a6d6763f1abcce330186775d7e99eb0b..292b3d72d72505579d3b642083e57983927ee1bc 100644 (file)
@@ -574,6 +574,7 @@ static u64 get_writepages_data_length(struct inode *inode,
  */
 static int writepage_nounlock(struct page *page, struct writeback_control *wbc)
 {
+       struct timespec ts;
        struct inode *inode;
        struct ceph_inode_info *ci;
        struct ceph_fs_client *fsc;
@@ -624,11 +625,12 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc)
                set_bdi_congested(inode_to_bdi(inode), BLK_RW_ASYNC);
 
        set_page_writeback(page);
+       ts = timespec64_to_timespec(inode->i_mtime);
        err = ceph_osdc_writepages(&fsc->client->osdc, ceph_vino(inode),
                                   &ci->i_layout, snapc, page_off, len,
                                   ceph_wbc.truncate_seq,
                                   ceph_wbc.truncate_size,
-                                  &inode->i_mtime, &page, 1);
+                                  &ts, &page, 1);
        if (err < 0) {
                struct writeback_control tmp_wbc;
                if (!wbc)
@@ -1132,7 +1134,7 @@ new_request:
                        pages = NULL;
                }
 
-               req->r_mtime = inode->i_mtime;
+               req->r_mtime = timespec64_to_timespec(inode->i_mtime);
                rc = ceph_osdc_start_request(&fsc->client->osdc, req, true);
                BUG_ON(rc);
                req = NULL;
@@ -1732,7 +1734,7 @@ int ceph_uninline_data(struct file *filp, struct page *locked_page)
                goto out;
        }
 
-       req->r_mtime = inode->i_mtime;
+       req->r_mtime = timespec64_to_timespec(inode->i_mtime);
        err = ceph_osdc_start_request(&fsc->client->osdc, req, false);
        if (!err)
                err = ceph_osdc_wait_request(&fsc->client->osdc, req);
@@ -1774,7 +1776,7 @@ int ceph_uninline_data(struct file *filp, struct page *locked_page)
                        goto out_put;
        }
 
-       req->r_mtime = inode->i_mtime;
+       req->r_mtime = timespec64_to_timespec(inode->i_mtime);
        err = ceph_osdc_start_request(&fsc->client->osdc, req, false);
        if (!err)
                err = ceph_osdc_wait_request(&fsc->client->osdc, req);
@@ -1935,8 +1937,7 @@ static int __ceph_pool_perm_get(struct ceph_inode_info *ci,
                                     0, false, true);
        err = ceph_osdc_start_request(&fsc->client->osdc, rd_req, false);
 
-       wr_req->r_mtime = ci->vfs_inode.i_mtime;
-       wr_req->r_abort_on_full = true;
+       wr_req->r_mtime = timespec64_to_timespec(ci->vfs_inode.i_mtime);
        err2 = ceph_osdc_start_request(&fsc->client->osdc, wr_req, false);
 
        if (!err)
index bb524c880b1eadf2915a0a551eb01730871dee9a..362900e424245bd7c5714fde340f9b6a286ce6f3 100644 (file)
@@ -130,7 +130,7 @@ static enum fscache_checkaux ceph_fscache_inode_check_aux(
 
        memset(&aux, 0, sizeof(aux));
        aux.version = ci->i_version;
-       aux.mtime = inode->i_mtime;
+       aux.mtime = timespec64_to_timespec(inode->i_mtime);
 
        if (memcmp(data, &aux, sizeof(aux)) != 0)
                return FSCACHE_CHECKAUX_OBSOLETE;
@@ -163,7 +163,7 @@ void ceph_fscache_register_inode_cookie(struct inode *inode)
        if (!ci->fscache) {
                memset(&aux, 0, sizeof(aux));
                aux.version = ci->i_version;
-               aux.mtime = inode->i_mtime;
+               aux.mtime = timespec64_to_timespec(inode->i_mtime);
                ci->fscache = fscache_acquire_cookie(fsc->fscache,
                                                     &ceph_fscache_inode_object_def,
                                                     &ci->i_vino, sizeof(ci->i_vino),
index 23dbfae1615685dde002b8fa4e77ed54f6a01c0e..990258cbd836c810df88bb4949d897fca1b7f043 100644 (file)
@@ -69,6 +69,8 @@ static char *gcap_string(char *s, int c)
                *s++ = 'w';
        if (c & CEPH_CAP_GBUFFER)
                *s++ = 'b';
+       if (c & CEPH_CAP_GWREXTEND)
+               *s++ = 'a';
        if (c & CEPH_CAP_GLAZYIO)
                *s++ = 'l';
        return s;
@@ -1358,9 +1360,9 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap,
                arg.xattr_buf = NULL;
        }
 
-       arg.mtime = inode->i_mtime;
-       arg.atime = inode->i_atime;
-       arg.ctime = inode->i_ctime;
+       arg.mtime = timespec64_to_timespec(inode->i_mtime);
+       arg.atime = timespec64_to_timespec(inode->i_atime);
+       arg.ctime = timespec64_to_timespec(inode->i_ctime);
 
        arg.op = op;
        arg.caps = cap->implemented;
@@ -3022,30 +3024,41 @@ static void invalidate_aliases(struct inode *inode)
                dput(prev);
 }
 
+struct cap_extra_info {
+       struct ceph_string *pool_ns;
+       /* inline data */
+       u64 inline_version;
+       void *inline_data;
+       u32 inline_len;
+       /* dirstat */
+       bool dirstat_valid;
+       u64 nfiles;
+       u64 nsubdirs;
+       /* currently issued */
+       int issued;
+};
+
 /*
  * Handle a cap GRANT message from the MDS.  (Note that a GRANT may
  * actually be a revocation if it specifies a smaller cap set.)
  *
  * caller holds s_mutex and i_ceph_lock, we drop both.
  */
-static void handle_cap_grant(struct ceph_mds_client *mdsc,
-                            struct inode *inode, struct ceph_mds_caps *grant,
-                            struct ceph_string **pns, u64 inline_version,
-                            void *inline_data, u32 inline_len,
-                            struct ceph_buffer *xattr_buf,
+static void handle_cap_grant(struct inode *inode,
                             struct ceph_mds_session *session,
-                            struct ceph_cap *cap, int issued)
+                            struct ceph_cap *cap,
+                            struct ceph_mds_caps *grant,
+                            struct ceph_buffer *xattr_buf,
+                            struct cap_extra_info *extra_info)
        __releases(ci->i_ceph_lock)
-       __releases(mdsc->snap_rwsem)
+       __releases(session->s_mdsc->snap_rwsem)
 {
        struct ceph_inode_info *ci = ceph_inode(inode);
-       int mds = session->s_mds;
        int seq = le32_to_cpu(grant->seq);
        int newcaps = le32_to_cpu(grant->caps);
        int used, wanted, dirty;
        u64 size = le64_to_cpu(grant->size);
        u64 max_size = le64_to_cpu(grant->max_size);
-       struct timespec mtime, atime, ctime;
        int check_caps = 0;
        bool wake = false;
        bool writeback = false;
@@ -3055,7 +3068,7 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc,
        bool fill_inline = false;
 
        dout("handle_cap_grant inode %p cap %p mds%d seq %d %s\n",
-            inode, cap, mds, seq, ceph_cap_string(newcaps));
+            inode, cap, session->s_mds, seq, ceph_cap_string(newcaps));
        dout(" size %llu max_size %llu, i_size %llu\n", size, max_size,
                inode->i_size);
 
@@ -3101,7 +3114,7 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc,
        __check_cap_issue(ci, cap, newcaps);
 
        if ((newcaps & CEPH_CAP_AUTH_SHARED) &&
-           (issued & CEPH_CAP_AUTH_EXCL) == 0) {
+           (extra_info->issued & CEPH_CAP_AUTH_EXCL) == 0) {
                inode->i_mode = le32_to_cpu(grant->mode);
                inode->i_uid = make_kuid(&init_user_ns, le32_to_cpu(grant->uid));
                inode->i_gid = make_kgid(&init_user_ns, le32_to_cpu(grant->gid));
@@ -3110,15 +3123,16 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc,
                     from_kgid(&init_user_ns, inode->i_gid));
        }
 
-       if ((newcaps & CEPH_CAP_AUTH_SHARED) &&
-           (issued & CEPH_CAP_LINK_EXCL) == 0) {
+       if ((newcaps & CEPH_CAP_LINK_SHARED) &&
+           (extra_info->issued & CEPH_CAP_LINK_EXCL) == 0) {
                set_nlink(inode, le32_to_cpu(grant->nlink));
                if (inode->i_nlink == 0 &&
                    (newcaps & (CEPH_CAP_LINK_SHARED | CEPH_CAP_LINK_EXCL)))
                        deleted_inode = true;
        }
 
-       if ((issued & CEPH_CAP_XATTR_EXCL) == 0 && grant->xattr_len) {
+       if ((extra_info->issued & CEPH_CAP_XATTR_EXCL) == 0 &&
+           grant->xattr_len) {
                int len = le32_to_cpu(grant->xattr_len);
                u64 version = le64_to_cpu(grant->xattr_version);
 
@@ -3134,15 +3148,21 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc,
        }
 
        if (newcaps & CEPH_CAP_ANY_RD) {
+               struct timespec mtime, atime, ctime;
                /* ctime/mtime/atime? */
                ceph_decode_timespec(&mtime, &grant->mtime);
                ceph_decode_timespec(&atime, &grant->atime);
                ceph_decode_timespec(&ctime, &grant->ctime);
-               ceph_fill_file_time(inode, issued,
+               ceph_fill_file_time(inode, extra_info->issued,
                                    le32_to_cpu(grant->time_warp_seq),
                                    &ctime, &mtime, &atime);
        }
 
+       if ((newcaps & CEPH_CAP_FILE_SHARED) && extra_info->dirstat_valid) {
+               ci->i_files = extra_info->nfiles;
+               ci->i_subdirs = extra_info->nsubdirs;
+       }
+
        if (newcaps & (CEPH_CAP_ANY_FILE_RD | CEPH_CAP_ANY_FILE_WR)) {
                /* file layout may have changed */
                s64 old_pool = ci->i_layout.pool_id;
@@ -3151,15 +3171,16 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc,
                ceph_file_layout_from_legacy(&ci->i_layout, &grant->layout);
                old_ns = rcu_dereference_protected(ci->i_layout.pool_ns,
                                        lockdep_is_held(&ci->i_ceph_lock));
-               rcu_assign_pointer(ci->i_layout.pool_ns, *pns);
+               rcu_assign_pointer(ci->i_layout.pool_ns, extra_info->pool_ns);
 
-               if (ci->i_layout.pool_id != old_pool || *pns != old_ns)
+               if (ci->i_layout.pool_id != old_pool ||
+                   extra_info->pool_ns != old_ns)
                        ci->i_ceph_flags &= ~CEPH_I_POOL_PERM;
 
-               *pns = old_ns;
+               extra_info->pool_ns = old_ns;
 
                /* size/truncate_seq? */
-               queue_trunc = ceph_fill_file_size(inode, issued,
+               queue_trunc = ceph_fill_file_size(inode, extra_info->issued,
                                        le32_to_cpu(grant->truncate_seq),
                                        le64_to_cpu(grant->truncate_size),
                                        size);
@@ -3238,24 +3259,26 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc,
        }
        BUG_ON(cap->issued & ~cap->implemented);
 
-       if (inline_version > 0 && inline_version >= ci->i_inline_version) {
-               ci->i_inline_version = inline_version;
+       if (extra_info->inline_version > 0 &&
+           extra_info->inline_version >= ci->i_inline_version) {
+               ci->i_inline_version = extra_info->inline_version;
                if (ci->i_inline_version != CEPH_INLINE_NONE &&
                    (newcaps & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)))
                        fill_inline = true;
        }
 
        if (le32_to_cpu(grant->op) == CEPH_CAP_OP_IMPORT) {
-               if (newcaps & ~issued)
+               if (newcaps & ~extra_info->issued)
                        wake = true;
-               kick_flushing_inode_caps(mdsc, session, inode);
-               up_read(&mdsc->snap_rwsem);
+               kick_flushing_inode_caps(session->s_mdsc, session, inode);
+               up_read(&session->s_mdsc->snap_rwsem);
        } else {
                spin_unlock(&ci->i_ceph_lock);
        }
 
        if (fill_inline)
-               ceph_fill_inline_data(inode, NULL, inline_data, inline_len);
+               ceph_fill_inline_data(inode, NULL, extra_info->inline_data,
+                                     extra_info->inline_len);
 
        if (queue_trunc)
                ceph_queue_vmtruncate(inode);
@@ -3720,31 +3743,25 @@ void ceph_handle_caps(struct ceph_mds_session *session,
                      struct ceph_msg *msg)
 {
        struct ceph_mds_client *mdsc = session->s_mdsc;
-       struct super_block *sb = mdsc->fsc->sb;
        struct inode *inode;
        struct ceph_inode_info *ci;
        struct ceph_cap *cap;
        struct ceph_mds_caps *h;
        struct ceph_mds_cap_peer *peer = NULL;
        struct ceph_snap_realm *realm = NULL;
-       struct ceph_string *pool_ns = NULL;
-       int mds = session->s_mds;
-       int op, issued;
+       int op;
+       int msg_version = le16_to_cpu(msg->hdr.version);
        u32 seq, mseq;
        struct ceph_vino vino;
-       u64 tid;
-       u64 inline_version = 0;
-       void *inline_data = NULL;
-       u32  inline_len = 0;
        void *snaptrace;
        size_t snaptrace_len;
        void *p, *end;
+       struct cap_extra_info extra_info = {};
 
-       dout("handle_caps from mds%d\n", mds);
+       dout("handle_caps from mds%d\n", session->s_mds);
 
        /* decode */
        end = msg->front.iov_base + msg->front.iov_len;
-       tid = le64_to_cpu(msg->hdr.tid);
        if (msg->front.iov_len < sizeof(*h))
                goto bad;
        h = msg->front.iov_base;
@@ -3758,7 +3775,7 @@ void ceph_handle_caps(struct ceph_mds_session *session,
        snaptrace_len = le32_to_cpu(h->snap_trace_len);
        p = snaptrace + snaptrace_len;
 
-       if (le16_to_cpu(msg->hdr.version) >= 2) {
+       if (msg_version >= 2) {
                u32 flock_len;
                ceph_decode_32_safe(&p, end, flock_len, bad);
                if (p + flock_len > end)
@@ -3766,7 +3783,7 @@ void ceph_handle_caps(struct ceph_mds_session *session,
                p += flock_len;
        }
 
-       if (le16_to_cpu(msg->hdr.version) >= 3) {
+       if (msg_version >= 3) {
                if (op == CEPH_CAP_OP_IMPORT) {
                        if (p + sizeof(*peer) > end)
                                goto bad;
@@ -3778,16 +3795,16 @@ void ceph_handle_caps(struct ceph_mds_session *session,
                }
        }
 
-       if (le16_to_cpu(msg->hdr.version) >= 4) {
-               ceph_decode_64_safe(&p, end, inline_version, bad);
-               ceph_decode_32_safe(&p, end, inline_len, bad);
-               if (p + inline_len > end)
+       if (msg_version >= 4) {
+               ceph_decode_64_safe(&p, end, extra_info.inline_version, bad);
+               ceph_decode_32_safe(&p, end, extra_info.inline_len, bad);
+               if (p + extra_info.inline_len > end)
                        goto bad;
-               inline_data = p;
-               p += inline_len;
+               extra_info.inline_data = p;
+               p += extra_info.inline_len;
        }
 
-       if (le16_to_cpu(msg->hdr.version) >= 5) {
+       if (msg_version >= 5) {
                struct ceph_osd_client  *osdc = &mdsc->fsc->client->osdc;
                u32                     epoch_barrier;
 
@@ -3795,7 +3812,7 @@ void ceph_handle_caps(struct ceph_mds_session *session,
                ceph_osdc_update_epoch_barrier(osdc, epoch_barrier);
        }
 
-       if (le16_to_cpu(msg->hdr.version) >= 8) {
+       if (msg_version >= 8) {
                u64 flush_tid;
                u32 caller_uid, caller_gid;
                u32 pool_ns_len;
@@ -3809,13 +3826,33 @@ void ceph_handle_caps(struct ceph_mds_session *session,
                ceph_decode_32_safe(&p, end, pool_ns_len, bad);
                if (pool_ns_len > 0) {
                        ceph_decode_need(&p, end, pool_ns_len, bad);
-                       pool_ns = ceph_find_or_create_string(p, pool_ns_len);
+                       extra_info.pool_ns =
+                               ceph_find_or_create_string(p, pool_ns_len);
                        p += pool_ns_len;
                }
        }
 
+       if (msg_version >= 11) {
+               struct ceph_timespec *btime;
+               u64 change_attr;
+               u32 flags;
+
+               /* version >= 9 */
+               if (p + sizeof(*btime) > end)
+                       goto bad;
+               btime = p;
+               p += sizeof(*btime);
+               ceph_decode_64_safe(&p, end, change_attr, bad);
+               /* version >= 10 */
+               ceph_decode_32_safe(&p, end, flags, bad);
+               /* version >= 11 */
+               extra_info.dirstat_valid = true;
+               ceph_decode_64_safe(&p, end, extra_info.nfiles, bad);
+               ceph_decode_64_safe(&p, end, extra_info.nsubdirs, bad);
+       }
+
        /* lookup ino */
-       inode = ceph_find_inode(sb, vino);
+       inode = ceph_find_inode(mdsc->fsc->sb, vino);
        ci = ceph_inode(inode);
        dout(" op %s ino %llx.%llx inode %p\n", ceph_cap_op_name(op), vino.ino,
             vino.snap, inode);
@@ -3848,7 +3885,8 @@ void ceph_handle_caps(struct ceph_mds_session *session,
        /* these will work even if we don't have a cap yet */
        switch (op) {
        case CEPH_CAP_OP_FLUSHSNAP_ACK:
-               handle_cap_flushsnap_ack(inode, tid, h, session);
+               handle_cap_flushsnap_ack(inode, le64_to_cpu(msg->hdr.tid),
+                                        h, session);
                goto done;
 
        case CEPH_CAP_OP_EXPORT:
@@ -3867,10 +3905,9 @@ void ceph_handle_caps(struct ceph_mds_session *session,
                        down_read(&mdsc->snap_rwsem);
                }
                handle_cap_import(mdsc, inode, h, peer, session,
-                                 &cap, &issued);
-               handle_cap_grant(mdsc, inode, h, &pool_ns,
-                                inline_version, inline_data, inline_len,
-                                msg->middle, session, cap, issued);
+                                 &cap, &extra_info.issued);
+               handle_cap_grant(inode, session, cap,
+                                h, msg->middle, &extra_info);
                if (realm)
                        ceph_put_snap_realm(mdsc, realm);
                goto done_unlocked;
@@ -3878,10 +3915,11 @@ void ceph_handle_caps(struct ceph_mds_session *session,
 
        /* the rest require a cap */
        spin_lock(&ci->i_ceph_lock);
-       cap = __get_cap_for_mds(ceph_inode(inode), mds);
+       cap = __get_cap_for_mds(ceph_inode(inode), session->s_mds);
        if (!cap) {
                dout(" no cap on %p ino %llx.%llx from mds%d\n",
-                    inode, ceph_ino(inode), ceph_snap(inode), mds);
+                    inode, ceph_ino(inode), ceph_snap(inode),
+                    session->s_mds);
                spin_unlock(&ci->i_ceph_lock);
                goto flush_cap_releases;
        }
@@ -3890,15 +3928,15 @@ void ceph_handle_caps(struct ceph_mds_session *session,
        switch (op) {
        case CEPH_CAP_OP_REVOKE:
        case CEPH_CAP_OP_GRANT:
-               __ceph_caps_issued(ci, &issued);
-               issued |= __ceph_caps_dirty(ci);
-               handle_cap_grant(mdsc, inode, h, &pool_ns,
-                                inline_version, inline_data, inline_len,
-                                msg->middle, session, cap, issued);
+               __ceph_caps_issued(ci, &extra_info.issued);
+               extra_info.issued |= __ceph_caps_dirty(ci);
+               handle_cap_grant(inode, session, cap,
+                                h, msg->middle, &extra_info);
                goto done_unlocked;
 
        case CEPH_CAP_OP_FLUSH_ACK:
-               handle_cap_flush_ack(inode, tid, h, session, cap);
+               handle_cap_flush_ack(inode, le64_to_cpu(msg->hdr.tid),
+                                    h, session, cap);
                break;
 
        case CEPH_CAP_OP_TRUNC:
@@ -3925,7 +3963,7 @@ done:
        mutex_unlock(&session->s_mutex);
 done_unlocked:
        iput(inode);
-       ceph_put_string(pool_ns);
+       ceph_put_string(extra_info.pool_ns);
        return;
 
 bad:
index 1a78dd6f8bf27655b03161de2617f7fc57f8f1b7..036ac0f3a393afe98278cd388de4e68b7e4b286c 100644 (file)
@@ -1486,6 +1486,8 @@ const struct file_operations ceph_dir_fops = {
        .release = ceph_release,
        .unlocked_ioctl = ceph_ioctl,
        .fsync = ceph_fsync,
+       .lock = ceph_lock,
+       .flock = ceph_flock,
 };
 
 const struct file_operations ceph_snapdir_fops = {
index cf0e45b10121aa8323ca7d6a86a109d6f8675c08..ad0bed99b1d5ab0c61922ae561cab24d2e9d4933 100644 (file)
@@ -895,7 +895,6 @@ static void ceph_aio_retry_work(struct work_struct *work)
        req->r_callback = ceph_aio_complete_req;
        req->r_inode = inode;
        req->r_priv = aio_req;
-       req->r_abort_on_full = true;
 
        ret = ceph_osdc_start_request(req->r_osdc, req, false);
 out:
@@ -924,7 +923,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
        int num_pages = 0;
        int flags;
        int ret;
-       struct timespec mtime = current_time(inode);
+       struct timespec mtime = timespec64_to_timespec(current_time(inode));
        size_t count = iov_iter_count(iter);
        loff_t pos = iocb->ki_pos;
        bool write = iov_iter_rw(iter) == WRITE;
@@ -1132,7 +1131,7 @@ ceph_sync_write(struct kiocb *iocb, struct iov_iter *from, loff_t pos,
        int flags;
        int ret;
        bool check_caps = false;
-       struct timespec mtime = current_time(inode);
+       struct timespec mtime = timespec64_to_timespec(current_time(inode));
        size_t count = iov_iter_count(from);
 
        if (ceph_snap(file_inode(file)) != CEPH_NOSNAP)
@@ -1664,7 +1663,7 @@ static int ceph_zero_partial_object(struct inode *inode,
                goto out;
        }
 
-       req->r_mtime = inode->i_mtime;
+       req->r_mtime = timespec64_to_timespec(inode->i_mtime);
        ret = ceph_osdc_start_request(&fsc->client->osdc, req, false);
        if (!ret) {
                ret = ceph_osdc_wait_request(&fsc->client->osdc, req);
index ae056927080d28cf3eff14697ded16acdf33f38d..ee764ac352ab7b855165b797c1daf579fbaa45e1 100644 (file)
@@ -662,6 +662,9 @@ void ceph_fill_file_time(struct inode *inode, int issued,
                         struct timespec *mtime, struct timespec *atime)
 {
        struct ceph_inode_info *ci = ceph_inode(inode);
+       struct timespec64 ctime64 = timespec_to_timespec64(*ctime);
+       struct timespec64 mtime64 = timespec_to_timespec64(*mtime);
+       struct timespec64 atime64 = timespec_to_timespec64(*atime);
        int warn = 0;
 
        if (issued & (CEPH_CAP_FILE_EXCL|
@@ -670,39 +673,39 @@ void ceph_fill_file_time(struct inode *inode, int issued,
                      CEPH_CAP_AUTH_EXCL|
                      CEPH_CAP_XATTR_EXCL)) {
                if (ci->i_version == 0 ||
-                   timespec_compare(ctime, &inode->i_ctime) > 0) {
-                       dout("ctime %ld.%09ld -> %ld.%09ld inc w/ cap\n",
-                            inode->i_ctime.tv_sec, inode->i_ctime.tv_nsec,
-                            ctime->tv_sec, ctime->tv_nsec);
-                       inode->i_ctime = *ctime;
+                   timespec64_compare(&ctime64, &inode->i_ctime) > 0) {
+                       dout("ctime %lld.%09ld -> %lld.%09ld inc w/ cap\n",
+                            (long long)inode->i_ctime.tv_sec, inode->i_ctime.tv_nsec,
+                            (long long)ctime->tv_sec, ctime->tv_nsec);
+                       inode->i_ctime = ctime64;
                }
                if (ci->i_version == 0 ||
                    ceph_seq_cmp(time_warp_seq, ci->i_time_warp_seq) > 0) {
                        /* the MDS did a utimes() */
-                       dout("mtime %ld.%09ld -> %ld.%09ld "
+                       dout("mtime %lld.%09ld -> %lld.%09ld "
                             "tw %d -> %d\n",
-                            inode->i_mtime.tv_sec, inode->i_mtime.tv_nsec,
-                            mtime->tv_sec, mtime->tv_nsec,
+                            (long long)inode->i_mtime.tv_sec, inode->i_mtime.tv_nsec,
+                            (long long)mtime->tv_sec, mtime->tv_nsec,
                             ci->i_time_warp_seq, (int)time_warp_seq);
 
-                       inode->i_mtime = *mtime;
-                       inode->i_atime = *atime;
+                       inode->i_mtime = mtime64;
+                       inode->i_atime = atime64;
                        ci->i_time_warp_seq = time_warp_seq;
                } else if (time_warp_seq == ci->i_time_warp_seq) {
                        /* nobody did utimes(); take the max */
-                       if (timespec_compare(mtime, &inode->i_mtime) > 0) {
-                               dout("mtime %ld.%09ld -> %ld.%09ld inc\n",
-                                    inode->i_mtime.tv_sec,
+                       if (timespec64_compare(&mtime64, &inode->i_mtime) > 0) {
+                               dout("mtime %lld.%09ld -> %lld.%09ld inc\n",
+                                    (long long)inode->i_mtime.tv_sec,
                                     inode->i_mtime.tv_nsec,
-                                    mtime->tv_sec, mtime->tv_nsec);
-                               inode->i_mtime = *mtime;
+                                    (long long)mtime->tv_sec, mtime->tv_nsec);
+                               inode->i_mtime = mtime64;
                        }
-                       if (timespec_compare(atime, &inode->i_atime) > 0) {
-                               dout("atime %ld.%09ld -> %ld.%09ld inc\n",
-                                    inode->i_atime.tv_sec,
+                       if (timespec64_compare(&atime64, &inode->i_atime) > 0) {
+                               dout("atime %lld.%09ld -> %lld.%09ld inc\n",
+                                    (long long)inode->i_atime.tv_sec,
                                     inode->i_atime.tv_nsec,
-                                    atime->tv_sec, atime->tv_nsec);
-                               inode->i_atime = *atime;
+                                    (long long)atime->tv_sec, atime->tv_nsec);
+                               inode->i_atime = atime64;
                        }
                } else if (issued & CEPH_CAP_FILE_EXCL) {
                        /* we did a utimes(); ignore mds values */
@@ -712,9 +715,9 @@ void ceph_fill_file_time(struct inode *inode, int issued,
        } else {
                /* we have no write|excl caps; whatever the MDS says is true */
                if (ceph_seq_cmp(time_warp_seq, ci->i_time_warp_seq) >= 0) {
-                       inode->i_ctime = *ctime;
-                       inode->i_mtime = *mtime;
-                       inode->i_atime = *atime;
+                       inode->i_ctime = ctime64;
+                       inode->i_mtime = mtime64;
+                       inode->i_atime = atime64;
                        ci->i_time_warp_seq = time_warp_seq;
                } else {
                        warn = 1;
@@ -739,7 +742,7 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
        struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
        struct ceph_mds_reply_inode *info = iinfo->in;
        struct ceph_inode_info *ci = ceph_inode(inode);
-       int issued = 0, implemented, new_issued;
+       int issued, new_issued, info_caps;
        struct timespec mtime, atime, ctime;
        struct ceph_buffer *xattr_blob = NULL;
        struct ceph_string *pool_ns = NULL;
@@ -754,8 +757,10 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
             inode, ceph_vinop(inode), le64_to_cpu(info->version),
             ci->i_version);
 
+       info_caps = le32_to_cpu(info->cap.caps);
+
        /* prealloc new cap struct */
-       if (info->cap.caps && ceph_snap(inode) == CEPH_NOSNAP)
+       if (info_caps && ceph_snap(inode) == CEPH_NOSNAP)
                new_cap = ceph_get_cap(mdsc, caps_reservation);
 
        /*
@@ -792,9 +797,9 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
             le64_to_cpu(info->version) > (ci->i_version & ~1)))
                new_version = true;
 
-       issued = __ceph_caps_issued(ci, &implemented);
-       issued |= implemented | __ceph_caps_dirty(ci);
-       new_issued = ~issued & le32_to_cpu(info->cap.caps);
+       __ceph_caps_issued(ci, &issued);
+       issued |= __ceph_caps_dirty(ci);
+       new_issued = ~issued & info_caps;
 
        /* update inode */
        inode->i_rdev = le32_to_cpu(info->rdev);
@@ -826,6 +831,11 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
                                &ctime, &mtime, &atime);
        }
 
+       if (new_version || (info_caps & CEPH_CAP_FILE_SHARED)) {
+               ci->i_files = le64_to_cpu(info->files);
+               ci->i_subdirs = le64_to_cpu(info->subdirs);
+       }
+
        if (new_version ||
            (new_issued & (CEPH_CAP_ANY_FILE_RD | CEPH_CAP_ANY_FILE_WR))) {
                s64 old_pool = ci->i_layout.pool_id;
@@ -854,6 +864,18 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
                }
        }
 
+       /* layout and rstat are not tracked by capability, update them if
+        * the inode info is from auth mds */
+       if (new_version || (info->cap.flags & CEPH_CAP_FLAG_AUTH)) {
+               if (S_ISDIR(inode->i_mode)) {
+                       ci->i_dir_layout = iinfo->dir_layout;
+                       ci->i_rbytes = le64_to_cpu(info->rbytes);
+                       ci->i_rfiles = le64_to_cpu(info->rfiles);
+                       ci->i_rsubdirs = le64_to_cpu(info->rsubdirs);
+                       ceph_decode_timespec(&ci->i_rctime, &info->rctime);
+               }
+       }
+
        /* xattrs */
        /* note that if i_xattrs.len <= 4, i_xattrs.data will still be NULL. */
        if ((ci->i_xattrs.version == 0 || !(issued & CEPH_CAP_XATTR_EXCL))  &&
@@ -870,7 +892,8 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
        }
 
        /* finally update i_version */
-       ci->i_version = le64_to_cpu(info->version);
+       if (le64_to_cpu(info->version) > ci->i_version)
+               ci->i_version = le64_to_cpu(info->version);
 
        inode->i_mapping->a_ops = &ceph_aops;
 
@@ -918,15 +941,6 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
        case S_IFDIR:
                inode->i_op = &ceph_dir_iops;
                inode->i_fop = &ceph_dir_fops;
-
-               ci->i_dir_layout = iinfo->dir_layout;
-
-               ci->i_files = le64_to_cpu(info->files);
-               ci->i_subdirs = le64_to_cpu(info->subdirs);
-               ci->i_rbytes = le64_to_cpu(info->rbytes);
-               ci->i_rfiles = le64_to_cpu(info->rfiles);
-               ci->i_rsubdirs = le64_to_cpu(info->rsubdirs);
-               ceph_decode_timespec(&ci->i_rctime, &info->rctime);
                break;
        default:
                pr_err("fill_inode %llx.%llx BAD mode 0%o\n",
@@ -934,12 +948,11 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
        }
 
        /* were we issued a capability? */
-       if (info->cap.caps) {
+       if (info_caps) {
                if (ceph_snap(inode) == CEPH_NOSNAP) {
-                       unsigned caps = le32_to_cpu(info->cap.caps);
                        ceph_add_cap(inode, session,
                                     le64_to_cpu(info->cap.cap_id),
-                                    cap_fmode, caps,
+                                    cap_fmode, info_caps,
                                     le32_to_cpu(info->cap.wanted),
                                     le32_to_cpu(info->cap.seq),
                                     le32_to_cpu(info->cap.mseq),
@@ -949,7 +962,7 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
                        /* set dir completion flag? */
                        if (S_ISDIR(inode->i_mode) &&
                            ci->i_files == 0 && ci->i_subdirs == 0 &&
-                           (caps & CEPH_CAP_FILE_SHARED) &&
+                           (info_caps & CEPH_CAP_FILE_SHARED) &&
                            (issued & CEPH_CAP_FILE_EXCL) == 0 &&
                            !__ceph_dir_is_complete(ci)) {
                                dout(" marking %p complete (empty)\n", inode);
@@ -962,8 +975,8 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
                        wake = true;
                } else {
                        dout(" %p got snap_caps %s\n", inode,
-                            ceph_cap_string(le32_to_cpu(info->cap.caps)));
-                       ci->i_snap_caps |= le32_to_cpu(info->cap.caps);
+                            ceph_cap_string(info_caps));
+                       ci->i_snap_caps |= info_caps;
                        if (cap_fmode >= 0)
                                __ceph_get_fmode(ci, cap_fmode);
                }
@@ -978,8 +991,7 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
                int cache_caps = CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_LAZYIO;
                ci->i_inline_version = iinfo->inline_version;
                if (ci->i_inline_version != CEPH_INLINE_NONE &&
-                   (locked_page ||
-                    (le32_to_cpu(info->cap.caps) & cache_caps)))
+                   (locked_page || (info_caps & cache_caps)))
                        fill_inline = true;
        }
 
@@ -1941,6 +1953,7 @@ int __ceph_setattr(struct inode *inode, struct iattr *attr)
        int err = 0;
        int inode_dirty_flags = 0;
        bool lock_snap_rwsem = false;
+       struct timespec ts;
 
        prealloc_cf = ceph_alloc_cap_flush();
        if (!prealloc_cf)
@@ -2015,44 +2028,44 @@ int __ceph_setattr(struct inode *inode, struct iattr *attr)
        }
 
        if (ia_valid & ATTR_ATIME) {
-               dout("setattr %p atime %ld.%ld -> %ld.%ld\n", inode,
-                    inode->i_atime.tv_sec, inode->i_atime.tv_nsec,
-                    attr->ia_atime.tv_sec, attr->ia_atime.tv_nsec);
+               dout("setattr %p atime %lld.%ld -> %lld.%ld\n", inode,
+                    (long long)inode->i_atime.tv_sec, inode->i_atime.tv_nsec,
+                    (long long)attr->ia_atime.tv_sec, attr->ia_atime.tv_nsec);
                if (issued & CEPH_CAP_FILE_EXCL) {
                        ci->i_time_warp_seq++;
                        inode->i_atime = attr->ia_atime;
                        dirtied |= CEPH_CAP_FILE_EXCL;
                } else if ((issued & CEPH_CAP_FILE_WR) &&
-                          timespec_compare(&inode->i_atime,
+                          timespec64_compare(&inode->i_atime,
                                            &attr->ia_atime) < 0) {
                        inode->i_atime = attr->ia_atime;
                        dirtied |= CEPH_CAP_FILE_WR;
                } else if ((issued & CEPH_CAP_FILE_SHARED) == 0 ||
-                          !timespec_equal(&inode->i_atime, &attr->ia_atime)) {
-                       ceph_encode_timespec(&req->r_args.setattr.atime,
-                                            &attr->ia_atime);
+                          !timespec64_equal(&inode->i_atime, &attr->ia_atime)) {
+                       ts = timespec64_to_timespec(attr->ia_atime);
+                       ceph_encode_timespec(&req->r_args.setattr.atime, &ts);
                        mask |= CEPH_SETATTR_ATIME;
                        release |= CEPH_CAP_FILE_SHARED |
                                   CEPH_CAP_FILE_RD | CEPH_CAP_FILE_WR;
                }
        }
        if (ia_valid & ATTR_MTIME) {
-               dout("setattr %p mtime %ld.%ld -> %ld.%ld\n", inode,
-                    inode->i_mtime.tv_sec, inode->i_mtime.tv_nsec,
-                    attr->ia_mtime.tv_sec, attr->ia_mtime.tv_nsec);
+               dout("setattr %p mtime %lld.%ld -> %lld.%ld\n", inode,
+                    (long long)inode->i_mtime.tv_sec, inode->i_mtime.tv_nsec,
+                    (long long)attr->ia_mtime.tv_sec, attr->ia_mtime.tv_nsec);
                if (issued & CEPH_CAP_FILE_EXCL) {
                        ci->i_time_warp_seq++;
                        inode->i_mtime = attr->ia_mtime;
                        dirtied |= CEPH_CAP_FILE_EXCL;
                } else if ((issued & CEPH_CAP_FILE_WR) &&
-                          timespec_compare(&inode->i_mtime,
+                          timespec64_compare(&inode->i_mtime,
                                            &attr->ia_mtime) < 0) {
                        inode->i_mtime = attr->ia_mtime;
                        dirtied |= CEPH_CAP_FILE_WR;
                } else if ((issued & CEPH_CAP_FILE_SHARED) == 0 ||
-                          !timespec_equal(&inode->i_mtime, &attr->ia_mtime)) {
-                       ceph_encode_timespec(&req->r_args.setattr.mtime,
-                                            &attr->ia_mtime);
+                          !timespec64_equal(&inode->i_mtime, &attr->ia_mtime)) {
+                       ts = timespec64_to_timespec(attr->ia_mtime);
+                       ceph_encode_timespec(&req->r_args.setattr.mtime, &ts);
                        mask |= CEPH_SETATTR_MTIME;
                        release |= CEPH_CAP_FILE_SHARED |
                                   CEPH_CAP_FILE_RD | CEPH_CAP_FILE_WR;
@@ -2082,9 +2095,9 @@ int __ceph_setattr(struct inode *inode, struct iattr *attr)
        if (ia_valid & ATTR_CTIME) {
                bool only = (ia_valid & (ATTR_SIZE|ATTR_MTIME|ATTR_ATIME|
                                         ATTR_MODE|ATTR_UID|ATTR_GID)) == 0;
-               dout("setattr %p ctime %ld.%ld -> %ld.%ld (%s)\n", inode,
-                    inode->i_ctime.tv_sec, inode->i_ctime.tv_nsec,
-                    attr->ia_ctime.tv_sec, attr->ia_ctime.tv_nsec,
+               dout("setattr %p ctime %lld.%ld -> %lld.%ld (%s)\n", inode,
+                    (long long)inode->i_ctime.tv_sec, inode->i_ctime.tv_nsec,
+                    (long long)attr->ia_ctime.tv_sec, attr->ia_ctime.tv_nsec,
                     only ? "ctime only" : "ignored");
                if (only) {
                        /*
@@ -2126,7 +2139,7 @@ int __ceph_setattr(struct inode *inode, struct iattr *attr)
                req->r_inode_drop = release;
                req->r_args.setattr.mask = cpu_to_le32(mask);
                req->r_num_caps = 1;
-               req->r_stamp = attr->ia_ctime;
+               req->r_stamp = timespec64_to_timespec(attr->ia_ctime);
                err = ceph_mdsc_do_request(mdsc, NULL, req);
        }
        dout("setattr %p result=%d (%s locally, %d remote)\n", inode, err,
@@ -2178,6 +2191,7 @@ int __ceph_do_getattr(struct inode *inode, struct page *locked_page,
        struct ceph_fs_client *fsc = ceph_sb_to_client(inode->i_sb);
        struct ceph_mds_client *mdsc = fsc->mdsc;
        struct ceph_mds_request *req;
+       int mode;
        int err;
 
        if (ceph_snap(inode) == CEPH_SNAPDIR) {
@@ -2190,7 +2204,8 @@ int __ceph_do_getattr(struct inode *inode, struct page *locked_page,
        if (!force && ceph_caps_issued_mask(ceph_inode(inode), mask, 1))
                return 0;
 
-       req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_GETATTR, USE_ANY_MDS);
+       mode = (mask & CEPH_STAT_RSTAT) ? USE_AUTH_MDS : USE_ANY_MDS;
+       req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_GETATTR, mode);
        if (IS_ERR(req))
                return PTR_ERR(req);
        req->r_inode = inode;
@@ -2261,6 +2276,14 @@ int ceph_getattr(const struct path *path, struct kstat *stat,
                                stat->size = ci->i_files + ci->i_subdirs;
                        stat->blocks = 0;
                        stat->blksize = 65536;
+                       /*
+                        * Some applications rely on the number of st_nlink
+                        * value on directories to be either 0 (if unlinked)
+                        * or 2 + number of subdirectories.
+                        */
+                       if (stat->nlink == 1)
+                               /* '.' + '..' + subdirs */
+                               stat->nlink = 1 + 1 + ci->i_subdirs;
                }
        }
        return err;
index cf8d24812cc00e0d01ebc991476298975498e2d9..dc8bc664a8716a5c946c70efa2dc5911cfb32962 100644 (file)
@@ -2958,12 +2958,15 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap,
                rec.v2.flock_len = (__force __le32)
                        ((ci->i_ceph_flags & CEPH_I_ERROR_FILELOCK) ? 0 : 1);
        } else {
+               struct timespec ts;
                rec.v1.cap_id = cpu_to_le64(cap->cap_id);
                rec.v1.wanted = cpu_to_le32(__ceph_caps_wanted(ci));
                rec.v1.issued = cpu_to_le32(cap->issued);
                rec.v1.size = cpu_to_le64(inode->i_size);
-               ceph_encode_timespec(&rec.v1.mtime, &inode->i_mtime);
-               ceph_encode_timespec(&rec.v1.atime, &inode->i_atime);
+               ts = timespec64_to_timespec(inode->i_mtime);
+               ceph_encode_timespec(&rec.v1.mtime, &ts);
+               ts = timespec64_to_timespec(inode->i_atime);
+               ceph_encode_timespec(&rec.v1.atime, &ts);
                rec.v1.snaprealm = cpu_to_le64(ci->i_snap_realm->ino);
                rec.v1.pathbase = cpu_to_le64(pathbase);
        }
index 041c27ea8de155a0002bdb5af25eb2fc5f8e6efa..af81555c14fd00a006ee360c95edf7335fc1f1fe 100644 (file)
@@ -594,9 +594,9 @@ int __ceph_finish_cap_snap(struct ceph_inode_info *ci,
 
        BUG_ON(capsnap->writing);
        capsnap->size = inode->i_size;
-       capsnap->mtime = inode->i_mtime;
-       capsnap->atime = inode->i_atime;
-       capsnap->ctime = inode->i_ctime;
+       capsnap->mtime = timespec64_to_timespec(inode->i_mtime);
+       capsnap->atime = timespec64_to_timespec(inode->i_atime);
+       capsnap->ctime = timespec64_to_timespec(inode->i_ctime);
        capsnap->time_warp_seq = ci->i_time_warp_seq;
        capsnap->truncate_size = ci->i_truncate_size;
        capsnap->truncate_seq = ci->i_truncate_seq;
index b33082e6878f1ca1ba8820716dafb1924d77855d..95a3b3ac9b6e251437d978d4fc7d513d2ea59507 100644 (file)
@@ -45,7 +45,7 @@ static void ceph_put_super(struct super_block *s)
 static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct ceph_fs_client *fsc = ceph_inode_to_client(d_inode(dentry));
-       struct ceph_monmap *monmap = fsc->client->monc.monmap;
+       struct ceph_mon_client *monc = &fsc->client->monc;
        struct ceph_statfs st;
        u64 fsid;
        int err;
@@ -58,7 +58,7 @@ static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf)
        }
 
        dout("statfs\n");
-       err = ceph_monc_do_statfs(&fsc->client->monc, data_pool, &st);
+       err = ceph_monc_do_statfs(monc, data_pool, &st);
        if (err < 0)
                return err;
 
@@ -94,8 +94,11 @@ static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_namelen = NAME_MAX;
 
        /* Must convert the fsid, for consistent values across arches */
-       fsid = le64_to_cpu(*(__le64 *)(&monmap->fsid)) ^
-              le64_to_cpu(*((__le64 *)&monmap->fsid + 1));
+       mutex_lock(&monc->mutex);
+       fsid = le64_to_cpu(*(__le64 *)(&monc->monmap->fsid)) ^
+              le64_to_cpu(*((__le64 *)&monc->monmap->fsid + 1));
+       mutex_unlock(&monc->mutex);
+
        buf->f_fsid.val[0] = fsid & 0xffffffff;
        buf->f_fsid.val[1] = fsid >> 32;
 
@@ -256,19 +259,19 @@ static int parse_fsopt_token(char *c, void *private)
                break;
                /* misc */
        case Opt_wsize:
-               if (intval < PAGE_SIZE || intval > CEPH_MAX_WRITE_SIZE)
+               if (intval < (int)PAGE_SIZE || intval > CEPH_MAX_WRITE_SIZE)
                        return -EINVAL;
                fsopt->wsize = ALIGN(intval, PAGE_SIZE);
                break;
        case Opt_rsize:
-               if (intval < PAGE_SIZE || intval > CEPH_MAX_READ_SIZE)
+               if (intval < (int)PAGE_SIZE || intval > CEPH_MAX_READ_SIZE)
                        return -EINVAL;
                fsopt->rsize = ALIGN(intval, PAGE_SIZE);
                break;
        case Opt_rasize:
                if (intval < 0)
                        return -EINVAL;
-               fsopt->rasize = ALIGN(intval + PAGE_SIZE - 1, PAGE_SIZE);
+               fsopt->rasize = ALIGN(intval, PAGE_SIZE);
                break;
        case Opt_caps_wanted_delay_min:
                if (intval < 1)
@@ -286,7 +289,7 @@ static int parse_fsopt_token(char *c, void *private)
                fsopt->max_readdir = intval;
                break;
        case Opt_readdir_max_bytes:
-               if (intval < PAGE_SIZE && intval != 0)
+               if (intval < (int)PAGE_SIZE && intval != 0)
                        return -EINVAL;
                fsopt->max_readdir_bytes = intval;
                break;
@@ -534,6 +537,8 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root)
                seq_puts(m, ",noasyncreaddir");
        if ((fsopt->flags & CEPH_MOUNT_OPT_DCACHE) == 0)
                seq_puts(m, ",nodcache");
+       if (fsopt->flags & CEPH_MOUNT_OPT_INO32)
+               seq_puts(m, ",ino32");
        if (fsopt->flags & CEPH_MOUNT_OPT_FSCACHE) {
                seq_show_option(m, "fsc", fsopt->fscache_uniq);
        }
@@ -551,7 +556,7 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root)
 
        if (fsopt->mds_namespace)
                seq_show_option(m, "mds_namespace", fsopt->mds_namespace);
-       if (fsopt->wsize)
+       if (fsopt->wsize != CEPH_MAX_WRITE_SIZE)
                seq_printf(m, ",wsize=%d", fsopt->wsize);
        if (fsopt->rsize != CEPH_MAX_READ_SIZE)
                seq_printf(m, ",rsize=%d", fsopt->rsize);
@@ -616,7 +621,9 @@ static struct ceph_fs_client *create_fs_client(struct ceph_mount_options *fsopt,
                err = PTR_ERR(fsc->client);
                goto fail;
        }
+
        fsc->client->extra_mon_dispatch = extra_mon_dispatch;
+       fsc->client->osdc.abort_on_full = true;
 
        if (!fsopt->mds_namespace) {
                ceph_monc_want_map(&fsc->client->monc, CEPH_SUB_MDSMAP,
@@ -674,6 +681,13 @@ fail:
        return ERR_PTR(err);
 }
 
+static void flush_fs_workqueues(struct ceph_fs_client *fsc)
+{
+       flush_workqueue(fsc->wb_wq);
+       flush_workqueue(fsc->pg_inv_wq);
+       flush_workqueue(fsc->trunc_wq);
+}
+
 static void destroy_fs_client(struct ceph_fs_client *fsc)
 {
        dout("destroy_fs_client %p\n", fsc);
@@ -793,6 +807,7 @@ static void ceph_umount_begin(struct super_block *sb)
        if (!fsc)
                return;
        fsc->mount_state = CEPH_MOUNT_SHUTDOWN;
+       ceph_osdc_abort_requests(&fsc->client->osdc, -EIO);
        ceph_mdsc_force_umount(fsc->mdsc);
        return;
 }
@@ -1088,6 +1103,8 @@ static void ceph_kill_sb(struct super_block *s)
        dout("kill_sb %p\n", s);
 
        ceph_mdsc_pre_umount(fsc->mdsc);
+       flush_fs_workqueues(fsc);
+
        generic_shutdown_super(s);
 
        fsc->client->extra_mon_dispatch = NULL;
index 315f7e63e7cca3b64eed882e8dc0c5fefbebe645..5bc8edb4c2a60ce82bfd03ac55b48c7f3003fde3 100644 (file)
@@ -50,10 +50,14 @@ struct ceph_vxattr {
        size_t name_size;       /* strlen(name) + 1 (for '\0') */
        size_t (*getxattr_cb)(struct ceph_inode_info *ci, char *val,
                              size_t size);
-       bool readonly, hidden;
        bool (*exists_cb)(struct ceph_inode_info *ci);
+       unsigned int flags;
 };
 
+#define VXATTR_FLAG_READONLY           (1<<0)
+#define VXATTR_FLAG_HIDDEN             (1<<1)
+#define VXATTR_FLAG_RSTAT              (1<<2)
+
 /* layouts */
 
 static bool ceph_vxattrcb_layout_exists(struct ceph_inode_info *ci)
@@ -262,32 +266,31 @@ static size_t ceph_vxattrcb_quota_max_files(struct ceph_inode_info *ci,
 #define CEPH_XATTR_NAME2(_type, _name, _name2) \
        XATTR_CEPH_PREFIX #_type "." #_name "." #_name2
 
-#define XATTR_NAME_CEPH(_type, _name)                                  \
+#define XATTR_NAME_CEPH(_type, _name, _flags)                          \
        {                                                               \
                .name = CEPH_XATTR_NAME(_type, _name),                  \
                .name_size = sizeof (CEPH_XATTR_NAME(_type, _name)), \
                .getxattr_cb = ceph_vxattrcb_ ## _type ## _ ## _name, \
-               .readonly = true,                               \
-               .hidden = false,                                \
-               .exists_cb = NULL,                      \
+               .exists_cb = NULL,                                      \
+               .flags = (VXATTR_FLAG_READONLY | _flags),               \
        }
+#define XATTR_RSTAT_FIELD(_type, _name)                        \
+       XATTR_NAME_CEPH(_type, _name, VXATTR_FLAG_RSTAT)
 #define XATTR_LAYOUT_FIELD(_type, _name, _field)                       \
        {                                                               \
                .name = CEPH_XATTR_NAME2(_type, _name, _field), \
                .name_size = sizeof (CEPH_XATTR_NAME2(_type, _name, _field)), \
                .getxattr_cb = ceph_vxattrcb_ ## _name ## _ ## _field, \
-               .readonly = false,                              \
-               .hidden = true,                 \
                .exists_cb = ceph_vxattrcb_layout_exists,       \
+               .flags = VXATTR_FLAG_HIDDEN,                    \
        }
 #define XATTR_QUOTA_FIELD(_type, _name)                                        \
        {                                                               \
                .name = CEPH_XATTR_NAME(_type, _name),                  \
                .name_size = sizeof(CEPH_XATTR_NAME(_type, _name)),     \
                .getxattr_cb = ceph_vxattrcb_ ## _type ## _ ## _name,   \
-               .readonly = false,                                      \
-               .hidden = true,                                         \
                .exists_cb = ceph_vxattrcb_quota_exists,                \
+               .flags = VXATTR_FLAG_HIDDEN,                            \
        }
 
 static struct ceph_vxattr ceph_dir_vxattrs[] = {
@@ -295,30 +298,28 @@ static struct ceph_vxattr ceph_dir_vxattrs[] = {
                .name = "ceph.dir.layout",
                .name_size = sizeof("ceph.dir.layout"),
                .getxattr_cb = ceph_vxattrcb_layout,
-               .readonly = false,
-               .hidden = true,
                .exists_cb = ceph_vxattrcb_layout_exists,
+               .flags = VXATTR_FLAG_HIDDEN,
        },
        XATTR_LAYOUT_FIELD(dir, layout, stripe_unit),
        XATTR_LAYOUT_FIELD(dir, layout, stripe_count),
        XATTR_LAYOUT_FIELD(dir, layout, object_size),
        XATTR_LAYOUT_FIELD(dir, layout, pool),
        XATTR_LAYOUT_FIELD(dir, layout, pool_namespace),
-       XATTR_NAME_CEPH(dir, entries),
-       XATTR_NAME_CEPH(dir, files),
-       XATTR_NAME_CEPH(dir, subdirs),
-       XATTR_NAME_CEPH(dir, rentries),
-       XATTR_NAME_CEPH(dir, rfiles),
-       XATTR_NAME_CEPH(dir, rsubdirs),
-       XATTR_NAME_CEPH(dir, rbytes),
-       XATTR_NAME_CEPH(dir, rctime),
+       XATTR_NAME_CEPH(dir, entries, 0),
+       XATTR_NAME_CEPH(dir, files, 0),
+       XATTR_NAME_CEPH(dir, subdirs, 0),
+       XATTR_RSTAT_FIELD(dir, rentries),
+       XATTR_RSTAT_FIELD(dir, rfiles),
+       XATTR_RSTAT_FIELD(dir, rsubdirs),
+       XATTR_RSTAT_FIELD(dir, rbytes),
+       XATTR_RSTAT_FIELD(dir, rctime),
        {
                .name = "ceph.quota",
                .name_size = sizeof("ceph.quota"),
                .getxattr_cb = ceph_vxattrcb_quota,
-               .readonly = false,
-               .hidden = true,
                .exists_cb = ceph_vxattrcb_quota_exists,
+               .flags = VXATTR_FLAG_HIDDEN,
        },
        XATTR_QUOTA_FIELD(quota, max_bytes),
        XATTR_QUOTA_FIELD(quota, max_files),
@@ -333,9 +334,8 @@ static struct ceph_vxattr ceph_file_vxattrs[] = {
                .name = "ceph.file.layout",
                .name_size = sizeof("ceph.file.layout"),
                .getxattr_cb = ceph_vxattrcb_layout,
-               .readonly = false,
-               .hidden = true,
                .exists_cb = ceph_vxattrcb_layout_exists,
+               .flags = VXATTR_FLAG_HIDDEN,
        },
        XATTR_LAYOUT_FIELD(file, layout, stripe_unit),
        XATTR_LAYOUT_FIELD(file, layout, stripe_count),
@@ -374,9 +374,10 @@ static size_t __init vxattrs_name_size(struct ceph_vxattr *vxattrs)
        struct ceph_vxattr *vxattr;
        size_t size = 0;
 
-       for (vxattr = vxattrs; vxattr->name; vxattr++)
-               if (!vxattr->hidden)
+       for (vxattr = vxattrs; vxattr->name; vxattr++) {
+               if (!(vxattr->flags & VXATTR_FLAG_HIDDEN))
                        size += vxattr->name_size;
+       }
 
        return size;
 }
@@ -809,7 +810,10 @@ ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value,
        /* let's see if a virtual xattr was requested */
        vxattr = ceph_match_vxattr(inode, name);
        if (vxattr) {
-               err = ceph_do_getattr(inode, 0, true);
+               int mask = 0;
+               if (vxattr->flags & VXATTR_FLAG_RSTAT)
+                       mask |= CEPH_STAT_RSTAT;
+               err = ceph_do_getattr(inode, mask, true);
                if (err)
                        return err;
                err = -ENODATA;
@@ -919,7 +923,7 @@ ssize_t ceph_listxattr(struct dentry *dentry, char *names, size_t size)
        err = namelen;
        if (vxattrs) {
                for (i = 0; vxattrs[i].name; i++) {
-                       if (!vxattrs[i].hidden &&
+                       if (!(vxattrs[i].flags & VXATTR_FLAG_HIDDEN) &&
                            !(vxattrs[i].exists_cb &&
                              !vxattrs[i].exists_cb(ci))) {
                                len = sprintf(names, "%s", vxattrs[i].name);
@@ -1024,7 +1028,7 @@ int __ceph_setxattr(struct inode *inode, const char *name,
 
        vxattr = ceph_match_vxattr(inode, name);
        if (vxattr) {
-               if (vxattr->readonly)
+               if (vxattr->flags & VXATTR_FLAG_READONLY)
                        return -EOPNOTSUPP;
                if (value && !strncmp(vxattr->name, "ceph.quota", 10))
                        check_realm = true;
index edf5f40898bf07d53ac781ade9f6470c621c97e5..e1553d1e0e504335f186e55d11410478cf56459c 100644 (file)
@@ -128,8 +128,8 @@ fscache_checkaux cifs_fscache_inode_check_aux(void *cookie_netfs_data,
 
        memset(&auxdata, 0, sizeof(auxdata));
        auxdata.eof = cifsi->server_eof;
-       auxdata.last_write_time = cifsi->vfs_inode.i_mtime;
-       auxdata.last_change_time = cifsi->vfs_inode.i_ctime;
+       auxdata.last_write_time = timespec64_to_timespec(cifsi->vfs_inode.i_mtime);
+       auxdata.last_change_time = timespec64_to_timespec(cifsi->vfs_inode.i_ctime);
 
        if (memcmp(data, &auxdata, datalen) != 0)
                return FSCACHE_CHECKAUX_OBSOLETE;
index 116146022aa1fa82d334790f7e2d7ff46b052bf3..bfe99950581527bcc494acb6419436e6373aa923 100644 (file)
@@ -126,6 +126,25 @@ static void cifs_debug_tcon(struct seq_file *m, struct cifs_tcon *tcon)
        seq_putc(m, '\n');
 }
 
+static void
+cifs_dump_iface(struct seq_file *m, struct cifs_server_iface *iface)
+{
+       struct sockaddr_in *ipv4 = (struct sockaddr_in *)&iface->sockaddr;
+       struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)&iface->sockaddr;
+
+       seq_printf(m, "\t\tSpeed: %zu bps\n", iface->speed);
+       seq_puts(m, "\t\tCapabilities: ");
+       if (iface->rdma_capable)
+               seq_puts(m, "rdma ");
+       if (iface->rss_capable)
+               seq_puts(m, "rss ");
+       seq_putc(m, '\n');
+       if (iface->sockaddr.ss_family == AF_INET)
+               seq_printf(m, "\t\tIPv4: %pI4\n", &ipv4->sin_addr);
+       else if (iface->sockaddr.ss_family == AF_INET6)
+               seq_printf(m, "\t\tIPv6: %pI6\n", &ipv6->sin6_addr);
+}
+
 static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
 {
        struct list_head *tmp1, *tmp2, *tmp3;
@@ -312,6 +331,16 @@ skip_rdma:
                                              mid_entry->mid);
                        }
                        spin_unlock(&GlobalMid_Lock);
+
+                       spin_lock(&ses->iface_lock);
+                       if (ses->iface_count)
+                               seq_printf(m, "\n\tServer interfaces: %zu\n",
+                                          ses->iface_count);
+                       for (j = 0; j < ses->iface_count; j++) {
+                               seq_printf(m, "\t%d)\n", j);
+                               cifs_dump_iface(m, &ses->iface_list[j]);
+                       }
+                       spin_unlock(&ses->iface_lock);
                }
        }
        spin_unlock(&cifs_tcp_ses_lock);
index 937251cc61c046916228f150916c8c0a82a442a5..ee2a8ec70056f7451695cb75bfe1e00a95280ff0 100644 (file)
@@ -37,7 +37,6 @@
 #include <crypto/aead.h>
 
 int __cifs_calc_signature(struct smb_rqst *rqst,
-                       int start,
                        struct TCP_Server_Info *server, char *signature,
                        struct shash_desc *shash)
 {
@@ -45,16 +44,27 @@ int __cifs_calc_signature(struct smb_rqst *rqst,
        int rc;
        struct kvec *iov = rqst->rq_iov;
        int n_vec = rqst->rq_nvec;
+       int is_smb2 = server->vals->header_preamble_size == 0;
 
-       for (i = start; i < n_vec; i++) {
+       /* iov[0] is actual data and not the rfc1002 length for SMB2+ */
+       if (is_smb2) {
+               if (iov[0].iov_len <= 4)
+                       return -EIO;
+               i = 0;
+       } else {
+               if (n_vec < 2 || iov[0].iov_len != 4)
+                       return -EIO;
+               i = 1; /* skip rfc1002 length */
+       }
+
+       for (; i < n_vec; i++) {
                if (iov[i].iov_len == 0)
                        continue;
                if (iov[i].iov_base == NULL) {
                        cifs_dbg(VFS, "null iovec entry\n");
                        return -EIO;
                }
-               if (i == 1 && iov[1].iov_len <= 4)
-                       break; /* nothing to sign or corrupt header */
+
                rc = crypto_shash_update(shash,
                                         iov[i].iov_base, iov[i].iov_len);
                if (rc) {
@@ -118,7 +128,7 @@ static int cifs_calc_signature(struct smb_rqst *rqst,
                return rc;
        }
 
-       return __cifs_calc_signature(rqst, 1, server, signature,
+       return __cifs_calc_signature(rqst, server, signature,
                                     &server->secmech.sdescmd5->shash);
 }
 
index 1efa2e65bc1a8971f01811ac699a82cb7c1f1727..bd78da59a4fdcd7e84ff9b57e01753ec64ca746d 100644 (file)
@@ -33,6 +33,9 @@
 
 #define CIFS_MAGIC_NUMBER 0xFF534D42      /* the first four bytes of SMB PDUs */
 
+#define CIFS_PORT 445
+#define RFC1001_PORT 139
+
 /*
  * The sizes of various internal tables and strings
  */
@@ -312,6 +315,10 @@ struct smb_version_operations {
        /* send echo request */
        int (*echo)(struct TCP_Server_Info *);
        /* create directory */
+       int (*posix_mkdir)(const unsigned int xid, struct inode *inode,
+                       umode_t mode, struct cifs_tcon *tcon,
+                       const char *full_path,
+                       struct cifs_sb_info *cifs_sb);
        int (*mkdir)(const unsigned int, struct cifs_tcon *, const char *,
                     struct cifs_sb_info *);
        /* set info on created directory */
@@ -838,6 +845,13 @@ static inline void cifs_set_net_ns(struct TCP_Server_Info *srv, struct net *net)
 
 #endif
 
+struct cifs_server_iface {
+       size_t speed;
+       unsigned int rdma_capable : 1;
+       unsigned int rss_capable : 1;
+       struct sockaddr_storage sockaddr;
+};
+
 /*
  * Session structure.  One of these for each uid session with a particular host
  */
@@ -875,6 +889,20 @@ struct cifs_ses {
 #ifdef CONFIG_CIFS_SMB311
        __u8 preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE];
 #endif /* 3.1.1 */
+
+       /*
+        * Network interfaces available on the server this session is
+        * connected to.
+        *
+        * Other channels can be opened by connecting and binding this
+        * session to interfaces from this list.
+        *
+        * iface_lock should be taken when accessing any of these fields
+        */
+       spinlock_t iface_lock;
+       struct cifs_server_iface *iface_list;
+       size_t iface_count;
+       unsigned long iface_last_update; /* jiffies */
 };
 
 static inline bool
@@ -883,6 +911,14 @@ cap_unix(struct cifs_ses *ses)
        return ses->server->vals->cap_unix & ses->capabilities;
 }
 
+struct cached_fid {
+       bool is_valid:1;        /* Do we have a useable root fid */
+       struct cifs_fid *fid;
+       struct mutex fid_mutex;
+       struct cifs_tcon *tcon;
+       struct work_struct lease_break;
+};
+
 /*
  * there is one of these for each connection to a resource on a particular
  * session
@@ -987,9 +1023,7 @@ struct cifs_tcon {
        struct fscache_cookie *fscache; /* cookie for share */
 #endif
        struct list_head pending_opens; /* list of incomplete opens */
-       bool valid_root_fid:1;  /* Do we have a useable root fid */
-       struct mutex prfid_mutex; /* prevents reopen race after dead ses*/
-       struct cifs_fid *prfid; /* handle to the directory at top of share */
+       struct cached_fid crfid; /* Cached root fid */
        /* BB add field for back pointer to sb struct(s)? */
 };
 
index 4e0d183c3d1016918d9934420af6e626d128d077..03018be1728333905ad0ae4eb6dde79aea5102fc 100644 (file)
@@ -112,10 +112,6 @@ extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *,
                        struct kvec *, int /* nvec to send */,
                        int * /* type of buf returned */, const int flags,
                        struct kvec * /* resp vec */);
-extern int smb2_send_recv(const unsigned int xid, struct cifs_ses *pses,
-                         struct kvec *pkvec, int nvec_to_send,
-                         int *pbuftype, const int flags,
-                         struct kvec *presp);
 extern int SendReceiveBlockingLock(const unsigned int xid,
                        struct cifs_tcon *ptcon,
                        struct smb_hdr *in_buf ,
@@ -544,7 +540,7 @@ int cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
                           struct cifs_sb_info *cifs_sb,
                           const unsigned char *path, char *pbuf,
                           unsigned int *pbytes_written);
-int __cifs_calc_signature(struct smb_rqst *rqst, int start,
+int __cifs_calc_signature(struct smb_rqst *rqst,
                        struct TCP_Server_Info *server, char *signature,
                        struct shash_desc *shash);
 enum securityEnum cifs_select_sectype(struct TCP_Server_Info *,
@@ -552,6 +548,7 @@ enum securityEnum cifs_select_sectype(struct TCP_Server_Info *,
 struct cifs_aio_ctx *cifs_aio_ctx_alloc(void);
 void cifs_aio_ctx_release(struct kref *refcount);
 int setup_aio_ctx_iter(struct cifs_aio_ctx *ctx, struct iov_iter *iter, int rw);
+void smb2_cached_lease_break(struct work_struct *work);
 
 int cifs_alloc_hash(const char *name, struct crypto_shash **shash,
                    struct sdesc **sdesc);
index 42329b25877db2b3de349b0ce5723f70bebad92b..d352da325de34d3c11b6dbb8c6579f6e4f0a216f 100644 (file)
@@ -107,10 +107,10 @@ cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
        }
        spin_unlock(&tcon->open_file_lock);
 
-       mutex_lock(&tcon->prfid_mutex);
-       tcon->valid_root_fid = false;
-       memset(tcon->prfid, 0, sizeof(struct cifs_fid));
-       mutex_unlock(&tcon->prfid_mutex);
+       mutex_lock(&tcon->crfid.fid_mutex);
+       tcon->crfid.is_valid = false;
+       memset(tcon->crfid.fid, 0, sizeof(struct cifs_fid));
+       mutex_unlock(&tcon->crfid.fid_mutex);
 
        /*
         * BB Add call to invalidate_inodes(sb) for all superblocks mounted
index 96645a7d8f27144a885863578d33e2b757afeec6..a57da1b88bdf5b5342b326ea06eb8686b2882cbe 100644 (file)
@@ -57,9 +57,6 @@
 #include "smb2proto.h"
 #include "smbdirect.h"
 
-#define CIFS_PORT 445
-#define RFC1001_PORT 139
-
 extern mempool_t *cifs_req_poolp;
 extern bool disable_legacy_dialects;
 
@@ -3029,8 +3026,11 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
 
 #ifdef CONFIG_CIFS_SMB311
        if ((volume_info->linux_ext) && (ses->server->posix_ext_supported)) {
-               if (ses->server->vals->protocol_id == SMB311_PROT_ID)
+               if (ses->server->vals->protocol_id == SMB311_PROT_ID) {
                        tcon->posix_extensions = true;
+                       printk_once(KERN_WARNING
+                               "SMB3.11 POSIX Extensions are experimental\n");
+               }
        }
 #endif /* 311 */
 
index 25d3f66b2d50899186a4b4e4f78dd7f66fe2035d..85145a7630216b0941d71d8cc5b9bb8d6f409af1 100644 (file)
@@ -129,8 +129,8 @@ static void cifs_fscache_acquire_inode_cookie(struct cifsInodeInfo *cifsi,
 
        memset(&auxdata, 0, sizeof(auxdata));
        auxdata.eof = cifsi->server_eof;
-       auxdata.last_write_time = cifsi->vfs_inode.i_mtime;
-       auxdata.last_change_time = cifsi->vfs_inode.i_ctime;
+       auxdata.last_write_time = timespec64_to_timespec(cifsi->vfs_inode.i_mtime);
+       auxdata.last_change_time = timespec64_to_timespec(cifsi->vfs_inode.i_ctime);
 
        cifsi->fscache =
                fscache_acquire_cookie(tcon->fscache,
@@ -166,8 +166,8 @@ void cifs_fscache_release_inode_cookie(struct inode *inode)
        if (cifsi->fscache) {
                memset(&auxdata, 0, sizeof(auxdata));
                auxdata.eof = cifsi->server_eof;
-               auxdata.last_write_time = cifsi->vfs_inode.i_mtime;
-               auxdata.last_change_time = cifsi->vfs_inode.i_ctime;
+               auxdata.last_write_time = timespec64_to_timespec(cifsi->vfs_inode.i_mtime);
+               auxdata.last_change_time = timespec64_to_timespec(cifsi->vfs_inode.i_ctime);
 
                cifs_dbg(FYI, "%s: (0x%p)\n", __func__, cifsi->fscache);
                fscache_relinquish_cookie(cifsi->fscache, &auxdata, false);
index a94071c7b4089076d35a82ae38c24bbe62a50a91..a2cfb33e85c1f8cb25a2d32a52bb5d60c93b79f1 100644 (file)
@@ -95,6 +95,7 @@ static void
 cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr)
 {
        struct cifsInodeInfo *cifs_i = CIFS_I(inode);
+       struct timespec ts;
 
        cifs_dbg(FYI, "%s: revalidating inode %llu\n",
                 __func__, cifs_i->uniqueid);
@@ -113,7 +114,8 @@ cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr)
        }
 
         /* revalidate if mtime or size have changed */
-       if (timespec_equal(&inode->i_mtime, &fattr->cf_mtime) &&
+       ts = timespec64_to_timespec(inode->i_mtime);
+       if (timespec_equal(&ts, &fattr->cf_mtime) &&
            cifs_i->server_eof == fattr->cf_eof) {
                cifs_dbg(FYI, "%s: inode %llu is unchanged\n",
                         __func__, cifs_i->uniqueid);
@@ -162,9 +164,9 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
        cifs_revalidate_cache(inode, fattr);
 
        spin_lock(&inode->i_lock);
-       inode->i_atime = fattr->cf_atime;
-       inode->i_mtime = fattr->cf_mtime;
-       inode->i_ctime = fattr->cf_ctime;
+       inode->i_atime = timespec_to_timespec64(fattr->cf_atime);
+       inode->i_mtime = timespec_to_timespec64(fattr->cf_mtime);
+       inode->i_ctime = timespec_to_timespec64(fattr->cf_ctime);
        inode->i_rdev = fattr->cf_rdev;
        cifs_nlink_fattr_to_inode(inode, fattr);
        inode->i_uid = fattr->cf_uid;
@@ -1123,14 +1125,14 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid,
        if (attrs->ia_valid & ATTR_ATIME) {
                set_time = true;
                info_buf.LastAccessTime =
-                       cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
+                       cpu_to_le64(cifs_UnixTimeToNT(timespec64_to_timespec(attrs->ia_atime)));
        } else
                info_buf.LastAccessTime = 0;
 
        if (attrs->ia_valid & ATTR_MTIME) {
                set_time = true;
                info_buf.LastWriteTime =
-                   cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
+                   cpu_to_le64(cifs_UnixTimeToNT(timespec64_to_timespec(attrs->ia_mtime)));
        } else
                info_buf.LastWriteTime = 0;
 
@@ -1143,7 +1145,7 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid,
        if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
                cifs_dbg(FYI, "CIFS - CTIME changed\n");
                info_buf.ChangeTime =
-                   cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
+                   cpu_to_le64(cifs_UnixTimeToNT(timespec64_to_timespec(attrs->ia_ctime)));
        } else
                info_buf.ChangeTime = 0;
 
@@ -1573,6 +1575,17 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
                goto mkdir_out;
        }
 
+       server = tcon->ses->server;
+
+#ifdef CONFIG_CIFS_SMB311
+       if ((server->ops->posix_mkdir) && (tcon->posix_extensions)) {
+               rc = server->ops->posix_mkdir(xid, inode, mode, tcon, full_path,
+                                             cifs_sb);
+               d_drop(direntry); /* for time being always refresh inode info */
+               goto mkdir_out;
+       }
+#endif /* SMB311 */
+
        if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
                                le64_to_cpu(tcon->fsUnixInfo.Capability))) {
                rc = cifs_posix_mkdir(inode, direntry, mode, full_path, cifs_sb,
@@ -1581,8 +1594,6 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
                        goto mkdir_out;
        }
 
-       server = tcon->ses->server;
-
        if (!server->ops->mkdir) {
                rc = -ENOSYS;
                goto mkdir_out;
@@ -2060,8 +2071,8 @@ int cifs_getattr(const struct path *path, struct kstat *stat,
        /* old CIFS Unix Extensions doesn't return create time */
        if (CIFS_I(inode)->createtime) {
                stat->result_mask |= STATX_BTIME;
-               stat->btime =
-                     cifs_NTtimeToUnix(cpu_to_le64(CIFS_I(inode)->createtime));
+               stat->btime = timespec_to_timespec64(
+                     cifs_NTtimeToUnix(cpu_to_le64(CIFS_I(inode)->createtime)));
        }
 
        stat->attributes_mask |= (STATX_ATTR_COMPRESSED | STATX_ATTR_ENCRYPTED);
@@ -2267,17 +2278,17 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
                args->gid = INVALID_GID; /* no change */
 
        if (attrs->ia_valid & ATTR_ATIME)
-               args->atime = cifs_UnixTimeToNT(attrs->ia_atime);
+               args->atime = cifs_UnixTimeToNT(timespec64_to_timespec(attrs->ia_atime));
        else
                args->atime = NO_CHANGE_64;
 
        if (attrs->ia_valid & ATTR_MTIME)
-               args->mtime = cifs_UnixTimeToNT(attrs->ia_mtime);
+               args->mtime = cifs_UnixTimeToNT(timespec64_to_timespec(attrs->ia_mtime));
        else
                args->mtime = NO_CHANGE_64;
 
        if (attrs->ia_valid & ATTR_CTIME)
-               args->ctime = cifs_UnixTimeToNT(attrs->ia_ctime);
+               args->ctime = cifs_UnixTimeToNT(timespec64_to_timespec(attrs->ia_ctime));
        else
                args->ctime = NO_CHANGE_64;
 
index af29ade195c002c0323d855edb391a155f1620f7..53e8362cbc4a953218d3fbd50f1c7133e5435cc9 100644 (file)
@@ -82,6 +82,7 @@ sesInfoAlloc(void)
                INIT_LIST_HEAD(&ret_buf->smb_ses_list);
                INIT_LIST_HEAD(&ret_buf->tcon_list);
                mutex_init(&ret_buf->session_mutex);
+               spin_lock_init(&ret_buf->iface_lock);
        }
        return ret_buf;
 }
@@ -102,6 +103,7 @@ sesInfoFree(struct cifs_ses *buf_to_free)
        kfree(buf_to_free->user_name);
        kfree(buf_to_free->domainName);
        kzfree(buf_to_free->auth_key.response);
+       kfree(buf_to_free->iface_list);
        kzfree(buf_to_free);
 }
 
@@ -117,8 +119,9 @@ tconInfoAlloc(void)
                INIT_LIST_HEAD(&ret_buf->openFileList);
                INIT_LIST_HEAD(&ret_buf->tcon_list);
                spin_lock_init(&ret_buf->open_file_lock);
-               mutex_init(&ret_buf->prfid_mutex);
-               ret_buf->prfid = kzalloc(sizeof(struct cifs_fid), GFP_KERNEL);
+               mutex_init(&ret_buf->crfid.fid_mutex);
+               ret_buf->crfid.fid = kzalloc(sizeof(struct cifs_fid),
+                                            GFP_KERNEL);
 #ifdef CONFIG_CIFS_STATS
                spin_lock_init(&ret_buf->stat_lock);
 #endif
@@ -136,7 +139,7 @@ tconInfoFree(struct cifs_tcon *buf_to_free)
        atomic_dec(&tconInfoAllocCount);
        kfree(buf_to_free->nativeFileSystem);
        kzfree(buf_to_free->password);
-       kfree(buf_to_free->prfid);
+       kfree(buf_to_free->crfid.fid);
        kfree(buf_to_free);
 }
 
index e2bec47c684580089a70e7914ec71d2f523da3e3..3ff7cec2da81141f67482c57ab03de52aed855ba 100644 (file)
@@ -454,7 +454,8 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb)
 #ifdef CONFIG_CIFS_SMB311
        /* SMB311 POSIX extensions paths do not include leading slash */
        else if (cifs_sb_master_tlink(cifs_sb) &&
-                cifs_sb_master_tcon(cifs_sb)->posix_extensions) {
+                cifs_sb_master_tcon(cifs_sb)->posix_extensions &&
+                (from[0] == '/')) {
                start_of_path = from + 1;
        }
 #endif /* 311 */
@@ -492,10 +493,11 @@ cifs_ses_oplock_break(struct work_struct *work)
 {
        struct smb2_lease_break_work *lw = container_of(work,
                                struct smb2_lease_break_work, lease_break);
-       int rc;
+       int rc = 0;
 
        rc = SMB2_lease_break(0, tlink_tcon(lw->tlink), lw->lease_key,
                              lw->lease_state);
+
        cifs_dbg(FYI, "Lease release rc %d\n", rc);
        cifs_put_tlink(lw->tlink);
        kfree(lw);
@@ -561,6 +563,7 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp,
 
                open->oplock = lease_state;
        }
+
        return found;
 }
 
@@ -603,6 +606,18 @@ smb2_is_valid_lease_break(char *buffer)
                                        return true;
                                }
                                spin_unlock(&tcon->open_file_lock);
+
+                               if (tcon->crfid.is_valid &&
+                                   !memcmp(rsp->LeaseKey,
+                                           tcon->crfid.fid->lease_key,
+                                           SMB2_LEASE_KEY_SIZE)) {
+                                       INIT_WORK(&tcon->crfid.lease_break,
+                                                 smb2_cached_lease_break);
+                                       queue_work(cifsiod_wq,
+                                                  &tcon->crfid.lease_break);
+                                       spin_unlock(&cifs_tcp_ses_lock);
+                                       return true;
+                               }
                        }
                }
        }
index b15f5957d64591f0af611670088dd4dd8439fb43..0356b5559c711ffa20d2710425b823106b0a0dc5 100644 (file)
@@ -294,34 +294,191 @@ smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
        return rsize;
 }
 
-#ifdef CONFIG_CIFS_STATS2
+
+static int
+parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
+                       size_t buf_len,
+                       struct cifs_server_iface **iface_list,
+                       size_t *iface_count)
+{
+       struct network_interface_info_ioctl_rsp *p;
+       struct sockaddr_in *addr4;
+       struct sockaddr_in6 *addr6;
+       struct iface_info_ipv4 *p4;
+       struct iface_info_ipv6 *p6;
+       struct cifs_server_iface *info;
+       ssize_t bytes_left;
+       size_t next = 0;
+       int nb_iface = 0;
+       int rc = 0;
+
+       *iface_list = NULL;
+       *iface_count = 0;
+
+       /*
+        * Fist pass: count and sanity check
+        */
+
+       bytes_left = buf_len;
+       p = buf;
+       while (bytes_left >= sizeof(*p)) {
+               nb_iface++;
+               next = le32_to_cpu(p->Next);
+               if (!next) {
+                       bytes_left -= sizeof(*p);
+                       break;
+               }
+               p = (struct network_interface_info_ioctl_rsp *)((u8 *)p+next);
+               bytes_left -= next;
+       }
+
+       if (!nb_iface) {
+               cifs_dbg(VFS, "%s: malformed interface info\n", __func__);
+               rc = -EINVAL;
+               goto out;
+       }
+
+       if (bytes_left || p->Next)
+               cifs_dbg(VFS, "%s: incomplete interface info\n", __func__);
+
+
+       /*
+        * Second pass: extract info to internal structure
+        */
+
+       *iface_list = kcalloc(nb_iface, sizeof(**iface_list), GFP_KERNEL);
+       if (!*iface_list) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       info = *iface_list;
+       bytes_left = buf_len;
+       p = buf;
+       while (bytes_left >= sizeof(*p)) {
+               info->speed = le64_to_cpu(p->LinkSpeed);
+               info->rdma_capable = le32_to_cpu(p->Capability & RDMA_CAPABLE);
+               info->rss_capable = le32_to_cpu(p->Capability & RSS_CAPABLE);
+
+               cifs_dbg(FYI, "%s: adding iface %zu\n", __func__, *iface_count);
+               cifs_dbg(FYI, "%s: speed %zu bps\n", __func__, info->speed);
+               cifs_dbg(FYI, "%s: capabilities 0x%08x\n", __func__,
+                        le32_to_cpu(p->Capability));
+
+               switch (p->Family) {
+               /*
+                * The kernel and wire socket structures have the same
+                * layout and use network byte order but make the
+                * conversion explicit in case either one changes.
+                */
+               case INTERNETWORK:
+                       addr4 = (struct sockaddr_in *)&info->sockaddr;
+                       p4 = (struct iface_info_ipv4 *)p->Buffer;
+                       addr4->sin_family = AF_INET;
+                       memcpy(&addr4->sin_addr, &p4->IPv4Address, 4);
+
+                       /* [MS-SMB2] 2.2.32.5.1.1 Clients MUST ignore these */
+                       addr4->sin_port = cpu_to_be16(CIFS_PORT);
+
+                       cifs_dbg(FYI, "%s: ipv4 %pI4\n", __func__,
+                                &addr4->sin_addr);
+                       break;
+               case INTERNETWORKV6:
+                       addr6 = (struct sockaddr_in6 *)&info->sockaddr;
+                       p6 = (struct iface_info_ipv6 *)p->Buffer;
+                       addr6->sin6_family = AF_INET6;
+                       memcpy(&addr6->sin6_addr, &p6->IPv6Address, 16);
+
+                       /* [MS-SMB2] 2.2.32.5.1.2 Clients MUST ignore these */
+                       addr6->sin6_flowinfo = 0;
+                       addr6->sin6_scope_id = 0;
+                       addr6->sin6_port = cpu_to_be16(CIFS_PORT);
+
+                       cifs_dbg(FYI, "%s: ipv6 %pI6\n", __func__,
+                                &addr6->sin6_addr);
+                       break;
+               default:
+                       cifs_dbg(VFS,
+                                "%s: skipping unsupported socket family\n",
+                                __func__);
+                       goto next_iface;
+               }
+
+               (*iface_count)++;
+               info++;
+next_iface:
+               next = le32_to_cpu(p->Next);
+               if (!next)
+                       break;
+               p = (struct network_interface_info_ioctl_rsp *)((u8 *)p+next);
+               bytes_left -= next;
+       }
+
+       if (!*iface_count) {
+               rc = -EINVAL;
+               goto out;
+       }
+
+out:
+       if (rc) {
+               kfree(*iface_list);
+               *iface_count = 0;
+               *iface_list = NULL;
+       }
+       return rc;
+}
+
+
 static int
 SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon)
 {
        int rc;
        unsigned int ret_data_len = 0;
-       struct network_interface_info_ioctl_rsp *out_buf;
+       struct network_interface_info_ioctl_rsp *out_buf = NULL;
+       struct cifs_server_iface *iface_list;
+       size_t iface_count;
+       struct cifs_ses *ses = tcon->ses;
 
        rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
                        FSCTL_QUERY_NETWORK_INTERFACE_INFO, true /* is_fsctl */,
                        NULL /* no data input */, 0 /* no data input */,
                        (char **)&out_buf, &ret_data_len);
-       if (rc != 0)
+       if (rc != 0) {
                cifs_dbg(VFS, "error %d on ioctl to get interface list\n", rc);
-       else if (ret_data_len < sizeof(struct network_interface_info_ioctl_rsp)) {
-               cifs_dbg(VFS, "server returned bad net interface info buf\n");
-               rc = -EINVAL;
-       } else {
-               /* Dump info on first interface */
-               cifs_dbg(FYI, "Adapter Capability 0x%x\t",
-                       le32_to_cpu(out_buf->Capability));
-               cifs_dbg(FYI, "Link Speed %lld\n",
-                       le64_to_cpu(out_buf->LinkSpeed));
+               goto out;
        }
+
+       rc = parse_server_interfaces(out_buf, ret_data_len,
+                                    &iface_list, &iface_count);
+       if (rc)
+               goto out;
+
+       spin_lock(&ses->iface_lock);
+       kfree(ses->iface_list);
+       ses->iface_list = iface_list;
+       ses->iface_count = iface_count;
+       ses->iface_last_update = jiffies;
+       spin_unlock(&ses->iface_lock);
+
+out:
        kfree(out_buf);
        return rc;
 }
-#endif /* STATS2 */
+
+void
+smb2_cached_lease_break(struct work_struct *work)
+{
+       struct cached_fid *cfid = container_of(work,
+                               struct cached_fid, lease_break);
+       mutex_lock(&cfid->fid_mutex);
+       if (cfid->is_valid) {
+               cifs_dbg(FYI, "clear cached root file handle\n");
+               SMB2_close(0, cfid->tcon, cfid->fid->persistent_fid,
+                          cfid->fid->volatile_fid);
+               cfid->is_valid = false;
+       }
+       mutex_unlock(&cfid->fid_mutex);
+}
 
 /*
  * Open the directory at the root of a share
@@ -331,13 +488,13 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
        struct cifs_open_parms oparams;
        int rc;
        __le16 srch_path = 0; /* Null - since an open of top of share */
-       u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
+       u8 oplock = SMB2_OPLOCK_LEVEL_II;
 
-       mutex_lock(&tcon->prfid_mutex);
-       if (tcon->valid_root_fid) {
+       mutex_lock(&tcon->crfid.fid_mutex);
+       if (tcon->crfid.is_valid) {
                cifs_dbg(FYI, "found a cached root file handle\n");
-               memcpy(pfid, tcon->prfid, sizeof(struct cifs_fid));
-               mutex_unlock(&tcon->prfid_mutex);
+               memcpy(pfid, tcon->crfid.fid, sizeof(struct cifs_fid));
+               mutex_unlock(&tcon->crfid.fid_mutex);
                return 0;
        }
 
@@ -350,10 +507,11 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
 
        rc = SMB2_open(xid, &oparams, &srch_path, &oplock, NULL, NULL, NULL);
        if (rc == 0) {
-               memcpy(tcon->prfid, pfid, sizeof(struct cifs_fid));
-               tcon->valid_root_fid = true;
+               memcpy(tcon->crfid.fid, pfid, sizeof(struct cifs_fid));
+               tcon->crfid.tcon = tcon;
+               tcon->crfid.is_valid = true;
        }
-       mutex_unlock(&tcon->prfid_mutex);
+       mutex_unlock(&tcon->crfid.fid_mutex);
        return rc;
 }
 
@@ -383,9 +541,7 @@ smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon)
        if (rc)
                return;
 
-#ifdef CONFIG_CIFS_STATS2
        SMB3_request_interfaces(xid, tcon);
-#endif /* STATS2 */
 
        SMB2_QFS_attr(xid, tcon, fid.persistent_fid, fid.volatile_fid,
                        FS_ATTRIBUTE_INFORMATION);
@@ -436,7 +592,7 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
        struct cifs_open_parms oparms;
        struct cifs_fid fid;
 
-       if ((*full_path == 0) && tcon->valid_root_fid)
+       if ((*full_path == 0) && tcon->crfid.is_valid)
                return 0;
 
        utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
@@ -2151,7 +2307,7 @@ fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, unsigned int orig_len,
                   struct smb_rqst *old_rq)
 {
        struct smb2_sync_hdr *shdr =
-                       (struct smb2_sync_hdr *)old_rq->rq_iov[1].iov_base;
+                       (struct smb2_sync_hdr *)old_rq->rq_iov[0].iov_base;
 
        memset(tr_hdr, 0, sizeof(struct smb2_transform_hdr));
        tr_hdr->ProtocolId = SMB2_TRANSFORM_PROTO_NUM;
@@ -2171,14 +2327,13 @@ static inline void smb2_sg_set_buf(struct scatterlist *sg, const void *buf,
 }
 
 /* Assumes:
- * rqst->rq_iov[0]  is rfc1002 length
- * rqst->rq_iov[1]  is tranform header
- * rqst->rq_iov[2+] data to be encrypted/decrypted
+ * rqst->rq_iov[0]  is transform header
+ * rqst->rq_iov[1+] data to be encrypted/decrypted
  */
 static struct scatterlist *
 init_sg(struct smb_rqst *rqst, u8 *sign)
 {
-       unsigned int sg_len = rqst->rq_nvec + rqst->rq_npages;
+       unsigned int sg_len = rqst->rq_nvec + rqst->rq_npages + 1;
        unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
        struct scatterlist *sg;
        unsigned int i;
@@ -2189,10 +2344,10 @@ init_sg(struct smb_rqst *rqst, u8 *sign)
                return NULL;
 
        sg_init_table(sg, sg_len);
-       smb2_sg_set_buf(&sg[0], rqst->rq_iov[1].iov_base + 20, assoc_data_len);
-       for (i = 1; i < rqst->rq_nvec - 1; i++)
-               smb2_sg_set_buf(&sg[i], rqst->rq_iov[i+1].iov_base,
-                                               rqst->rq_iov[i+1].iov_len);
+       smb2_sg_set_buf(&sg[0], rqst->rq_iov[0].iov_base + 20, assoc_data_len);
+       for (i = 1; i < rqst->rq_nvec; i++)
+               smb2_sg_set_buf(&sg[i], rqst->rq_iov[i].iov_base,
+                                               rqst->rq_iov[i].iov_len);
        for (j = 0; i < sg_len - 1; i++, j++) {
                unsigned int len, offset;
 
@@ -2224,18 +2379,17 @@ smb2_get_enc_key(struct TCP_Server_Info *server, __u64 ses_id, int enc, u8 *key)
        return 1;
 }
 /*
- * Encrypt or decrypt @rqst message. @rqst has the following format:
- * iov[0] - rfc1002 length
- * iov[1] - transform header (associate data),
- * iov[2-N] and pages - data to encrypt.
- * On success return encrypted data in iov[2-N] and pages, leave iov[0-1]
+ * Encrypt or decrypt @rqst message. @rqst[0] has the following format:
+ * iov[0]   - transform header (associate data),
+ * iov[1-N] - SMB2 header and pages - data to encrypt.
+ * On success return encrypted data in iov[1-N] and pages, leave iov[0]
  * untouched.
  */
 static int
 crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc)
 {
        struct smb2_transform_hdr *tr_hdr =
-                       (struct smb2_transform_hdr *)rqst->rq_iov[1].iov_base;
+                       (struct smb2_transform_hdr *)rqst->rq_iov[0].iov_base;
        unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
        int rc = 0;
        struct scatterlist *sg;
@@ -2323,10 +2477,6 @@ free_req:
        return rc;
 }
 
-/*
- * This is called from smb_send_rqst. At this point we have the rfc1002
- * header as the first element in the vector.
- */
 static int
 smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq,
                       struct smb_rqst *old_rq)
@@ -2335,7 +2485,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq,
        struct page **pages;
        struct smb2_transform_hdr *tr_hdr;
        unsigned int npages = old_rq->rq_npages;
-       unsigned int orig_len = get_rfc1002_length(old_rq->rq_iov[0].iov_base);
+       unsigned int orig_len;
        int i;
        int rc = -ENOMEM;
 
@@ -2355,18 +2505,14 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq,
                        goto err_free_pages;
        }
 
-       /* Make space for one extra iov to hold the transform header */
        iov = kmalloc_array(old_rq->rq_nvec + 1, sizeof(struct kvec),
                            GFP_KERNEL);
        if (!iov)
                goto err_free_pages;
 
-       /* copy all iovs from the old except the 1st one (rfc1002 length) */
-       memcpy(&iov[2], &old_rq->rq_iov[1],
-                               sizeof(struct kvec) * (old_rq->rq_nvec - 1));
-       /* copy the rfc1002 iov */
-       iov[0].iov_base = old_rq->rq_iov[0].iov_base;
-       iov[0].iov_len  = old_rq->rq_iov[0].iov_len;
+       /* copy all iovs from the old */
+       memcpy(&iov[1], &old_rq->rq_iov[0],
+                               sizeof(struct kvec) * old_rq->rq_nvec);
 
        new_rq->rq_iov = iov;
        new_rq->rq_nvec = old_rq->rq_nvec + 1;
@@ -2375,14 +2521,12 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq,
        if (!tr_hdr)
                goto err_free_iov;
 
+       orig_len = smb2_rqst_len(old_rq, false);
+
        /* fill the 2nd iov with a transform header */
        fill_transform_hdr(tr_hdr, orig_len, old_rq);
-       new_rq->rq_iov[1].iov_base = tr_hdr;
-       new_rq->rq_iov[1].iov_len = sizeof(struct smb2_transform_hdr);
-
-       /* Update rfc1002 header */
-       inc_rfc1001_len(new_rq->rq_iov[0].iov_base,
-                       sizeof(struct smb2_transform_hdr));
+       new_rq->rq_iov[0].iov_base = tr_hdr;
+       new_rq->rq_iov[0].iov_len = sizeof(struct smb2_transform_hdr);
 
        /* copy pages form the old */
        for (i = 0; i < npages; i++) {
@@ -2426,7 +2570,7 @@ smb3_free_transform_rq(struct smb_rqst *rqst)
                put_page(rqst->rq_pages[i]);
        kfree(rqst->rq_pages);
        /* free transform header */
-       kfree(rqst->rq_iov[1].iov_base);
+       kfree(rqst->rq_iov[0].iov_base);
        kfree(rqst->rq_iov);
 }
 
@@ -2443,19 +2587,17 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf,
                 unsigned int buf_data_size, struct page **pages,
                 unsigned int npages, unsigned int page_data_size)
 {
-       struct kvec iov[3];
+       struct kvec iov[2];
        struct smb_rqst rqst = {NULL};
        int rc;
 
-       iov[0].iov_base = NULL;
-       iov[0].iov_len = 0;
-       iov[1].iov_base = buf;
-       iov[1].iov_len = sizeof(struct smb2_transform_hdr);
-       iov[2].iov_base = buf + sizeof(struct smb2_transform_hdr);
-       iov[2].iov_len = buf_data_size;
+       iov[0].iov_base = buf;
+       iov[0].iov_len = sizeof(struct smb2_transform_hdr);
+       iov[1].iov_base = buf + sizeof(struct smb2_transform_hdr);
+       iov[1].iov_len = buf_data_size;
 
        rqst.rq_iov = iov;
-       rqst.rq_nvec = 3;
+       rqst.rq_nvec = 2;
        rqst.rq_pages = pages;
        rqst.rq_npages = npages;
        rqst.rq_pagesz = PAGE_SIZE;
@@ -2467,7 +2609,7 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf,
        if (rc)
                return rc;
 
-       memmove(buf, iov[2].iov_base, buf_data_size);
+       memmove(buf, iov[1].iov_base, buf_data_size);
 
        server->total_read = buf_data_size + page_data_size;
 
@@ -3170,6 +3312,7 @@ struct smb_version_operations smb311_operations = {
        .set_compression = smb2_set_compression,
        .mkdir = smb2_mkdir,
        .mkdir_setinfo = smb2_mkdir_setinfo,
+       .posix_mkdir = smb311_posix_mkdir,
        .rmdir = smb2_rmdir,
        .unlink = smb2_unlink,
        .rename = smb2_rename_path,
index af032e1a3eac7adaf0570f5923e0ba6164e8ed6b..810b85787c9133909ef3731010b2bce604963b37 100644 (file)
@@ -602,6 +602,7 @@ static void assemble_neg_contexts(struct smb2_negotiate_req *req,
 int
 SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
 {
+       struct smb_rqst rqst;
        struct smb2_negotiate_req *req;
        struct smb2_negotiate_rsp *rsp;
        struct kvec iov[1];
@@ -673,7 +674,11 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
        iov[0].iov_base = (char *)req;
        iov[0].iov_len = total_len;
 
-       rc = smb2_send_recv(xid, ses, iov, 1, &resp_buftype, flags, &rsp_iov);
+       memset(&rqst, 0, sizeof(struct smb_rqst));
+       rqst.rq_iov = iov;
+       rqst.rq_nvec = 1;
+
+       rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
        cifs_small_buf_release(req);
        rsp = (struct smb2_negotiate_rsp *)rsp_iov.iov_base;
        /*
@@ -990,8 +995,9 @@ SMB2_sess_alloc_buffer(struct SMB2_sess_data *sess_data)
        req->PreviousSessionId = sess_data->previous_session;
 
        req->Flags = 0; /* MBZ */
-       /* to enable echos and oplocks */
-       req->sync_hdr.CreditRequest = cpu_to_le16(3);
+
+       /* enough to enable echos and oplocks and one max size write */
+       req->sync_hdr.CreditRequest = cpu_to_le16(130);
 
        /* only one of SMB2 signing flags may be set in SMB2 request */
        if (server->sign)
@@ -1027,6 +1033,7 @@ static int
 SMB2_sess_sendreceive(struct SMB2_sess_data *sess_data)
 {
        int rc;
+       struct smb_rqst rqst;
        struct smb2_sess_setup_req *req = sess_data->iov[0].iov_base;
        struct kvec rsp_iov = { NULL, 0 };
 
@@ -1035,10 +1042,13 @@ SMB2_sess_sendreceive(struct SMB2_sess_data *sess_data)
                cpu_to_le16(sizeof(struct smb2_sess_setup_req) - 1 /* pad */);
        req->SecurityBufferLength = cpu_to_le16(sess_data->iov[1].iov_len);
 
-       /* BB add code to build os and lm fields */
+       memset(&rqst, 0, sizeof(struct smb_rqst));
+       rqst.rq_iov = sess_data->iov;
+       rqst.rq_nvec = 2;
 
-       rc = smb2_send_recv(sess_data->xid, sess_data->ses,
-                           sess_data->iov, 2,
+       /* BB add code to build os and lm fields */
+       rc = cifs_send_recv(sess_data->xid, sess_data->ses,
+                           &rqst,
                            &sess_data->buf0_type,
                            CIFS_LOG_ERROR | CIFS_NEG_OP, &rsp_iov);
        cifs_small_buf_release(sess_data->iov[0].iov_base);
@@ -1376,6 +1386,7 @@ out:
 int
 SMB2_logoff(const unsigned int xid, struct cifs_ses *ses)
 {
+       struct smb_rqst rqst;
        struct smb2_logoff_req *req; /* response is also trivial struct */
        int rc = 0;
        struct TCP_Server_Info *server;
@@ -1413,7 +1424,11 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses)
        iov[0].iov_base = (char *)req;
        iov[0].iov_len = total_len;
 
-       rc = smb2_send_recv(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov);
+       memset(&rqst, 0, sizeof(struct smb_rqst));
+       rqst.rq_iov = iov;
+       rqst.rq_nvec = 1;
+
+       rc = cifs_send_recv(xid, ses, &rqst, &resp_buf_type, flags, &rsp_iov);
        cifs_small_buf_release(req);
        /*
         * No tcon so can't do
@@ -1443,6 +1458,7 @@ int
 SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
          struct cifs_tcon *tcon, const struct nls_table *cp)
 {
+       struct smb_rqst rqst;
        struct smb2_tree_connect_req *req;
        struct smb2_tree_connect_rsp *rsp = NULL;
        struct kvec iov[2];
@@ -1499,7 +1515,11 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
            !smb3_encryption_required(tcon))
                req->sync_hdr.Flags |= SMB2_FLAGS_SIGNED;
 
-       rc = smb2_send_recv(xid, ses, iov, 2, &resp_buftype, flags, &rsp_iov);
+       memset(&rqst, 0, sizeof(struct smb_rqst));
+       rqst.rq_iov = iov;
+       rqst.rq_nvec = 2;
+
+       rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
        cifs_small_buf_release(req);
        rsp = (struct smb2_tree_connect_rsp *)rsp_iov.iov_base;
 
@@ -1563,6 +1583,7 @@ tcon_error_exit:
 int
 SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
 {
+       struct smb_rqst rqst;
        struct smb2_tree_disconnect_req *req; /* response is trivial */
        int rc = 0;
        struct cifs_ses *ses = tcon->ses;
@@ -1593,7 +1614,11 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
        iov[0].iov_base = (char *)req;
        iov[0].iov_len = total_len;
 
-       rc = smb2_send_recv(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov);
+       memset(&rqst, 0, sizeof(struct smb_rqst));
+       rqst.rq_iov = iov;
+       rqst.rq_nvec = 1;
+
+       rc = cifs_send_recv(xid, ses, &rqst, &resp_buf_type, flags, &rsp_iov);
        cifs_small_buf_release(req);
        if (rc)
                cifs_stats_fail_inc(tcon, SMB2_TREE_DISCONNECT_HE);
@@ -1886,11 +1911,165 @@ alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len,
        return 0;
 }
 
+#ifdef CONFIG_CIFS_SMB311
+int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
+                              umode_t mode, struct cifs_tcon *tcon,
+                              const char *full_path,
+                              struct cifs_sb_info *cifs_sb)
+{
+       struct smb_rqst rqst;
+       struct smb2_create_req *req;
+       struct smb2_create_rsp *rsp;
+       struct TCP_Server_Info *server;
+       struct cifs_ses *ses = tcon->ses;
+       struct kvec iov[3]; /* make sure at least one for each open context */
+       struct kvec rsp_iov = {NULL, 0};
+       int resp_buftype;
+       int uni_path_len;
+       __le16 *copy_path = NULL;
+       int copy_size;
+       int rc = 0;
+       unsigned int n_iov = 2;
+       __u32 file_attributes = 0;
+       char *pc_buf = NULL;
+       int flags = 0;
+       unsigned int total_len;
+       __le16 *path = cifs_convert_path_to_utf16(full_path, cifs_sb);
+
+       if (!path)
+               return -ENOMEM;
+
+       cifs_dbg(FYI, "mkdir\n");
+
+       if (ses && (ses->server))
+               server = ses->server;
+       else
+               return -EIO;
+
+       rc = smb2_plain_req_init(SMB2_CREATE, tcon, (void **) &req, &total_len);
+
+       if (rc)
+               return rc;
+
+       if (smb3_encryption_required(tcon))
+               flags |= CIFS_TRANSFORM_REQ;
+
+
+       req->ImpersonationLevel = IL_IMPERSONATION;
+       req->DesiredAccess = cpu_to_le32(FILE_WRITE_ATTRIBUTES);
+       /* File attributes ignored on open (used in create though) */
+       req->FileAttributes = cpu_to_le32(file_attributes);
+       req->ShareAccess = FILE_SHARE_ALL_LE;
+       req->CreateDisposition = cpu_to_le32(FILE_CREATE);
+       req->CreateOptions = cpu_to_le32(CREATE_NOT_FILE);
+
+       iov[0].iov_base = (char *)req;
+       /* -1 since last byte is buf[0] which is sent below (path) */
+       iov[0].iov_len = total_len - 1;
+
+       req->NameOffset = cpu_to_le16(sizeof(struct smb2_create_req));
+
+       /* [MS-SMB2] 2.2.13 NameOffset:
+        * If SMB2_FLAGS_DFS_OPERATIONS is set in the Flags field of
+        * the SMB2 header, the file name includes a prefix that will
+        * be processed during DFS name normalization as specified in
+        * section 3.3.5.9. Otherwise, the file name is relative to
+        * the share that is identified by the TreeId in the SMB2
+        * header.
+        */
+       if (tcon->share_flags & SHI1005_FLAGS_DFS) {
+               int name_len;
+
+               req->sync_hdr.Flags |= SMB2_FLAGS_DFS_OPERATIONS;
+               rc = alloc_path_with_tree_prefix(&copy_path, &copy_size,
+                                                &name_len,
+                                                tcon->treeName, path);
+               if (rc) {
+                       cifs_small_buf_release(req);
+                       return rc;
+               }
+               req->NameLength = cpu_to_le16(name_len * 2);
+               uni_path_len = copy_size;
+               path = copy_path;
+       } else {
+               uni_path_len = (2 * UniStrnlen((wchar_t *)path, PATH_MAX)) + 2;
+               /* MUST set path len (NameLength) to 0 opening root of share */
+               req->NameLength = cpu_to_le16(uni_path_len - 2);
+               if (uni_path_len % 8 != 0) {
+                       copy_size = roundup(uni_path_len, 8);
+                       copy_path = kzalloc(copy_size, GFP_KERNEL);
+                       if (!copy_path) {
+                               cifs_small_buf_release(req);
+                               return -ENOMEM;
+                       }
+                       memcpy((char *)copy_path, (const char *)path,
+                              uni_path_len);
+                       uni_path_len = copy_size;
+                       path = copy_path;
+               }
+       }
+
+       iov[1].iov_len = uni_path_len;
+       iov[1].iov_base = path;
+       req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_NONE;
+
+       if (tcon->posix_extensions) {
+               if (n_iov > 2) {
+                       struct create_context *ccontext =
+                           (struct create_context *)iov[n_iov-1].iov_base;
+                       ccontext->Next =
+                               cpu_to_le32(iov[n_iov-1].iov_len);
+               }
+
+               rc = add_posix_context(iov, &n_iov, mode);
+               if (rc) {
+                       cifs_small_buf_release(req);
+                       kfree(copy_path);
+                       return rc;
+               }
+               pc_buf = iov[n_iov-1].iov_base;
+       }
+
+
+       memset(&rqst, 0, sizeof(struct smb_rqst));
+       rqst.rq_iov = iov;
+       rqst.rq_nvec = n_iov;
+
+       rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags,
+                           &rsp_iov);
+
+       cifs_small_buf_release(req);
+       rsp = (struct smb2_create_rsp *)rsp_iov.iov_base;
+
+       if (rc != 0) {
+               cifs_stats_fail_inc(tcon, SMB2_CREATE_HE);
+               trace_smb3_posix_mkdir_err(xid, tcon->tid, ses->Suid,
+                                   CREATE_NOT_FILE, FILE_WRITE_ATTRIBUTES, rc);
+               goto smb311_mkdir_exit;
+       } else
+               trace_smb3_posix_mkdir_done(xid, rsp->PersistentFileId, tcon->tid,
+                                    ses->Suid, CREATE_NOT_FILE,
+                                    FILE_WRITE_ATTRIBUTES);
+
+       SMB2_close(xid, tcon, rsp->PersistentFileId, rsp->VolatileFileId);
+
+       /* Eventually save off posix specific response info and timestaps */
+
+smb311_mkdir_exit:
+       kfree(copy_path);
+       kfree(pc_buf);
+       free_rsp_buf(resp_buftype, rsp);
+       return rc;
+
+}
+#endif /* SMB311 */
+
 int
 SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
          __u8 *oplock, struct smb2_file_all_info *buf,
          struct kvec *err_iov, int *buftype)
 {
+       struct smb_rqst rqst;
        struct smb2_create_req *req;
        struct smb2_create_rsp *rsp;
        struct TCP_Server_Info *server;
@@ -2043,7 +2222,11 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
        }
 #endif /* SMB311 */
 
-       rc = smb2_send_recv(xid, ses, iov, n_iov, &resp_buftype, flags,
+       memset(&rqst, 0, sizeof(struct smb_rqst));
+       rqst.rq_iov = iov;
+       rqst.rq_nvec = n_iov;
+
+       rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags,
                            &rsp_iov);
        cifs_small_buf_release(req);
        rsp = (struct smb2_create_rsp *)rsp_iov.iov_base;
@@ -2099,6 +2282,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
           char *in_data, u32 indatalen,
           char **out_data, u32 *plen /* returned data len */)
 {
+       struct smb_rqst rqst;
        struct smb2_ioctl_req *req;
        struct smb2_ioctl_rsp *rsp;
        struct cifs_ses *ses;
@@ -2189,7 +2373,11 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
        if (opcode == FSCTL_VALIDATE_NEGOTIATE_INFO)
                req->sync_hdr.Flags |= SMB2_FLAGS_SIGNED;
 
-       rc = smb2_send_recv(xid, ses, iov, n_iov, &resp_buftype, flags,
+       memset(&rqst, 0, sizeof(struct smb_rqst));
+       rqst.rq_iov = iov;
+       rqst.rq_nvec = n_iov;
+
+       rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags,
                            &rsp_iov);
        cifs_small_buf_release(req);
        rsp = (struct smb2_ioctl_rsp *)rsp_iov.iov_base;
@@ -2274,6 +2462,7 @@ int
 SMB2_close_flags(const unsigned int xid, struct cifs_tcon *tcon,
                 u64 persistent_fid, u64 volatile_fid, int flags)
 {
+       struct smb_rqst rqst;
        struct smb2_close_req *req;
        struct smb2_close_rsp *rsp;
        struct cifs_ses *ses = tcon->ses;
@@ -2301,7 +2490,11 @@ SMB2_close_flags(const unsigned int xid, struct cifs_tcon *tcon,
        iov[0].iov_base = (char *)req;
        iov[0].iov_len = total_len;
 
-       rc = smb2_send_recv(xid, ses, iov, 1, &resp_buftype, flags, &rsp_iov);
+       memset(&rqst, 0, sizeof(struct smb_rqst));
+       rqst.rq_iov = iov;
+       rqst.rq_nvec = 1;
+
+       rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
        cifs_small_buf_release(req);
        rsp = (struct smb2_close_rsp *)rsp_iov.iov_base;
 
@@ -2387,6 +2580,7 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
           u32 additional_info, size_t output_len, size_t min_len, void **data,
                u32 *dlen)
 {
+       struct smb_rqst rqst;
        struct smb2_query_info_req *req;
        struct smb2_query_info_rsp *rsp = NULL;
        struct kvec iov[2];
@@ -2427,7 +2621,11 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
        /* 1 for Buffer */
        iov[0].iov_len = total_len - 1;
 
-       rc = smb2_send_recv(xid, ses, iov, 1, &resp_buftype, flags, &rsp_iov);
+       memset(&rqst, 0, sizeof(struct smb_rqst));
+       rqst.rq_iov = iov;
+       rqst.rq_nvec = 1;
+
+       rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
        cifs_small_buf_release(req);
        rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base;
 
@@ -2594,11 +2792,10 @@ SMB2_echo(struct TCP_Server_Info *server)
 {
        struct smb2_echo_req *req;
        int rc = 0;
-       struct kvec iov[2];
+       struct kvec iov[1];
        struct smb_rqst rqst = { .rq_iov = iov,
-                                .rq_nvec = 2 };
+                                .rq_nvec = 1 };
        unsigned int total_len;
-       __be32 rfc1002_marker;
 
        cifs_dbg(FYI, "In echo request\n");
 
@@ -2614,11 +2811,8 @@ SMB2_echo(struct TCP_Server_Info *server)
 
        req->sync_hdr.CreditRequest = cpu_to_le16(1);
 
-       iov[0].iov_len = 4;
-       rfc1002_marker = cpu_to_be32(total_len);
-       iov[0].iov_base = &rfc1002_marker;
-       iov[1].iov_len = total_len;
-       iov[1].iov_base = (char *)req;
+       iov[0].iov_len = total_len;
+       iov[0].iov_base = (char *)req;
 
        rc = cifs_call_async(server, &rqst, NULL, smb2_echo_callback, NULL,
                             server, CIFS_ECHO_OP);
@@ -2633,6 +2827,7 @@ int
 SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
           u64 volatile_fid)
 {
+       struct smb_rqst rqst;
        struct smb2_flush_req *req;
        struct cifs_ses *ses = tcon->ses;
        struct kvec iov[1];
@@ -2660,7 +2855,11 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
        iov[0].iov_base = (char *)req;
        iov[0].iov_len = total_len;
 
-       rc = smb2_send_recv(xid, ses, iov, 1, &resp_buftype, flags, &rsp_iov);
+       memset(&rqst, 0, sizeof(struct smb_rqst));
+       rqst.rq_iov = iov;
+       rqst.rq_nvec = 1;
+
+       rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
        cifs_small_buf_release(req);
 
        if (rc != 0) {
@@ -2848,10 +3047,9 @@ smb2_async_readv(struct cifs_readdata *rdata)
        struct smb2_sync_hdr *shdr;
        struct cifs_io_parms io_parms;
        struct smb_rqst rqst = { .rq_iov = rdata->iov,
-                                .rq_nvec = 2 };
+                                .rq_nvec = 1 };
        struct TCP_Server_Info *server;
        unsigned int total_len;
-       __be32 req_len;
 
        cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
                 __func__, rdata->offset, rdata->bytes);
@@ -2882,12 +3080,8 @@ smb2_async_readv(struct cifs_readdata *rdata)
        if (smb3_encryption_required(io_parms.tcon))
                flags |= CIFS_TRANSFORM_REQ;
 
-       req_len = cpu_to_be32(total_len);
-
-       rdata->iov[0].iov_base = &req_len;
-       rdata->iov[0].iov_len = sizeof(__be32);
-       rdata->iov[1].iov_base = buf;
-       rdata->iov[1].iov_len = total_len;
+       rdata->iov[0].iov_base = buf;
+       rdata->iov[0].iov_len = total_len;
 
        shdr = (struct smb2_sync_hdr *)buf;
 
@@ -2926,6 +3120,7 @@ int
 SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
          unsigned int *nbytes, char **buf, int *buf_type)
 {
+       struct smb_rqst rqst;
        int resp_buftype, rc = -EACCES;
        struct smb2_read_plain_req *req = NULL;
        struct smb2_read_rsp *rsp = NULL;
@@ -2946,7 +3141,11 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
        iov[0].iov_base = (char *)req;
        iov[0].iov_len = total_len;
 
-       rc = smb2_send_recv(xid, ses, iov, 1, &resp_buftype, flags, &rsp_iov);
+       memset(&rqst, 0, sizeof(struct smb_rqst));
+       rqst.rq_iov = iov;
+       rqst.rq_nvec = 1;
+
+       rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
        cifs_small_buf_release(req);
 
        rsp = (struct smb2_read_rsp *)rsp_iov.iov_base;
@@ -3062,10 +3261,9 @@ smb2_async_writev(struct cifs_writedata *wdata,
        struct smb2_sync_hdr *shdr;
        struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
        struct TCP_Server_Info *server = tcon->ses->server;
-       struct kvec iov[2];
+       struct kvec iov[1];
        struct smb_rqst rqst = { };
        unsigned int total_len;
-       __be32 rfc1002_marker;
 
        rc = smb2_plain_req_init(SMB2_WRITE, tcon, (void **) &req, &total_len);
        if (rc) {
@@ -3137,15 +3335,11 @@ smb2_async_writev(struct cifs_writedata *wdata,
                v1->length = cpu_to_le32(wdata->mr->mr->length);
        }
 #endif
-       /* 4 for rfc1002 length field and 1 for Buffer */
-       iov[0].iov_len = 4;
-       rfc1002_marker = cpu_to_be32(total_len - 1 + wdata->bytes);
-       iov[0].iov_base = &rfc1002_marker;
-       iov[1].iov_len = total_len - 1;
-       iov[1].iov_base = (char *)req;
+       iov[0].iov_len = total_len - 1;
+       iov[0].iov_base = (char *)req;
 
        rqst.rq_iov = iov;
-       rqst.rq_nvec = 2;
+       rqst.rq_nvec = 1;
        rqst.rq_pages = wdata->pages;
        rqst.rq_offset = wdata->page_offset;
        rqst.rq_npages = wdata->nr_pages;
@@ -3153,7 +3347,7 @@ smb2_async_writev(struct cifs_writedata *wdata,
        rqst.rq_tailsz = wdata->tailsz;
 #ifdef CONFIG_CIFS_SMB_DIRECT
        if (wdata->mr) {
-               iov[1].iov_len += sizeof(struct smbd_buffer_descriptor_v1);
+               iov[0].iov_len += sizeof(struct smbd_buffer_descriptor_v1);
                rqst.rq_npages = 0;
        }
 #endif
@@ -3210,6 +3404,7 @@ int
 SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
           unsigned int *nbytes, struct kvec *iov, int n_vec)
 {
+       struct smb_rqst rqst;
        int rc = 0;
        struct smb2_write_req *req = NULL;
        struct smb2_write_rsp *rsp = NULL;
@@ -3251,7 +3446,11 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
        /* 1 for Buffer */
        iov[0].iov_len = total_len - 1;
 
-       rc = smb2_send_recv(xid, io_parms->tcon->ses, iov, n_vec + 1,
+       memset(&rqst, 0, sizeof(struct smb_rqst));
+       rqst.rq_iov = iov;
+       rqst.rq_nvec = n_vec + 1;
+
+       rc = cifs_send_recv(xid, io_parms->tcon->ses, &rqst,
                            &resp_buftype, flags, &rsp_iov);
        cifs_small_buf_release(req);
        rsp = (struct smb2_write_rsp *)rsp_iov.iov_base;
@@ -3323,6 +3522,7 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
                     u64 persistent_fid, u64 volatile_fid, int index,
                     struct cifs_search_info *srch_inf)
 {
+       struct smb_rqst rqst;
        struct smb2_query_directory_req *req;
        struct smb2_query_directory_rsp *rsp = NULL;
        struct kvec iov[2];
@@ -3395,7 +3595,11 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
        iov[1].iov_base = (char *)(req->Buffer);
        iov[1].iov_len = len;
 
-       rc = smb2_send_recv(xid, ses, iov, 2, &resp_buftype, flags, &rsp_iov);
+       memset(&rqst, 0, sizeof(struct smb_rqst));
+       rqst.rq_iov = iov;
+       rqst.rq_nvec = 2;
+
+       rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
        cifs_small_buf_release(req);
        rsp = (struct smb2_query_directory_rsp *)rsp_iov.iov_base;
 
@@ -3454,6 +3658,7 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
               u8 info_type, u32 additional_info, unsigned int num,
                void **data, unsigned int *size)
 {
+       struct smb_rqst rqst;
        struct smb2_set_info_req *req;
        struct smb2_set_info_rsp *rsp = NULL;
        struct kvec *iov;
@@ -3509,7 +3714,11 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
                iov[i].iov_len = size[i];
        }
 
-       rc = smb2_send_recv(xid, ses, iov, num, &resp_buftype, flags,
+       memset(&rqst, 0, sizeof(struct smb_rqst));
+       rqst.rq_iov = iov;
+       rqst.rq_nvec = num;
+
+       rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags,
                            &rsp_iov);
        cifs_small_buf_release(req);
        rsp = (struct smb2_set_info_rsp *)rsp_iov.iov_base;
@@ -3664,6 +3873,7 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
                  const u64 persistent_fid, const u64 volatile_fid,
                  __u8 oplock_level)
 {
+       struct smb_rqst rqst;
        int rc;
        struct smb2_oplock_break *req = NULL;
        struct cifs_ses *ses = tcon->ses;
@@ -3692,7 +3902,11 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
        iov[0].iov_base = (char *)req;
        iov[0].iov_len = total_len;
 
-       rc = smb2_send_recv(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov);
+       memset(&rqst, 0, sizeof(struct smb_rqst));
+       rqst.rq_iov = iov;
+       rqst.rq_nvec = 1;
+
+       rc = cifs_send_recv(xid, ses, &rqst, &resp_buf_type, flags, &rsp_iov);
        cifs_small_buf_release(req);
 
        if (rc) {
@@ -3755,6 +3969,7 @@ int
 SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
              u64 persistent_fid, u64 volatile_fid, struct kstatfs *fsdata)
 {
+       struct smb_rqst rqst;
        struct smb2_query_info_rsp *rsp = NULL;
        struct kvec iov;
        struct kvec rsp_iov;
@@ -3773,7 +3988,11 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
        if (smb3_encryption_required(tcon))
                flags |= CIFS_TRANSFORM_REQ;
 
-       rc = smb2_send_recv(xid, ses, &iov, 1, &resp_buftype, flags, &rsp_iov);
+       memset(&rqst, 0, sizeof(struct smb_rqst));
+       rqst.rq_iov = &iov;
+       rqst.rq_nvec = 1;
+
+       rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
        cifs_small_buf_release(iov.iov_base);
        if (rc) {
                cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
@@ -3798,6 +4017,7 @@ int
 SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
              u64 persistent_fid, u64 volatile_fid, int level)
 {
+       struct smb_rqst rqst;
        struct smb2_query_info_rsp *rsp = NULL;
        struct kvec iov;
        struct kvec rsp_iov;
@@ -3829,7 +4049,11 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
        if (smb3_encryption_required(tcon))
                flags |= CIFS_TRANSFORM_REQ;
 
-       rc = smb2_send_recv(xid, ses, &iov, 1, &resp_buftype, flags, &rsp_iov);
+       memset(&rqst, 0, sizeof(struct smb_rqst));
+       rqst.rq_iov = &iov;
+       rqst.rq_nvec = 1;
+
+       rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
        cifs_small_buf_release(iov.iov_base);
        if (rc) {
                cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
@@ -3868,6 +4092,7 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
           const __u64 persist_fid, const __u64 volatile_fid, const __u32 pid,
           const __u32 num_lock, struct smb2_lock_element *buf)
 {
+       struct smb_rqst rqst;
        int rc = 0;
        struct smb2_lock_req *req = NULL;
        struct kvec iov[2];
@@ -3900,7 +4125,12 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
        iov[1].iov_len = count;
 
        cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
-       rc = smb2_send_recv(xid, tcon->ses, iov, 2, &resp_buf_type, flags,
+
+       memset(&rqst, 0, sizeof(struct smb_rqst));
+       rqst.rq_iov = iov;
+       rqst.rq_nvec = 2;
+
+       rc = cifs_send_recv(xid, tcon->ses, &rqst, &resp_buf_type, flags,
                            &rsp_iov);
        cifs_small_buf_release(req);
        if (rc) {
@@ -3934,6 +4164,7 @@ int
 SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon,
                 __u8 *lease_key, const __le32 lease_state)
 {
+       struct smb_rqst rqst;
        int rc;
        struct smb2_lease_ack *req = NULL;
        struct cifs_ses *ses = tcon->ses;
@@ -3964,7 +4195,11 @@ SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon,
        iov[0].iov_base = (char *)req;
        iov[0].iov_len = total_len;
 
-       rc = smb2_send_recv(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov);
+       memset(&rqst, 0, sizeof(struct smb_rqst));
+       rqst.rq_iov = iov;
+       rqst.rq_nvec = 1;
+
+       rc = cifs_send_recv(xid, ses, &rqst, &resp_buf_type, flags, &rsp_iov);
        cifs_small_buf_release(req);
 
        if (rc) {
index a345560001ced354c550d6ab2f507a18d72ff9d2..824dddeee3f2dc8723d6ce9ac792e9de71358796 100644 (file)
@@ -851,8 +851,11 @@ struct validate_negotiate_info_rsp {
        __le16 Dialect; /* Dialect in use for the connection */
 } __packed;
 
-#define RSS_CAPABLE    0x00000001
-#define RDMA_CAPABLE   0x00000002
+#define RSS_CAPABLE    cpu_to_le32(0x00000001)
+#define RDMA_CAPABLE   cpu_to_le32(0x00000002)
+
+#define INTERNETWORK   cpu_to_le16(0x0002)
+#define INTERNETWORKV6 cpu_to_le16(0x0017)
 
 struct network_interface_info_ioctl_rsp {
        __le32 Next; /* next interface. zero if this is last one */
@@ -860,7 +863,21 @@ struct network_interface_info_ioctl_rsp {
        __le32 Capability; /* RSS or RDMA Capable */
        __le32 Reserved;
        __le64 LinkSpeed;
-       char    SockAddr_Storage[128];
+       __le16 Family;
+       __u8 Buffer[126];
+} __packed;
+
+struct iface_info_ipv4 {
+       __be16 Port;
+       __be32 IPv4Address;
+       __be64 Reserved;
+} __packed;
+
+struct iface_info_ipv6 {
+       __be16 Port;
+       __be32 FlowInfo;
+       __u8   IPv6Address[16];
+       __be32 ScopeId;
 } __packed;
 
 #define NO_FILE_ID 0xFFFFFFFFFFFFFFFFULL /* general ioctls to srv not to file */
index c84020057bd816c31a69fd173746374c5c224c8a..3ae208ac2a770d2177036d60e86d0104a4de022a 100644 (file)
@@ -79,6 +79,10 @@ extern int smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
                              struct cifs_sb_info *cifs_sb, bool set_alloc);
 extern int smb2_set_file_info(struct inode *inode, const char *full_path,
                              FILE_BASIC_INFO *buf, const unsigned int xid);
+extern int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
+                              umode_t mode, struct cifs_tcon *tcon,
+                              const char *full_path,
+                              struct cifs_sb_info *cifs_sb);
 extern int smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon,
                      const char *name, struct cifs_sb_info *cifs_sb);
 extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path,
@@ -109,6 +113,8 @@ extern int smb2_unlock_range(struct cifsFileInfo *cfile,
 extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile);
 extern void smb2_reconnect_server(struct work_struct *work);
 extern int smb3_crypto_aead_allocate(struct TCP_Server_Info *server);
+extern unsigned long
+smb2_rqst_len(struct smb_rqst *rqst, bool skip_rfc1002_marker);
 
 /*
  * SMB2 Worker functions - most of protocol specific implementation details
index 349d5ccf854c26999ed8554f6d19cf64a89a33a3..51b9437c3c7b7cf60987170f7e46ac23d9ae98ac 100644 (file)
@@ -171,9 +171,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
        unsigned char smb2_signature[SMB2_HMACSHA256_SIZE];
        unsigned char *sigptr = smb2_signature;
        struct kvec *iov = rqst->rq_iov;
-       int iov_hdr_index = rqst->rq_nvec > 1 ? 1 : 0;
-       struct smb2_sync_hdr *shdr =
-               (struct smb2_sync_hdr *)iov[iov_hdr_index].iov_base;
+       struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[0].iov_base;
        struct cifs_ses *ses;
 
        ses = smb2_find_smb_ses(server, shdr->SessionId);
@@ -204,7 +202,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
                return rc;
        }
 
-       rc = __cifs_calc_signature(rqst, iov_hdr_index,  server, sigptr,
+       rc = __cifs_calc_signature(rqst, server, sigptr,
                &server->secmech.sdeschmacsha256->shash);
 
        if (!rc)
@@ -414,9 +412,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
        unsigned char smb3_signature[SMB2_CMACAES_SIZE];
        unsigned char *sigptr = smb3_signature;
        struct kvec *iov = rqst->rq_iov;
-       int iov_hdr_index = rqst->rq_nvec > 1 ? 1 : 0;
-       struct smb2_sync_hdr *shdr =
-               (struct smb2_sync_hdr *)iov[iov_hdr_index].iov_base;
+       struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[0].iov_base;
        struct cifs_ses *ses;
 
        ses = smb2_find_smb_ses(server, shdr->SessionId);
@@ -447,7 +443,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
                return rc;
        }
 
-       rc = __cifs_calc_signature(rqst, iov_hdr_index, server, sigptr,
+       rc = __cifs_calc_signature(rqst, server, sigptr,
                                   &server->secmech.sdesccmacaes->shash);
 
        if (!rc)
@@ -462,7 +458,7 @@ smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 {
        int rc = 0;
        struct smb2_sync_hdr *shdr =
-                       (struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base;
+                       (struct smb2_sync_hdr *)rqst->rq_iov[0].iov_base;
 
        if (!(shdr->Flags & SMB2_FLAGS_SIGNED) ||
            server->tcpStatus == CifsNeedNegotiate)
@@ -635,7 +631,7 @@ smb2_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst)
 {
        int rc;
        struct smb2_sync_hdr *shdr =
-                       (struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base;
+                       (struct smb2_sync_hdr *)rqst->rq_iov[0].iov_base;
        struct mid_q_entry *mid;
 
        smb2_seq_num_into_buf(ses->server, shdr);
@@ -656,7 +652,7 @@ smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 {
        int rc;
        struct smb2_sync_hdr *shdr =
-                       (struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base;
+                       (struct smb2_sync_hdr *)rqst->rq_iov[0].iov_base;
        struct mid_q_entry *mid;
 
        smb2_seq_num_into_buf(server, shdr);
index e459c97151b34e684dc3f3cbbc36772fee5aaee5..6fd94d9ffac21ad6d8c4fbc436d2b8afa063aede 100644 (file)
@@ -18,6 +18,7 @@
 #include "smbdirect.h"
 #include "cifs_debug.h"
 #include "cifsproto.h"
+#include "smb2proto.h"
 
 static struct smbd_response *get_empty_queue_buffer(
                struct smbd_connection *info);
@@ -2087,7 +2088,7 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst)
        struct kvec vec;
        int nvecs;
        int size;
-       unsigned int buflen = 0, remaining_data_length;
+       unsigned int buflen, remaining_data_length;
        int start, i, j;
        int max_iov_size =
                info->max_send_size - sizeof(struct smbd_data_transfer);
@@ -2111,25 +2112,13 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst)
                log_write(ERR, "expected the pdu length in 1st iov, but got %zu\n", rqst->rq_iov[0].iov_len);
                return -EINVAL;
        }
-       iov = &rqst->rq_iov[1];
-
-       /* total up iov array first */
-       for (i = 0; i < rqst->rq_nvec-1; i++) {
-               buflen += iov[i].iov_len;
-       }
 
        /*
         * Add in the page array if there is one. The caller needs to set
         * rq_tailsz to PAGE_SIZE when the buffer has multiple pages and
         * ends at page boundary
         */
-       if (rqst->rq_npages) {
-               if (rqst->rq_npages == 1)
-                       buflen += rqst->rq_tailsz;
-               else
-                       buflen += rqst->rq_pagesz * (rqst->rq_npages - 1) -
-                                       rqst->rq_offset + rqst->rq_tailsz;
-       }
+       buflen = smb2_rqst_len(rqst, true);
 
        if (buflen + sizeof(struct smbd_data_transfer) >
                info->max_fragmented_send_size) {
@@ -2139,6 +2128,8 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst)
                goto done;
        }
 
+       iov = &rqst->rq_iov[1];
+
        cifs_dbg(FYI, "Sending smb (RDMA): smb_len=%u\n", buflen);
        for (i = 0; i < rqst->rq_nvec-1; i++)
                dump_smb(iov[i].iov_base, iov[i].iov_len);
index 61e74d455d90625339591a3b47560f5bdb50c343..67e413f6ee4d8fd1dbd1eede0a7b0a9e6442a9e3 100644 (file)
@@ -378,7 +378,7 @@ DEFINE_EVENT(smb3_open_err_class, smb3_##name,    \
        TP_ARGS(xid, tid, sesid, create_options, desired_access, rc))
 
 DEFINE_SMB3_OPEN_ERR_EVENT(open_err);
-
+DEFINE_SMB3_OPEN_ERR_EVENT(posix_mkdir_err);
 
 DECLARE_EVENT_CLASS(smb3_open_done_class,
        TP_PROTO(unsigned int xid,
@@ -420,6 +420,7 @@ DEFINE_EVENT(smb3_open_done_class, smb3_##name,  \
        TP_ARGS(xid, fid, tid, sesid, create_options, desired_access))
 
 DEFINE_SMB3_OPEN_DONE_EVENT(open_done);
+DEFINE_SMB3_OPEN_DONE_EVENT(posix_mkdir_done);
 
 #endif /* _CIFS_TRACE_H */
 
index 1f1a68f8911001bae86976171e44a09402982d92..fb57dfbfb749973c1c72423a93d76442c0a07fad 100644 (file)
@@ -201,15 +201,24 @@ smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg,
        return 0;
 }
 
-static unsigned long
-rqst_len(struct smb_rqst *rqst)
+unsigned long
+smb2_rqst_len(struct smb_rqst *rqst, bool skip_rfc1002_marker)
 {
        unsigned int i;
-       struct kvec *iov = rqst->rq_iov;
+       struct kvec *iov;
+       int nvec;
        unsigned long buflen = 0;
 
+       if (skip_rfc1002_marker && rqst->rq_iov[0].iov_len == 4) {
+               iov = &rqst->rq_iov[1];
+               nvec = rqst->rq_nvec - 1;
+       } else {
+               iov = rqst->rq_iov;
+               nvec = rqst->rq_nvec;
+       }
+
        /* total up iov array first */
-       for (i = 0; i < rqst->rq_nvec; i++)
+       for (i = 0; i < nvec; i++)
                buflen += iov[i].iov_len;
 
        /*
@@ -236,18 +245,20 @@ rqst_len(struct smb_rqst *rqst)
 }
 
 static int
-__smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
+__smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
+               struct smb_rqst *rqst)
 {
-       int rc;
-       struct kvec *iov = rqst->rq_iov;
-       int n_vec = rqst->rq_nvec;
-       unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base);
-       unsigned long send_length;
-       unsigned int i;
+       int rc = 0;
+       struct kvec *iov;
+       int n_vec;
+       unsigned int send_length = 0;
+       unsigned int i, j;
        size_t total_len = 0, sent, size;
        struct socket *ssocket = server->ssocket;
        struct msghdr smb_msg;
        int val = 1;
+       __be32 rfc1002_marker;
+
        if (cifs_rdma_enabled(server) && server->smbd_conn) {
                rc = smbd_send(server->smbd_conn, rqst);
                goto smbd_done;
@@ -255,51 +266,67 @@ __smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
        if (ssocket == NULL)
                return -ENOTSOCK;
 
-       /* sanity check send length */
-       send_length = rqst_len(rqst);
-       if (send_length != smb_buf_length + 4) {
-               WARN(1, "Send length mismatch(send_length=%lu smb_buf_length=%u)\n",
-                       send_length, smb_buf_length);
-               return -EIO;
-       }
-
-       if (n_vec < 2)
-               return -EIO;
-
-       cifs_dbg(FYI, "Sending smb: smb_len=%u\n", smb_buf_length);
-       dump_smb(iov[0].iov_base, iov[0].iov_len);
-       dump_smb(iov[1].iov_base, iov[1].iov_len);
-
        /* cork the socket */
        kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK,
                                (char *)&val, sizeof(val));
 
-       size = 0;
-       for (i = 0; i < n_vec; i++)
-               size += iov[i].iov_len;
+       for (j = 0; j < num_rqst; j++)
+               send_length += smb2_rqst_len(&rqst[j], true);
+       rfc1002_marker = cpu_to_be32(send_length);
 
-       iov_iter_kvec(&smb_msg.msg_iter, WRITE | ITER_KVEC, iov, n_vec, size);
+       /* Generate a rfc1002 marker for SMB2+ */
+       if (server->vals->header_preamble_size == 0) {
+               struct kvec hiov = {
+                       .iov_base = &rfc1002_marker,
+                       .iov_len  = 4
+               };
+               iov_iter_kvec(&smb_msg.msg_iter, WRITE | ITER_KVEC, &hiov,
+                             1, 4);
+               rc = smb_send_kvec(server, &smb_msg, &sent);
+               if (rc < 0)
+                       goto uncork;
 
-       rc = smb_send_kvec(server, &smb_msg, &sent);
-       if (rc < 0)
-               goto uncork;
+               total_len += sent;
+               send_length += 4;
+       }
 
-       total_len += sent;
+       cifs_dbg(FYI, "Sending smb: smb_len=%u\n", send_length);
 
-       /* now walk the page array and send each page in it */
-       for (i = 0; i < rqst->rq_npages; i++) {
-               struct bio_vec bvec;
+       for (j = 0; j < num_rqst; j++) {
+               iov = rqst[j].rq_iov;
+               n_vec = rqst[j].rq_nvec;
 
-               bvec.bv_page = rqst->rq_pages[i];
-               rqst_page_get_length(rqst, i, &bvec.bv_len, &bvec.bv_offset);
+               size = 0;
+               for (i = 0; i < n_vec; i++) {
+                       dump_smb(iov[i].iov_base, iov[i].iov_len);
+                       size += iov[i].iov_len;
+               }
+
+               iov_iter_kvec(&smb_msg.msg_iter, WRITE | ITER_KVEC,
+                             iov, n_vec, size);
 
-               iov_iter_bvec(&smb_msg.msg_iter, WRITE | ITER_BVEC,
-                             &bvec, 1, bvec.bv_len);
                rc = smb_send_kvec(server, &smb_msg, &sent);
                if (rc < 0)
-                       break;
+                       goto uncork;
 
                total_len += sent;
+
+               /* now walk the page array and send each page in it */
+               for (i = 0; i < rqst[j].rq_npages; i++) {
+                       struct bio_vec bvec;
+
+                       bvec.bv_page = rqst[j].rq_pages[i];
+                       rqst_page_get_length(&rqst[j], i, &bvec.bv_len,
+                                            &bvec.bv_offset);
+
+                       iov_iter_bvec(&smb_msg.msg_iter, WRITE | ITER_BVEC,
+                                     &bvec, 1, bvec.bv_len);
+                       rc = smb_send_kvec(server, &smb_msg, &sent);
+                       if (rc < 0)
+                               break;
+
+                       total_len += sent;
+               }
        }
 
 uncork:
@@ -308,9 +335,9 @@ uncork:
        kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK,
                                (char *)&val, sizeof(val));
 
-       if ((total_len > 0) && (total_len != smb_buf_length + 4)) {
+       if ((total_len > 0) && (total_len != send_length)) {
                cifs_dbg(FYI, "partial send (wanted=%u sent=%zu): terminating session\n",
-                        smb_buf_length + 4, total_len);
+                        send_length, total_len);
                /*
                 * If we have only sent part of an SMB then the next SMB could
                 * be taken as the remainder of this one. We need to kill the
@@ -335,7 +362,7 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst, int flags)
        int rc;
 
        if (!(flags & CIFS_TRANSFORM_REQ))
-               return __smb_send_rqst(server, rqst);
+               return __smb_send_rqst(server, 1, rqst);
 
        if (!server->ops->init_transform_rq ||
            !server->ops->free_transform_rq) {
@@ -347,7 +374,7 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst, int flags)
        if (rc)
                return rc;
 
-       rc = __smb_send_rqst(server, &cur_rqst);
+       rc = __smb_send_rqst(server, 1, &cur_rqst);
        server->ops->free_transform_rq(&cur_rqst);
        return rc;
 }
@@ -365,7 +392,7 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
        iov[1].iov_base = (char *)smb_buffer + 4;
        iov[1].iov_len = smb_buf_length;
 
-       return __smb_send_rqst(server, &rqst);
+       return __smb_send_rqst(server, 1, &rqst);
 }
 
 static int
@@ -730,7 +757,6 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
         * to the same server. We may make this configurable later or
         * use ses->maxReq.
         */
-
        rc = wait_for_free_request(ses->server, timeout, optype);
        if (rc)
                return rc;
@@ -766,8 +792,8 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
 
 #ifdef CONFIG_CIFS_SMB311
        if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP))
-               smb311_update_preauth_hash(ses, rqst->rq_iov+1,
-                                          rqst->rq_nvec-1);
+               smb311_update_preauth_hash(ses, rqst->rq_iov,
+                                          rqst->rq_nvec);
 #endif
 
        if (timeout == CIFS_ASYNC_OP)
@@ -812,8 +838,8 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
 #ifdef CONFIG_CIFS_SMB311
        if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP)) {
                struct kvec iov = {
-                       .iov_base = buf,
-                       .iov_len = midQ->resp_buf_size
+                       .iov_base = resp_iov->iov_base,
+                       .iov_len = resp_iov->iov_len
                };
                smb311_update_preauth_hash(ses, &iov, 1);
        }
@@ -872,49 +898,6 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
        return rc;
 }
 
-/* Like SendReceive2 but iov[0] does not contain an rfc1002 header */
-int
-smb2_send_recv(const unsigned int xid, struct cifs_ses *ses,
-              struct kvec *iov, int n_vec, int *resp_buf_type /* ret */,
-              const int flags, struct kvec *resp_iov)
-{
-       struct smb_rqst rqst;
-       struct kvec s_iov[CIFS_MAX_IOV_SIZE], *new_iov;
-       int rc;
-       int i;
-       __u32 count;
-       __be32 rfc1002_marker;
-
-       if (n_vec + 1 > CIFS_MAX_IOV_SIZE) {
-               new_iov = kmalloc_array(n_vec + 1, sizeof(struct kvec),
-                                       GFP_KERNEL);
-               if (!new_iov)
-                       return -ENOMEM;
-       } else
-               new_iov = s_iov;
-
-       /* 1st iov is an RFC1002 Session Message length */
-       memcpy(new_iov + 1, iov, (sizeof(struct kvec) * n_vec));
-
-       count = 0;
-       for (i = 1; i < n_vec + 1; i++)
-               count += new_iov[i].iov_len;
-
-       rfc1002_marker = cpu_to_be32(count);
-
-       new_iov[0].iov_base = &rfc1002_marker;
-       new_iov[0].iov_len = 4;
-
-       memset(&rqst, 0, sizeof(struct smb_rqst));
-       rqst.rq_iov = new_iov;
-       rqst.rq_nvec = n_vec + 1;
-
-       rc = cifs_send_recv(xid, ses, &rqst, resp_buf_type, flags, resp_iov);
-       if (n_vec + 1 > CIFS_MAX_IOV_SIZE)
-               kfree(new_iov);
-       return rc;
-}
-
 int
 SendReceive(const unsigned int xid, struct cifs_ses *ses,
            struct smb_hdr *in_buf, struct smb_hdr *out_buf,
index ca599df0dcb1e18da08c50cf6406d6203b974e92..f3d543dd9a980282e723f8034771c14e88f9f4de 100644 (file)
@@ -105,11 +105,11 @@ void coda_vattr_to_iattr(struct inode *inode, struct coda_vattr *attr)
        if (attr->va_size != -1)
                inode->i_blocks = (attr->va_size + 511) >> 9;
        if (attr->va_atime.tv_sec != -1) 
-               inode->i_atime = attr->va_atime;
+               inode->i_atime = timespec_to_timespec64(attr->va_atime);
        if (attr->va_mtime.tv_sec != -1)
-               inode->i_mtime = attr->va_mtime;
+               inode->i_mtime = timespec_to_timespec64(attr->va_mtime);
         if (attr->va_ctime.tv_sec != -1)
-               inode->i_ctime = attr->va_ctime;
+               inode->i_ctime = timespec_to_timespec64(attr->va_ctime);
 }
 
 
@@ -175,13 +175,13 @@ void coda_iattr_to_vattr(struct iattr *iattr, struct coda_vattr *vattr)
                 vattr->va_size = iattr->ia_size;
        }
         if ( valid & ATTR_ATIME ) {
-                vattr->va_atime = iattr->ia_atime;
+               vattr->va_atime = timespec64_to_timespec(iattr->ia_atime);
        }
         if ( valid & ATTR_MTIME ) {
-                vattr->va_mtime = iattr->ia_mtime;
+               vattr->va_mtime = timespec64_to_timespec(iattr->ia_mtime);
        }
         if ( valid & ATTR_CTIME ) {
-                vattr->va_ctime = iattr->ia_ctime;
+               vattr->va_ctime = timespec64_to_timespec(iattr->ia_ctime);
        }
 }
 
index ad718e5e37bb6415e3a8de5f5d7c98e31c90a425..28ef9e5288532dc16a74f634bea6f2cdec1a384d 100644 (file)
@@ -90,14 +90,14 @@ int configfs_setattr(struct dentry * dentry, struct iattr * iattr)
        if (ia_valid & ATTR_GID)
                sd_iattr->ia_gid = iattr->ia_gid;
        if (ia_valid & ATTR_ATIME)
-               sd_iattr->ia_atime = timespec_trunc(iattr->ia_atime,
-                                               inode->i_sb->s_time_gran);
+               sd_iattr->ia_atime = timespec64_trunc(iattr->ia_atime,
+                                                     inode->i_sb->s_time_gran);
        if (ia_valid & ATTR_MTIME)
-               sd_iattr->ia_mtime = timespec_trunc(iattr->ia_mtime,
-                                               inode->i_sb->s_time_gran);
+               sd_iattr->ia_mtime = timespec64_trunc(iattr->ia_mtime,
+                                                     inode->i_sb->s_time_gran);
        if (ia_valid & ATTR_CTIME)
-               sd_iattr->ia_ctime = timespec_trunc(iattr->ia_ctime,
-                                               inode->i_sb->s_time_gran);
+               sd_iattr->ia_ctime = timespec64_trunc(iattr->ia_ctime,
+                                                     inode->i_sb->s_time_gran);
        if (ia_valid & ATTR_MODE) {
                umode_t mode = iattr->ia_mode;
 
index c4fb9ad7c808175d0a4b358bb3bb13da9e42dabb..f408994fc632129dcbdceca43cedf2fd14705205 100644 (file)
@@ -90,7 +90,7 @@ static struct inode *get_cramfs_inode(struct super_block *sb,
        const struct cramfs_inode *cramfs_inode, unsigned int offset)
 {
        struct inode *inode;
-       static struct timespec zerotime;
+       static struct timespec64 zerotime;
 
        inode = iget_locked(sb, cramino(cramfs_inode, offset));
        if (!inode)
index 61c9514da5e956a36a90e9df601eccfc01b9595a..ceb1031f1cac948e74a970f02058cfeb52d7a351 100644 (file)
@@ -156,11 +156,11 @@ static __poll_t eventfd_poll_mask(struct file *file, __poll_t eventmask)
        count = READ_ONCE(ctx->count);
 
        if (count > 0)
-               events |= EPOLLIN;
+               events |= (EPOLLIN & eventmask);
        if (count == ULLONG_MAX)
                events |= EPOLLERR;
        if (ULLONG_MAX - 1 > count)
-               events |= EPOLLOUT;
+               events |= (EPOLLOUT & eventmask);
 
        return events;
 }
index 67db22fe99c5ce8bf0ba606c0a45f221cbf69b38..ea4436f409fb005a16edeca3f49f29f955db0171 100644 (file)
@@ -922,13 +922,17 @@ static __poll_t ep_read_events_proc(struct eventpoll *ep, struct list_head *head
        return 0;
 }
 
-static __poll_t ep_eventpoll_poll(struct file *file, poll_table *wait)
+static struct wait_queue_head *ep_eventpoll_get_poll_head(struct file *file,
+               __poll_t eventmask)
 {
        struct eventpoll *ep = file->private_data;
-       int depth = 0;
+       return &ep->poll_wait;
+}
 
-       /* Insert inside our poll wait queue */
-       poll_wait(file, &ep->poll_wait, wait);
+static __poll_t ep_eventpoll_poll_mask(struct file *file, __poll_t eventmask)
+{
+       struct eventpoll *ep = file->private_data;
+       int depth = 0;
 
        /*
         * Proceed to find out if wanted events are really available inside
@@ -968,7 +972,8 @@ static const struct file_operations eventpoll_fops = {
        .show_fdinfo    = ep_show_fdinfo,
 #endif
        .release        = ep_eventpoll_release,
-       .poll           = ep_eventpoll_poll,
+       .get_poll_head  = ep_eventpoll_get_poll_head,
+       .poll_mask      = ep_eventpoll_poll_mask,
        .llseek         = noop_llseek,
 };
 
index ddbf87246898252b19f4df4de696434d35fed67d..1b8b44637e7065b9bc7ffdf17f0228fc84814860 100644 (file)
@@ -146,68 +146,82 @@ int  _ore_get_io_state(struct ore_layout *layout,
                        struct ore_io_state **pios)
 {
        struct ore_io_state *ios;
-       struct page **pages;
-       struct osd_sg_entry *sgilist;
+       size_t size_ios, size_extra, size_total;
+       void *ios_extra;
+
+       /*
+        * The desired layout looks like this, with the extra_allocation
+        * items pointed at from fields within ios or per_dev:
+
        struct __alloc_all_io_state {
                struct ore_io_state ios;
                struct ore_per_dev_state per_dev[numdevs];
                union {
                        struct osd_sg_entry sglist[sgs_per_dev * numdevs];
                        struct page *pages[num_par_pages];
-               };
-       } *_aios;
-
-       if (likely(sizeof(*_aios) <= PAGE_SIZE)) {
-               _aios = kzalloc(sizeof(*_aios), GFP_KERNEL);
-               if (unlikely(!_aios)) {
-                       ORE_DBGMSG("Failed kzalloc bytes=%zd\n",
-                                  sizeof(*_aios));
+               } extra_allocation;
+       } whole_allocation;
+
+       */
+
+       /* This should never happen, so abort early if it ever does. */
+       if (sgs_per_dev && num_par_pages) {
+               ORE_DBGMSG("Tried to use both pages and sglist\n");
+               *pios = NULL;
+               return -EINVAL;
+       }
+
+       if (numdevs > (INT_MAX - sizeof(*ios)) /
+                      sizeof(struct ore_per_dev_state))
+               return -ENOMEM;
+       size_ios = sizeof(*ios) + sizeof(struct ore_per_dev_state) * numdevs;
+
+       if (sgs_per_dev * numdevs > INT_MAX / sizeof(struct osd_sg_entry))
+               return -ENOMEM;
+       if (num_par_pages > INT_MAX / sizeof(struct page *))
+               return -ENOMEM;
+       size_extra = max(sizeof(struct osd_sg_entry) * (sgs_per_dev * numdevs),
+                        sizeof(struct page *) * num_par_pages);
+
+       size_total = size_ios + size_extra;
+
+       if (likely(size_total <= PAGE_SIZE)) {
+               ios = kzalloc(size_total, GFP_KERNEL);
+               if (unlikely(!ios)) {
+                       ORE_DBGMSG("Failed kzalloc bytes=%zd\n", size_total);
                        *pios = NULL;
                        return -ENOMEM;
                }
-               pages = num_par_pages ? _aios->pages : NULL;
-               sgilist = sgs_per_dev ? _aios->sglist : NULL;
-               ios = &_aios->ios;
+               ios_extra = (char *)ios + size_ios;
        } else {
-               struct __alloc_small_io_state {
-                       struct ore_io_state ios;
-                       struct ore_per_dev_state per_dev[numdevs];
-               } *_aio_small;
-               union __extra_part {
-                       struct osd_sg_entry sglist[sgs_per_dev * numdevs];
-                       struct page *pages[num_par_pages];
-               } *extra_part;
-
-               _aio_small = kzalloc(sizeof(*_aio_small), GFP_KERNEL);
-               if (unlikely(!_aio_small)) {
+               ios = kzalloc(size_ios, GFP_KERNEL);
+               if (unlikely(!ios)) {
                        ORE_DBGMSG("Failed alloc first part bytes=%zd\n",
-                                  sizeof(*_aio_small));
+                                  size_ios);
                        *pios = NULL;
                        return -ENOMEM;
                }
-               extra_part = kzalloc(sizeof(*extra_part), GFP_KERNEL);
-               if (unlikely(!extra_part)) {
+               ios_extra = kzalloc(size_extra, GFP_KERNEL);
+               if (unlikely(!ios_extra)) {
                        ORE_DBGMSG("Failed alloc second part bytes=%zd\n",
-                                  sizeof(*extra_part));
-                       kfree(_aio_small);
+                                  size_extra);
+                       kfree(ios);
                        *pios = NULL;
                        return -ENOMEM;
                }
 
-               pages = num_par_pages ? extra_part->pages : NULL;
-               sgilist = sgs_per_dev ? extra_part->sglist : NULL;
                /* In this case the per_dev[0].sgilist holds the pointer to
                 * be freed
                 */
-               ios = &_aio_small->ios;
                ios->extra_part_alloc = true;
        }
 
-       if (pages) {
-               ios->parity_pages = pages;
+       if (num_par_pages) {
+               ios->parity_pages = ios_extra;
                ios->max_par_pages = num_par_pages;
        }
-       if (sgilist) {
+       if (sgs_per_dev) {
+               struct osd_sg_entry *sgilist = ios_extra;
                unsigned d;
 
                for (d = 0; d < numdevs; ++d) {
index 27cbdb6976495f5f830ca473e9b844fb1a2bd29d..199590f362030d2c4dad33968b2e0a12ef90299a 100644 (file)
@@ -71,6 +71,11 @@ static int _sp2d_alloc(unsigned pages_in_unit, unsigned group_width,
 {
        struct __stripe_pages_2d *sp2d;
        unsigned data_devs = group_width - parity;
+
+       /*
+        * Desired allocation layout is, though when larger than PAGE_SIZE,
+        * each struct __alloc_1p_arrays is separately allocated:
+
        struct _alloc_all_bytes {
                struct __alloc_stripe_pages_2d {
                        struct __stripe_pages_2d sp2d;
@@ -82,55 +87,85 @@ static int _sp2d_alloc(unsigned pages_in_unit, unsigned group_width,
                        char page_is_read[data_devs];
                } __a1pa[pages_in_unit];
        } *_aab;
+
        struct __alloc_1p_arrays *__a1pa;
        struct __alloc_1p_arrays *__a1pa_end;
-       const unsigned sizeof__a1pa = sizeof(_aab->__a1pa[0]);
+
+       */
+
+       char *__a1pa;
+       char *__a1pa_end;
+
+       const size_t sizeof_stripe_pages_2d =
+               sizeof(struct __stripe_pages_2d) +
+               sizeof(struct __1_page_stripe) * pages_in_unit;
+       const size_t sizeof__a1pa =
+               ALIGN(sizeof(struct page *) * (2 * group_width) + data_devs,
+                     sizeof(void *));
+       const size_t sizeof__a1pa_arrays = sizeof__a1pa * pages_in_unit;
+       const size_t alloc_total = sizeof_stripe_pages_2d +
+                                  sizeof__a1pa_arrays;
+
        unsigned num_a1pa, alloc_size, i;
 
        /* FIXME: check these numbers in ore_verify_layout */
-       BUG_ON(sizeof(_aab->__asp2d) > PAGE_SIZE);
+       BUG_ON(sizeof_stripe_pages_2d > PAGE_SIZE);
        BUG_ON(sizeof__a1pa > PAGE_SIZE);
 
-       if (sizeof(*_aab) > PAGE_SIZE) {
-               num_a1pa = (PAGE_SIZE - sizeof(_aab->__asp2d)) / sizeof__a1pa;
-               alloc_size = sizeof(_aab->__asp2d) + sizeof__a1pa * num_a1pa;
+       /*
+        * If alloc_total would be larger than PAGE_SIZE, only allocate
+        * as many a1pa items as would fill the rest of the page, instead
+        * of the full pages_in_unit count.
+        */
+       if (alloc_total > PAGE_SIZE) {
+               num_a1pa = (PAGE_SIZE - sizeof_stripe_pages_2d) / sizeof__a1pa;
+               alloc_size = sizeof_stripe_pages_2d + sizeof__a1pa * num_a1pa;
        } else {
                num_a1pa = pages_in_unit;
-               alloc_size = sizeof(*_aab);
+               alloc_size = alloc_total;
        }
 
-       _aab = kzalloc(alloc_size, GFP_KERNEL);
-       if (unlikely(!_aab)) {
+       *psp2d = sp2d = kzalloc(alloc_size, GFP_KERNEL);
+       if (unlikely(!sp2d)) {
                ORE_DBGMSG("!! Failed to alloc sp2d size=%d\n", alloc_size);
                return -ENOMEM;
        }
+       /* From here Just call _sp2d_free */
 
-       sp2d = &_aab->__asp2d.sp2d;
-       *psp2d = sp2d; /* From here Just call _sp2d_free */
-
-       __a1pa = _aab->__a1pa;
-       __a1pa_end = __a1pa + num_a1pa;
+       /* Find start of a1pa area. */
+       __a1pa = (char *)sp2d + sizeof_stripe_pages_2d;
+       /* Find end of the _allocated_ a1pa area. */
+       __a1pa_end = __a1pa + alloc_size;
 
+       /* Allocate additionally needed a1pa items in PAGE_SIZE chunks. */
        for (i = 0; i < pages_in_unit; ++i) {
+               struct __1_page_stripe *stripe = &sp2d->_1p_stripes[i];
+
                if (unlikely(__a1pa >= __a1pa_end)) {
                        num_a1pa = min_t(unsigned, PAGE_SIZE / sizeof__a1pa,
                                                        pages_in_unit - i);
+                       alloc_size = sizeof__a1pa * num_a1pa;
 
-                       __a1pa = kcalloc(num_a1pa, sizeof__a1pa, GFP_KERNEL);
+                       __a1pa = kzalloc(alloc_size, GFP_KERNEL);
                        if (unlikely(!__a1pa)) {
                                ORE_DBGMSG("!! Failed to _alloc_1p_arrays=%d\n",
                                           num_a1pa);
                                return -ENOMEM;
                        }
-                       __a1pa_end = __a1pa + num_a1pa;
+                       __a1pa_end = __a1pa + alloc_size;
                        /* First *pages is marked for kfree of the buffer */
-                       sp2d->_1p_stripes[i].alloc = true;
+                       stripe->alloc = true;
                }
 
-               sp2d->_1p_stripes[i].pages = __a1pa->pages;
-               sp2d->_1p_stripes[i].scribble = __a1pa->scribble ;
-               sp2d->_1p_stripes[i].page_is_read = __a1pa->page_is_read;
-               ++__a1pa;
+               /*
+                * Attach all _lp_stripes pointers to the allocation for
+                * it which was either part of the original PAGE_SIZE
+                * allocation or the subsequent allocation in this loop.
+                */
+               stripe->pages = (void *)__a1pa;
+               stripe->scribble = stripe->pages + group_width;
+               stripe->page_is_read = (char *)stripe->scribble + group_width;
+               __a1pa += sizeof__a1pa;
        }
 
        sp2d->parity = parity;
index 719a3152da80589a858c89b5260331246fce70bf..41cf2fbee50da4cb9ec0999a967d7d777fb7fc45 100644 (file)
@@ -549,27 +549,26 @@ static int exofs_devs_2_odi(struct exofs_dt_device_info *dt_dev,
 static int __alloc_dev_table(struct exofs_sb_info *sbi, unsigned numdevs,
                      struct exofs_dev **peds)
 {
-       struct __alloc_ore_devs_and_exofs_devs {
-               /* Twice bigger table: See exofs_init_comps() and comment at
-                * exofs_read_lookup_dev_table()
-                */
-               struct ore_dev *oreds[numdevs * 2 - 1];
-               struct exofs_dev eds[numdevs];
-       } *aoded;
+       /* Twice bigger table: See exofs_init_comps() and comment at
+        * exofs_read_lookup_dev_table()
+        */
+       const size_t numores = numdevs * 2 - 1;
        struct exofs_dev *eds;
        unsigned i;
 
-       aoded = kzalloc(sizeof(*aoded), GFP_KERNEL);
-       if (unlikely(!aoded)) {
+       sbi->oc.ods = kzalloc(numores * sizeof(struct ore_dev *) +
+                             numdevs * sizeof(struct exofs_dev), GFP_KERNEL);
+       if (unlikely(!sbi->oc.ods)) {
                EXOFS_ERR("ERROR: failed allocating Device array[%d]\n",
                          numdevs);
                return -ENOMEM;
        }
 
-       sbi->oc.ods = aoded->oreds;
-       *peds = eds = aoded->eds;
+       /* Start of allocated struct exofs_dev entries */
+       *peds = eds = (void *)sbi->oc.ods[numores];
+       /* Initialize pointers into struct exofs_dev */
        for (i = 0; i < numdevs; ++i)
-               aoded->oreds[i] = &eds[i].ored;
+               sbi->oc.ods[i] = &eds[i].ored;
        return 0;
 }
 
index df95412915eaa7fc1df7113734dded459eab5601..0b127853c5845aef5bcfeaa9ec2485f47d7939fb 100644 (file)
@@ -817,12 +817,14 @@ static inline void ext4_decode_extra_time(struct timespec *time, __le32 extra)
        time->tv_nsec = (le32_to_cpu(extra) & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS;
 }
 
-#define EXT4_INODE_SET_XTIME(xtime, inode, raw_inode)                         \
-do {                                                                          \
-       (raw_inode)->xtime = cpu_to_le32((inode)->xtime.tv_sec);               \
-       if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra))     \
-               (raw_inode)->xtime ## _extra =                                 \
-                               ext4_encode_extra_time(&(inode)->xtime);       \
+#define EXT4_INODE_SET_XTIME(xtime, inode, raw_inode)                          \
+do {                                                                           \
+       (raw_inode)->xtime = cpu_to_le32((inode)->xtime.tv_sec);                \
+       if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra))     {\
+               struct timespec ts = timespec64_to_timespec((inode)->xtime);    \
+               (raw_inode)->xtime ## _extra =                                  \
+                               ext4_encode_extra_time(&ts);                    \
+               }                                                               \
 } while (0)
 
 #define EXT4_EINODE_SET_XTIME(xtime, einode, raw_inode)                               \
@@ -834,16 +836,20 @@ do {                                                                             \
                                ext4_encode_extra_time(&(einode)->xtime);      \
 } while (0)
 
-#define EXT4_INODE_GET_XTIME(xtime, inode, raw_inode)                         \
-do {                                                                          \
-       (inode)->xtime.tv_sec = (signed)le32_to_cpu((raw_inode)->xtime);       \
-       if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra))     \
-               ext4_decode_extra_time(&(inode)->xtime,                        \
-                                      raw_inode->xtime ## _extra);            \
-       else                                                                   \
-               (inode)->xtime.tv_nsec = 0;                                    \
+#define EXT4_INODE_GET_XTIME(xtime, inode, raw_inode)                          \
+do {                                                                           \
+       (inode)->xtime.tv_sec = (signed)le32_to_cpu((raw_inode)->xtime);        \
+       if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra)) {    \
+               struct timespec ts = timespec64_to_timespec((inode)->xtime);    \
+               ext4_decode_extra_time(&ts,                                     \
+                                      raw_inode->xtime ## _extra);             \
+               (inode)->xtime = timespec_to_timespec64(ts);                    \
+               }                                                               \
+       else                                                                    \
+               (inode)->xtime.tv_nsec = 0;                                     \
 } while (0)
 
+
 #define EXT4_EINODE_GET_XTIME(xtime, einode, raw_inode)                               \
 do {                                                                          \
        if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime))                      \
index 4d6e007f3569a5440398e2c0f5e88fc1fea7225e..f525f909b559c8c12e361f0750b56717a972ffb1 100644 (file)
@@ -1072,8 +1072,8 @@ got:
        inode->i_ino = ino + group * EXT4_INODES_PER_GROUP(sb);
        /* This is the optimal IO size (for stat), not the fs block size */
        inode->i_blocks = 0;
-       inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime =
-                                                      current_time(inode);
+       inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
+       ei->i_crtime = timespec64_to_timespec(inode->i_mtime);
 
        memset(ei->i_data, 0, sizeof(ei->i_data));
        ei->i_dir_start_lookup = 0;
index 4a09063ce1d215492c313a2ce54a10418cf63d8b..2a4c25c4681da5fac6f61edc848ce45ee2e42218 100644 (file)
@@ -3673,7 +3673,7 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
        };
        u8 new_file_type;
        int retval;
-       struct timespec ctime;
+       struct timespec64 ctime;
 
        if ((ext4_test_inode_flag(new_dir, EXT4_INODE_PROJINHERIT) &&
             !projid_eq(EXT4_I(new_dir)->i_projid,
index 4c09e770a0a3bf6d8ef8f8e79d0582e5df05306d..4d8b1de831439ae8b6e4c493a388ef5045224225 100644 (file)
@@ -2518,6 +2518,7 @@ static inline void clear_file(struct inode *inode, int type)
 
 static inline bool f2fs_skip_inode_update(struct inode *inode, int dsync)
 {
+       struct timespec ts;
        bool ret;
 
        if (dsync) {
@@ -2533,11 +2534,14 @@ static inline bool f2fs_skip_inode_update(struct inode *inode, int dsync)
                        i_size_read(inode) & ~PAGE_MASK)
                return false;
 
-       if (!timespec_equal(F2FS_I(inode)->i_disk_time, &inode->i_atime))
+       ts = timespec64_to_timespec(inode->i_atime);
+       if (!timespec_equal(F2FS_I(inode)->i_disk_time, &ts))
                return false;
-       if (!timespec_equal(F2FS_I(inode)->i_disk_time + 1, &inode->i_ctime))
+       ts = timespec64_to_timespec(inode->i_ctime);
+       if (!timespec_equal(F2FS_I(inode)->i_disk_time + 1, &ts))
                return false;
-       if (!timespec_equal(F2FS_I(inode)->i_disk_time + 2, &inode->i_mtime))
+       ts = timespec64_to_timespec(inode->i_mtime);
+       if (!timespec_equal(F2FS_I(inode)->i_disk_time + 2, &ts))
                return false;
        if (!timespec_equal(F2FS_I(inode)->i_disk_time + 3,
                                                &F2FS_I(inode)->i_crtime))
index cadb425c02d7a9d7c851c56dfd5468795dfb491a..6880c6f78d58d0670bf28863d53de0c1e6afb3b0 100644 (file)
@@ -730,14 +730,14 @@ static void __setattr_copy(struct inode *inode, const struct iattr *attr)
        if (ia_valid & ATTR_GID)
                inode->i_gid = attr->ia_gid;
        if (ia_valid & ATTR_ATIME)
-               inode->i_atime = timespec_trunc(attr->ia_atime,
-                                               inode->i_sb->s_time_gran);
+               inode->i_atime = timespec64_trunc(attr->ia_atime,
+                                                 inode->i_sb->s_time_gran);
        if (ia_valid & ATTR_MTIME)
-               inode->i_mtime = timespec_trunc(attr->ia_mtime,
-                                               inode->i_sb->s_time_gran);
+               inode->i_mtime = timespec64_trunc(attr->ia_mtime,
+                                                 inode->i_sb->s_time_gran);
        if (ia_valid & ATTR_CTIME)
-               inode->i_ctime = timespec_trunc(attr->ia_ctime,
-                                               inode->i_sb->s_time_gran);
+               inode->i_ctime = timespec64_trunc(attr->ia_ctime,
+                                                 inode->i_sb->s_time_gran);
        if (ia_valid & ATTR_MODE) {
                umode_t mode = attr->ia_mode;
 
index 30a777369d2b905a34117ab0e9cdede3e9b951ac..f121c864f4c0d9cfe5f7c6601d23b8af4fe88501 100644 (file)
@@ -297,9 +297,9 @@ static int do_read_inode(struct inode *inode)
                fi->i_crtime.tv_nsec = le32_to_cpu(ri->i_crtime_nsec);
        }
 
-       F2FS_I(inode)->i_disk_time[0] = inode->i_atime;
-       F2FS_I(inode)->i_disk_time[1] = inode->i_ctime;
-       F2FS_I(inode)->i_disk_time[2] = inode->i_mtime;
+       F2FS_I(inode)->i_disk_time[0] = timespec64_to_timespec(inode->i_atime);
+       F2FS_I(inode)->i_disk_time[1] = timespec64_to_timespec(inode->i_ctime);
+       F2FS_I(inode)->i_disk_time[2] = timespec64_to_timespec(inode->i_mtime);
        F2FS_I(inode)->i_disk_time[3] = F2FS_I(inode)->i_crtime;
        f2fs_put_page(node_page, 1);
 
@@ -470,9 +470,9 @@ void f2fs_update_inode(struct inode *inode, struct page *node_page)
        if (inode->i_nlink == 0)
                clear_inline_node(node_page);
 
-       F2FS_I(inode)->i_disk_time[0] = inode->i_atime;
-       F2FS_I(inode)->i_disk_time[1] = inode->i_ctime;
-       F2FS_I(inode)->i_disk_time[2] = inode->i_mtime;
+       F2FS_I(inode)->i_disk_time[0] = timespec64_to_timespec(inode->i_atime);
+       F2FS_I(inode)->i_disk_time[1] = timespec64_to_timespec(inode->i_ctime);
+       F2FS_I(inode)->i_disk_time[2] = timespec64_to_timespec(inode->i_mtime);
        F2FS_I(inode)->i_disk_time[3] = F2FS_I(inode)->i_crtime;
 }
 
index 64050c84d353ca4ac2b2cc2e7ee4b4cbf948ad90..231b7f3ea7d3f0e27863bebf4b7886df753bf805 100644 (file)
@@ -50,8 +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 =
-                       F2FS_I(inode)->i_crtime = current_time(inode);
+       inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
+       F2FS_I(inode)->i_crtime = timespec64_to_timespec(inode->i_mtime);
        inode->i_generation = sbi->s_next_generation++;
 
        if (S_ISDIR(inode->i_mode))
index ffbbf0520d9e8f8f566cb790642fd78647767410..065dc919a0ce15963b21265f4872b007bcfc3310 100644 (file)
@@ -158,8 +158,14 @@ static inline int __fat_get_block(struct inode *inode, sector_t iblock,
        err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create, false);
        if (err)
                return err;
+       if (!phys) {
+               fat_fs_error(sb,
+                            "invalid FAT chain (i_pos %lld, last_block %llu)",
+                            MSDOS_I(inode)->i_pos,
+                            (unsigned long long)last_block);
+               return -EIO;
+       }
 
-       BUG_ON(!phys);
        BUG_ON(*max_blocks != mapped_blocks);
        set_buffer_new(bh_result);
        map_bh(bh_result, sb, phys);
@@ -502,6 +508,7 @@ static int fat_validate_dir(struct inode *dir)
 /* doesn't deal with root inode */
 int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
 {
+       struct timespec ts;
        struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
        int error;
 
@@ -552,11 +559,14 @@ int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
        inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1))
                           & ~((loff_t)sbi->cluster_size - 1)) >> 9;
 
-       fat_time_fat2unix(sbi, &inode->i_mtime, de->time, de->date, 0);
+       fat_time_fat2unix(sbi, &ts, de->time, de->date, 0);
+       inode->i_mtime = timespec_to_timespec64(ts);
        if (sbi->options.isvfat) {
-               fat_time_fat2unix(sbi, &inode->i_ctime, de->ctime,
+               fat_time_fat2unix(sbi, &ts, de->ctime,
                                  de->cdate, de->ctime_cs);
-               fat_time_fat2unix(sbi, &inode->i_atime, 0, de->adate, 0);
+               inode->i_ctime = timespec_to_timespec64(ts);
+               fat_time_fat2unix(sbi, &ts, 0, de->adate, 0);
+               inode->i_atime = timespec_to_timespec64(ts);
        } else
                inode->i_ctime = inode->i_atime = inode->i_mtime;
 
@@ -825,6 +835,7 @@ static int fat_statfs(struct dentry *dentry, struct kstatfs *buf)
 
 static int __fat_write_inode(struct inode *inode, int wait)
 {
+       struct timespec ts;
        struct super_block *sb = inode->i_sb;
        struct msdos_sb_info *sbi = MSDOS_SB(sb);
        struct buffer_head *bh;
@@ -862,13 +873,16 @@ retry:
                raw_entry->size = cpu_to_le32(inode->i_size);
        raw_entry->attr = fat_make_attrs(inode);
        fat_set_start(raw_entry, MSDOS_I(inode)->i_logstart);
-       fat_time_unix2fat(sbi, &inode->i_mtime, &raw_entry->time,
+       ts = timespec64_to_timespec(inode->i_mtime);
+       fat_time_unix2fat(sbi, &ts, &raw_entry->time,
                          &raw_entry->date, NULL);
        if (sbi->options.isvfat) {
                __le16 atime;
-               fat_time_unix2fat(sbi, &inode->i_ctime, &raw_entry->ctime,
+               ts = timespec64_to_timespec(inode->i_ctime);
+               fat_time_unix2fat(sbi, &ts, &raw_entry->ctime,
                                  &raw_entry->cdate, &raw_entry->ctime_cs);
-               fat_time_unix2fat(sbi, &inode->i_atime, &atime,
+               ts = timespec64_to_timespec(inode->i_atime);
+               fat_time_unix2fat(sbi, &ts, &atime,
                                  &raw_entry->adate, NULL);
        }
        spin_unlock(&sbi->inode_hash_lock);
index 484ce674e0cdd18b0f501391f21551684643d9f0..16a832c37d663b518432387e5826c1b957fee3d9 100644 (file)
@@ -250,7 +250,7 @@ static int msdos_add_entry(struct inode *dir, const unsigned char *name,
        if (err)
                return err;
 
-       dir->i_ctime = dir->i_mtime = *ts;
+       dir->i_ctime = dir->i_mtime = timespec_to_timespec64(*ts);
        if (IS_DIRSYNC(dir))
                (void)fat_sync_inode(dir);
        else
@@ -266,7 +266,8 @@ static int msdos_create(struct inode *dir, struct dentry *dentry, umode_t mode,
        struct super_block *sb = dir->i_sb;
        struct inode *inode = NULL;
        struct fat_slot_info sinfo;
-       struct timespec ts;
+       struct timespec64 ts;
+       struct timespec t;
        unsigned char msdos_name[MSDOS_NAME];
        int err, is_hid;
 
@@ -285,7 +286,8 @@ static int msdos_create(struct inode *dir, struct dentry *dentry, umode_t mode,
        }
 
        ts = current_time(dir);
-       err = msdos_add_entry(dir, msdos_name, 0, is_hid, 0, &ts, &sinfo);
+       t = timespec64_to_timespec(ts);
+       err = msdos_add_entry(dir, msdos_name, 0, is_hid, 0, &t, &sinfo);
        if (err)
                goto out;
        inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
@@ -344,7 +346,8 @@ static int msdos_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
        struct fat_slot_info sinfo;
        struct inode *inode;
        unsigned char msdos_name[MSDOS_NAME];
-       struct timespec ts;
+       struct timespec64 ts;
+       struct timespec t;
        int err, is_hid, cluster;
 
        mutex_lock(&MSDOS_SB(sb)->s_lock);
@@ -362,12 +365,13 @@ static int msdos_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
        }
 
        ts = current_time(dir);
-       cluster = fat_alloc_new_dir(dir, &ts);
+       t = timespec64_to_timespec(ts);
+       cluster = fat_alloc_new_dir(dir, &t);
        if (cluster < 0) {
                err = cluster;
                goto out;
        }
-       err = msdos_add_entry(dir, msdos_name, 1, is_hid, cluster, &ts, &sinfo);
+       err = msdos_add_entry(dir, msdos_name, 1, is_hid, cluster, &t, &sinfo);
        if (err)
                goto out_free;
        inc_nlink(dir);
@@ -432,7 +436,7 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
        struct msdos_dir_entry *dotdot_de;
        struct inode *old_inode, *new_inode;
        struct fat_slot_info old_sinfo, sinfo;
-       struct timespec ts;
+       struct timespec64 ts;
        loff_t new_i_pos;
        int err, old_attrs, is_dir, update_dotdot, corrupt = 0;
 
@@ -499,8 +503,9 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
                new_i_pos = MSDOS_I(new_inode)->i_pos;
                fat_detach(new_inode);
        } else {
+               struct timespec t = timespec64_to_timespec(ts);
                err = msdos_add_entry(new_dir, new_name, is_dir, is_hid, 0,
-                                     &ts, &sinfo);
+                                     &t, &sinfo);
                if (err)
                        goto out;
                new_i_pos = sinfo.i_pos;
index d4e23f8ddcf6e30f065a9417da16e4c0cfcba4ca..9a5469120caaf4dc6adafc7560da2fb13ffd009b 100644 (file)
@@ -678,7 +678,7 @@ static int vfat_add_entry(struct inode *dir, const struct qstr *qname,
                goto cleanup;
 
        /* update timestamp */
-       dir->i_ctime = dir->i_mtime = dir->i_atime = *ts;
+       dir->i_ctime = dir->i_mtime = dir->i_atime = timespec_to_timespec64(*ts);
        if (IS_DIRSYNC(dir))
                (void)fat_sync_inode(dir);
        else
@@ -761,13 +761,15 @@ static int vfat_create(struct inode *dir, struct dentry *dentry, umode_t mode,
        struct super_block *sb = dir->i_sb;
        struct inode *inode;
        struct fat_slot_info sinfo;
-       struct timespec ts;
+       struct timespec64 ts;
+       struct timespec t;
        int err;
 
        mutex_lock(&MSDOS_SB(sb)->s_lock);
 
        ts = current_time(dir);
-       err = vfat_add_entry(dir, &dentry->d_name, 0, 0, &ts, &sinfo);
+       t = timespec64_to_timespec(ts);
+       err = vfat_add_entry(dir, &dentry->d_name, 0, 0, &t, &sinfo);
        if (err)
                goto out;
        inode_inc_iversion(dir);
@@ -850,18 +852,20 @@ static int vfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
        struct super_block *sb = dir->i_sb;
        struct inode *inode;
        struct fat_slot_info sinfo;
-       struct timespec ts;
+       struct timespec64 ts;
+       struct timespec t;
        int err, cluster;
 
        mutex_lock(&MSDOS_SB(sb)->s_lock);
 
        ts = current_time(dir);
-       cluster = fat_alloc_new_dir(dir, &ts);
+       t = timespec64_to_timespec(ts);
+       cluster = fat_alloc_new_dir(dir, &t);
        if (cluster < 0) {
                err = cluster;
                goto out;
        }
-       err = vfat_add_entry(dir, &dentry->d_name, 1, cluster, &ts, &sinfo);
+       err = vfat_add_entry(dir, &dentry->d_name, 1, cluster, &t, &sinfo);
        if (err)
                goto out_free;
        inode_inc_iversion(dir);
@@ -899,7 +903,8 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
        struct msdos_dir_entry *dotdot_de;
        struct inode *old_inode, *new_inode;
        struct fat_slot_info old_sinfo, sinfo;
-       struct timespec ts;
+       struct timespec64 ts;
+       struct timespec t;
        loff_t new_i_pos;
        int err, is_dir, update_dotdot, corrupt = 0;
        struct super_block *sb = old_dir->i_sb;
@@ -934,8 +939,9 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
                new_i_pos = MSDOS_I(new_inode)->i_pos;
                fat_detach(new_inode);
        } else {
+               t = timespec64_to_timespec(ts);
                err = vfat_add_entry(new_dir, &new_dentry->d_name, is_dir, 0,
-                                    &ts, &sinfo);
+                                    &t, &sinfo);
                if (err)
                        goto out;
                new_i_pos = sinfo.i_pos;
index ffcaf98044b9aeb81292532a838133c518ca6d73..a24df8861b40d2148e51b98f2503c5c846f9d7ea 100644 (file)
@@ -217,7 +217,7 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
                return;
        }
 
-       old_mtime = inode->i_mtime;
+       old_mtime = timespec64_to_timespec(inode->i_mtime);
        fuse_change_attributes_common(inode, attr, attr_valid);
 
        oldsize = inode->i_size;
index 3090c445e8fc845ea4c343c4468577920d8f159f..d97ad89955d1419f4bb88eb5c86c4e6daecb284c 100644 (file)
@@ -871,7 +871,7 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh,
        struct buffer_head *bh;
        struct gfs2_leaf *leaf;
        struct gfs2_dirent *dent;
-       struct timespec tv = current_time(inode);
+       struct timespec64 tv = current_time(inode);
 
        error = gfs2_alloc_blocks(ip, &bn, &n, 0, NULL);
        if (error)
@@ -1802,7 +1802,7 @@ int gfs2_dir_add(struct inode *inode, const struct qstr *name,
        struct gfs2_inode *ip = GFS2_I(inode);
        struct buffer_head *bh = da->bh;
        struct gfs2_dirent *dent = da->dent;
-       struct timespec tv;
+       struct timespec64 tv;
        struct gfs2_leaf *leaf;
        int error;
 
@@ -1880,7 +1880,7 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry)
        const struct qstr *name = &dentry->d_name;
        struct gfs2_dirent *dent, *prev = NULL;
        struct buffer_head *bh;
-       struct timespec tv = current_time(&dip->i_inode);
+       struct timespec64 tv = current_time(&dip->i_inode);
 
        /* Returns _either_ the entry (if its first in block) or the
           previous entry otherwise */
index d8782a7a1e7dd250aa332c21c8d9b479fa11b317..c63bee9adb6a8e175d8e2cfc78abe197264acf5e 100644 (file)
@@ -338,7 +338,7 @@ static int inode_go_demote_ok(const struct gfs2_glock *gl)
 static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
 {
        const struct gfs2_dinode *str = buf;
-       struct timespec atime;
+       struct timespec64 atime;
        u16 height, depth;
 
        if (unlikely(ip->i_no_addr != be64_to_cpu(str->di_num.no_addr)))
@@ -361,7 +361,7 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
        gfs2_set_inode_blocks(&ip->i_inode, be64_to_cpu(str->di_blocks));
        atime.tv_sec = be64_to_cpu(str->di_atime);
        atime.tv_nsec = be32_to_cpu(str->di_atime_nsec);
-       if (timespec_compare(&ip->i_inode.i_atime, &atime) < 0)
+       if (timespec64_compare(&ip->i_inode.i_atime, &atime) < 0)
                ip->i_inode.i_atime = atime;
        ip->i_inode.i_mtime.tv_sec = be64_to_cpu(str->di_mtime);
        ip->i_inode.i_mtime.tv_nsec = be32_to_cpu(str->di_mtime_nsec);
index b3309b83371a24232459a518d90b2537f7a3b06b..2a16111d312fcaded7e265d294031035b63a9a3a 100644 (file)
@@ -351,7 +351,7 @@ static int hfs_read_inode(struct inode *inode, void *data)
                inode->i_mode &= ~hsb->s_file_umask;
                inode->i_mode |= S_IFREG;
                inode->i_ctime = inode->i_atime = inode->i_mtime =
-                               hfs_m_to_utime(rec->file.MdDat);
+                               timespec_to_timespec64(hfs_m_to_utime(rec->file.MdDat));
                inode->i_op = &hfs_file_inode_operations;
                inode->i_fop = &hfs_file_operations;
                inode->i_mapping->a_ops = &hfs_aops;
@@ -362,7 +362,7 @@ static int hfs_read_inode(struct inode *inode, void *data)
                HFS_I(inode)->fs_blocks = 0;
                inode->i_mode = S_IFDIR | (S_IRWXUGO & ~hsb->s_dir_umask);
                inode->i_ctime = inode->i_atime = inode->i_mtime =
-                               hfs_m_to_utime(rec->dir.MdDat);
+                               timespec_to_timespec64(hfs_m_to_utime(rec->dir.MdDat));
                inode->i_op = &hfs_dir_inode_operations;
                inode->i_fop = &hfs_dir_operations;
                break;
index c0c8d433864f15cc97ee9aead06298dab27443b5..c824f702feec438eb1cbd59aa721ba19ea280a25 100644 (file)
@@ -493,9 +493,9 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
                hfsplus_get_perms(inode, &folder->permissions, 1);
                set_nlink(inode, 1);
                inode->i_size = 2 + be32_to_cpu(folder->valence);
-               inode->i_atime = hfsp_mt2ut(folder->access_date);
-               inode->i_mtime = hfsp_mt2ut(folder->content_mod_date);
-               inode->i_ctime = hfsp_mt2ut(folder->attribute_mod_date);
+               inode->i_atime = timespec_to_timespec64(hfsp_mt2ut(folder->access_date));
+               inode->i_mtime = timespec_to_timespec64(hfsp_mt2ut(folder->content_mod_date));
+               inode->i_ctime = timespec_to_timespec64(hfsp_mt2ut(folder->attribute_mod_date));
                HFSPLUS_I(inode)->create_date = folder->create_date;
                HFSPLUS_I(inode)->fs_blocks = 0;
                if (folder->flags & cpu_to_be16(HFSPLUS_HAS_FOLDER_COUNT)) {
@@ -531,9 +531,9 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
                        init_special_inode(inode, inode->i_mode,
                                           be32_to_cpu(file->permissions.dev));
                }
-               inode->i_atime = hfsp_mt2ut(file->access_date);
-               inode->i_mtime = hfsp_mt2ut(file->content_mod_date);
-               inode->i_ctime = hfsp_mt2ut(file->attribute_mod_date);
+               inode->i_atime = timespec_to_timespec64(hfsp_mt2ut(file->access_date));
+               inode->i_mtime = timespec_to_timespec64(hfsp_mt2ut(file->content_mod_date));
+               inode->i_ctime = timespec_to_timespec64(hfsp_mt2ut(file->attribute_mod_date));
                HFSPLUS_I(inode)->create_date = file->create_date;
        } else {
                pr_err("bad catalog entry used to create inode\n");
index 3cd85eb5bbb124b77dfbbd105abce405d7b66f80..2597b290c2a596c0853761a1f7f776f38ddfbfa0 100644 (file)
@@ -555,9 +555,9 @@ static int read_name(struct inode *ino, char *name)
        set_nlink(ino, st.nlink);
        i_uid_write(ino, st.uid);
        i_gid_write(ino, st.gid);
-       ino->i_atime = st.atime;
-       ino->i_mtime = st.mtime;
-       ino->i_ctime = st.ctime;
+       ino->i_atime = timespec_to_timespec64(st.atime);
+       ino->i_mtime = timespec_to_timespec64(st.mtime);
+       ino->i_ctime = timespec_to_timespec64(st.ctime);
        ino->i_size = st.size;
        ino->i_blocks = st.blocks;
        return 0;
@@ -838,15 +838,15 @@ static int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
        }
        if (attr->ia_valid & ATTR_ATIME) {
                attrs.ia_valid |= HOSTFS_ATTR_ATIME;
-               attrs.ia_atime = attr->ia_atime;
+               attrs.ia_atime = timespec64_to_timespec(attr->ia_atime);
        }
        if (attr->ia_valid & ATTR_MTIME) {
                attrs.ia_valid |= HOSTFS_ATTR_MTIME;
-               attrs.ia_mtime = attr->ia_mtime;
+               attrs.ia_mtime = timespec64_to_timespec(attr->ia_mtime);
        }
        if (attr->ia_valid & ATTR_CTIME) {
                attrs.ia_valid |= HOSTFS_ATTR_CTIME;
-               attrs.ia_ctime = attr->ia_ctime;
+               attrs.ia_ctime = timespec64_to_timespec(attr->ia_ctime);
        }
        if (attr->ia_valid & ATTR_ATIME_SET) {
                attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
index 0df41bb77e0f426bde8901b3124071bf89701da0..2c300e98179607ea0062a2c1dbcee17e9bc926c4 100644 (file)
@@ -1577,8 +1577,8 @@ static void update_ovl_inode_times(struct dentry *dentry, struct inode *inode,
        if (upperdentry) {
                struct inode *realinode = d_inode(upperdentry);
 
-               if ((!timespec_equal(&inode->i_mtime, &realinode->i_mtime) ||
-                    !timespec_equal(&inode->i_ctime, &realinode->i_ctime))) {
+               if ((!timespec64_equal(&inode->i_mtime, &realinode->i_mtime) ||
+                    !timespec64_equal(&inode->i_ctime, &realinode->i_ctime))) {
                        inode->i_mtime = realinode->i_mtime;
                        inode->i_ctime = realinode->i_ctime;
                }
@@ -1601,12 +1601,12 @@ static int relatime_need_update(const struct path *path, struct inode *inode,
        /*
         * Is mtime younger than atime? If yes, update atime:
         */
-       if (timespec_compare(&inode->i_mtime, &inode->i_atime) >= 0)
+       if (timespec64_compare(&inode->i_mtime, &inode->i_atime) >= 0)
                return 1;
        /*
         * Is ctime younger than atime? If yes, update atime:
         */
-       if (timespec_compare(&inode->i_ctime, &inode->i_atime) >= 0)
+       if (timespec64_compare(&inode->i_ctime, &inode->i_atime) >= 0)
                return 1;
 
        /*
@@ -1621,7 +1621,7 @@ static int relatime_need_update(const struct path *path, struct inode *inode,
        return 0;
 }
 
-int generic_update_time(struct inode *inode, struct timespec *time, int flags)
+int generic_update_time(struct inode *inode, struct timespec64 *time, int flags)
 {
        int iflags = I_DIRTY_TIME;
        bool dirty = false;
@@ -1649,9 +1649,9 @@ EXPORT_SYMBOL(generic_update_time);
  * This does the actual work of updating an inodes time or version.  Must have
  * had called mnt_want_write() before calling this.
  */
-static int update_time(struct inode *inode, struct timespec *time, int flags)
+static int update_time(struct inode *inode, struct timespec64 *time, int flags)
 {
-       int (*update_time)(struct inode *, struct timespec *, int);
+       int (*update_time)(struct inode *, struct timespec64 *, int);
 
        update_time = inode->i_op->update_time ? inode->i_op->update_time :
                generic_update_time;
@@ -1672,7 +1672,7 @@ bool __atime_needs_update(const struct path *path, struct inode *inode,
                          bool rcu)
 {
        struct vfsmount *mnt = path->mnt;
-       struct timespec now;
+       struct timespec64 now;
 
        if (inode->i_flags & S_NOATIME)
                return false;
@@ -1695,10 +1695,10 @@ bool __atime_needs_update(const struct path *path, struct inode *inode,
 
        now = current_time(inode);
 
-       if (!relatime_need_update(path, inode, now, rcu))
+       if (!relatime_need_update(path, inode, timespec64_to_timespec(now), rcu))
                return false;
 
-       if (timespec_equal(&inode->i_atime, &now))
+       if (timespec64_equal(&inode->i_atime, &now))
                return false;
 
        return true;
@@ -1708,7 +1708,7 @@ void touch_atime(const struct path *path)
 {
        struct vfsmount *mnt = path->mnt;
        struct inode *inode = d_inode(path->dentry);
-       struct timespec now;
+       struct timespec64 now;
 
        if (!__atime_needs_update(path, inode, false))
                return;
@@ -1842,7 +1842,7 @@ EXPORT_SYMBOL(file_remove_privs);
 int file_update_time(struct file *file)
 {
        struct inode *inode = file_inode(file);
-       struct timespec now;
+       struct timespec64 now;
        int sync_it = 0;
        int ret;
 
@@ -1851,10 +1851,10 @@ int file_update_time(struct file *file)
                return 0;
 
        now = current_time(inode);
-       if (!timespec_equal(&inode->i_mtime, &now))
+       if (!timespec64_equal(&inode->i_mtime, &now))
                sync_it = S_MTIME;
 
-       if (!timespec_equal(&inode->i_ctime, &now))
+       if (!timespec64_equal(&inode->i_ctime, &now))
                sync_it |= S_CTIME;
 
        if (IS_I_VERSION(inode) && inode_iversion_need_inc(inode))
@@ -2097,6 +2097,30 @@ void inode_nohighmem(struct inode *inode)
 }
 EXPORT_SYMBOL(inode_nohighmem);
 
+/**
+ * timespec64_trunc - Truncate timespec64 to a granularity
+ * @t: Timespec64
+ * @gran: Granularity in ns.
+ *
+ * Truncate a timespec64 to a granularity. Always rounds down. gran must
+ * not be 0 nor greater than a second (NSEC_PER_SEC, or 10^9 ns).
+ */
+struct timespec64 timespec64_trunc(struct timespec64 t, unsigned gran)
+{
+       /* Avoid division in the common cases 1 ns and 1 s. */
+       if (gran == 1) {
+               /* nothing */
+       } else if (gran == NSEC_PER_SEC) {
+               t.tv_nsec = 0;
+       } else if (gran > 1 && gran < NSEC_PER_SEC) {
+               t.tv_nsec -= t.tv_nsec % gran;
+       } else {
+               WARN(1, "illegal file time granularity: %u", gran);
+       }
+       return t;
+}
+EXPORT_SYMBOL(timespec64_trunc);
+
 /**
  * current_time - Return FS time
  * @inode: inode.
@@ -2107,15 +2131,15 @@ EXPORT_SYMBOL(inode_nohighmem);
  * Note that inode and inode->sb cannot be NULL.
  * Otherwise, the function warns and returns time without truncation.
  */
-struct timespec current_time(struct inode *inode)
+struct timespec64 current_time(struct inode *inode)
 {
-       struct timespec now = current_kernel_time();
+       struct timespec64 now = current_kernel_time64();
 
        if (unlikely(!inode->i_sb)) {
                WARN(1, "current_time() called with uninitialized super_block in the inode");
                return now;
        }
 
-       return timespec_trunc(now, inode->i_sb->s_time_gran);
+       return timespec64_trunc(now, inode->i_sb->s_time_gran);
 }
 EXPORT_SYMBOL(current_time);
index e5a6deb38e1e1be47803250b3de5d115ce5c7e88..b2944f9218f79df0e1b43b3342cf17657784c4d5 100644 (file)
@@ -201,7 +201,7 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry,
        if (ret)
                goto fail;
 
-       dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(ri->ctime));
+       dir_i->i_mtime = dir_i->i_ctime = timespec_to_timespec64(ITIME(je32_to_cpu(ri->ctime)));
 
        jffs2_free_raw_inode(ri);
 
@@ -234,7 +234,7 @@ static int jffs2_unlink(struct inode *dir_i, struct dentry *dentry)
        if (dead_f->inocache)
                set_nlink(d_inode(dentry), dead_f->inocache->pino_nlink);
        if (!ret)
-               dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
+               dir_i->i_mtime = dir_i->i_ctime = timespec_to_timespec64(ITIME(now));
        return ret;
 }
 /***********************************************************************/
@@ -268,7 +268,7 @@ static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct de
                set_nlink(d_inode(old_dentry), ++f->inocache->pino_nlink);
                mutex_unlock(&f->sem);
                d_instantiate(dentry, d_inode(old_dentry));
-               dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
+               dir_i->i_mtime = dir_i->i_ctime = timespec_to_timespec64(ITIME(now));
                ihold(d_inode(old_dentry));
        }
        return ret;
@@ -418,7 +418,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
                goto fail;
        }
 
-       dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
+       dir_i->i_mtime = dir_i->i_ctime = timespec_to_timespec64(ITIME(je32_to_cpu(rd->mctime)));
 
        jffs2_free_raw_dirent(rd);
 
@@ -561,7 +561,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, umode_t mode
                goto fail;
        }
 
-       dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
+       dir_i->i_mtime = dir_i->i_ctime = timespec_to_timespec64(ITIME(je32_to_cpu(rd->mctime)));
        inc_nlink(dir_i);
 
        jffs2_free_raw_dirent(rd);
@@ -598,7 +598,7 @@ static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry)
        ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name,
                              dentry->d_name.len, f, now);
        if (!ret) {
-               dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
+               dir_i->i_mtime = dir_i->i_ctime = timespec_to_timespec64(ITIME(now));
                clear_nlink(d_inode(dentry));
                drop_nlink(dir_i);
        }
@@ -733,7 +733,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, umode_t mode
                goto fail;
        }
 
-       dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
+       dir_i->i_mtime = dir_i->i_ctime = timespec_to_timespec64(ITIME(je32_to_cpu(rd->mctime)));
 
        jffs2_free_raw_dirent(rd);
 
@@ -853,14 +853,14 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
                 * caller won't do it on its own since we are returning an error.
                 */
                d_invalidate(new_dentry);
-               new_dir_i->i_mtime = new_dir_i->i_ctime = ITIME(now);
+               new_dir_i->i_mtime = new_dir_i->i_ctime = timespec_to_timespec64(ITIME(now));
                return ret;
        }
 
        if (d_is_dir(old_dentry))
                drop_nlink(old_dir_i);
 
-       new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now);
+       new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = timespec_to_timespec64(ITIME(now));
 
        return 0;
 }
index bd0428bebe9b7787089135ddc4094800f86882a0..481afd4c2e1a4efef715b1bcd46f8e3962bb9aac 100644 (file)
@@ -308,7 +308,7 @@ static int jffs2_write_end(struct file *filp, struct address_space *mapping,
                        inode->i_size = pos + writtenlen;
                        inode->i_blocks = (inode->i_size + 511) >> 9;
 
-                       inode->i_ctime = inode->i_mtime = ITIME(je32_to_cpu(ri->ctime));
+                       inode->i_ctime = inode->i_mtime = timespec_to_timespec64(ITIME(je32_to_cpu(ri->ctime)));
                }
        }
 
index eab04eca95a3f6accd533be6b0c36fe7a92c75f1..0ecfb8ea38cd2ee7328252010a48af4db4fd194c 100644 (file)
@@ -146,9 +146,9 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
                return PTR_ERR(new_metadata);
        }
        /* It worked. Update the inode */
-       inode->i_atime = ITIME(je32_to_cpu(ri->atime));
-       inode->i_ctime = ITIME(je32_to_cpu(ri->ctime));
-       inode->i_mtime = ITIME(je32_to_cpu(ri->mtime));
+       inode->i_atime = timespec_to_timespec64(ITIME(je32_to_cpu(ri->atime)));
+       inode->i_ctime = timespec_to_timespec64(ITIME(je32_to_cpu(ri->ctime)));
+       inode->i_mtime = timespec_to_timespec64(ITIME(je32_to_cpu(ri->mtime)));
        inode->i_mode = jemode_to_cpu(ri->mode);
        i_uid_write(inode, je16_to_cpu(ri->uid));
        i_gid_write(inode, je16_to_cpu(ri->gid));
@@ -280,9 +280,9 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino)
        i_uid_write(inode, je16_to_cpu(latest_node.uid));
        i_gid_write(inode, je16_to_cpu(latest_node.gid));
        inode->i_size = je32_to_cpu(latest_node.isize);
-       inode->i_atime = ITIME(je32_to_cpu(latest_node.atime));
-       inode->i_mtime = ITIME(je32_to_cpu(latest_node.mtime));
-       inode->i_ctime = ITIME(je32_to_cpu(latest_node.ctime));
+       inode->i_atime = timespec_to_timespec64(ITIME(je32_to_cpu(latest_node.atime)));
+       inode->i_mtime = timespec_to_timespec64(ITIME(je32_to_cpu(latest_node.mtime)));
+       inode->i_ctime = timespec_to_timespec64(ITIME(je32_to_cpu(latest_node.ctime)));
 
        set_nlink(inode, f->inocache->pino_nlink);
 
index c60f3d32ee911192c0cd8dae3b7cb11c0f416411..a6797986b625a34d19e097050c58f582c177c30c 100644 (file)
@@ -491,15 +491,17 @@ static int ea_get(struct inode *inode, struct ea_buffer *ea_buf, int min_size)
        if (size > PSIZE) {
                /*
                 * To keep the rest of the code simple.  Allocate a
-                * contiguous buffer to work with
+                * contiguous buffer to work with. Make the buffer large
+                * enough to make use of the whole extent.
                 */
-               ea_buf->xattr = kmalloc(size, GFP_KERNEL);
+               ea_buf->max_size = (size + sb->s_blocksize - 1) &
+                   ~(sb->s_blocksize - 1);
+
+               ea_buf->xattr = kmalloc(ea_buf->max_size, GFP_KERNEL);
                if (ea_buf->xattr == NULL)
                        return -ENOMEM;
 
                ea_buf->flag = EA_MALLOC;
-               ea_buf->max_size = (size + sb->s_blocksize - 1) &
-                   ~(sb->s_blocksize - 1);
 
                if (ea_size == 0)
                        return 0;
index 89d1dc19340b09d4d9cd9db44ae3dfc9413bea98..d66cc077730386e811679abcecbf7efebcdf11b4 100644 (file)
@@ -779,7 +779,7 @@ int kernfs_add_one(struct kernfs_node *kn)
        ps_iattr = parent->iattr;
        if (ps_iattr) {
                struct iattr *ps_iattrs = &ps_iattr->ia_iattr;
-               ktime_get_real_ts(&ps_iattrs->ia_ctime);
+               ktime_get_real_ts64(&ps_iattrs->ia_ctime);
                ps_iattrs->ia_mtime = ps_iattrs->ia_ctime;
        }
 
@@ -1306,7 +1306,7 @@ static void __kernfs_remove(struct kernfs_node *kn)
 
                        /* update timestamps on the parent */
                        if (ps_iattr) {
-                               ktime_get_real_ts(&ps_iattr->ia_iattr.ia_ctime);
+                               ktime_get_real_ts64(&ps_iattr->ia_iattr.ia_ctime);
                                ps_iattr->ia_iattr.ia_mtime =
                                        ps_iattr->ia_iattr.ia_ctime;
                        }
index a34303981deb2cac6d39996e767b9e738d3c81df..3d73fe9d56e235f51907eac11510aabae9fc3344 100644 (file)
@@ -52,7 +52,7 @@ static struct kernfs_iattrs *kernfs_iattrs(struct kernfs_node *kn)
        iattrs->ia_uid = GLOBAL_ROOT_UID;
        iattrs->ia_gid = GLOBAL_ROOT_GID;
 
-       ktime_get_real_ts(&iattrs->ia_atime);
+       ktime_get_real_ts64(&iattrs->ia_atime);
        iattrs->ia_mtime = iattrs->ia_atime;
        iattrs->ia_ctime = iattrs->ia_atime;
 
@@ -176,9 +176,9 @@ static inline void set_inode_attr(struct inode *inode, struct iattr *iattr)
        struct super_block *sb = inode->i_sb;
        inode->i_uid = iattr->ia_uid;
        inode->i_gid = iattr->ia_gid;
-       inode->i_atime = timespec_trunc(iattr->ia_atime, sb->s_time_gran);
-       inode->i_mtime = timespec_trunc(iattr->ia_mtime, sb->s_time_gran);
-       inode->i_ctime = timespec_trunc(iattr->ia_ctime, sb->s_time_gran);
+       inode->i_atime = timespec64_trunc(iattr->ia_atime, sb->s_time_gran);
+       inode->i_mtime = timespec64_trunc(iattr->ia_mtime, sb->s_time_gran);
+       inode->i_ctime = timespec64_trunc(iattr->ia_ctime, sb->s_time_gran);
 }
 
 static void kernfs_refresh_inode(struct kernfs_node *kn, struct inode *inode)
index 05e211be86840f065c604a75cf9a914d55726a38..db7b6917d9c52d52d981efca3eb36f17149a0712 100644 (file)
@@ -1562,7 +1562,7 @@ EXPORT_SYMBOL(__break_lease);
  * exclusive leases.  The justification is that if someone has an
  * exclusive lease, then they could be modifying it.
  */
-void lease_get_mtime(struct inode *inode, struct timespec *time)
+void lease_get_mtime(struct inode *inode, struct timespec64 *time)
 {
        bool has_lease = false;
        struct file_lock_context *ctx;
index 2490ddb8bc90ca5c7dfcf406d50d374977a71846..734cef54fdf8b0cc3c4136dc3b11f6e07c5952e2 100644 (file)
@@ -2463,6 +2463,35 @@ static int lookup_one_len_common(const char *name, struct dentry *base,
        return inode_permission(base->d_inode, MAY_EXEC);
 }
 
+/**
+ * try_lookup_one_len - filesystem helper to lookup single pathname component
+ * @name:      pathname component to lookup
+ * @base:      base directory to lookup from
+ * @len:       maximum length @len should be interpreted to
+ *
+ * Look up a dentry by name in the dcache, returning NULL if it does not
+ * currently exist.  The function does not try to create a dentry.
+ *
+ * Note that this routine is purely a helper for filesystem usage and should
+ * not be called by generic code.
+ *
+ * The caller must hold base->i_mutex.
+ */
+struct dentry *try_lookup_one_len(const char *name, struct dentry *base, int len)
+{
+       struct qstr this;
+       int err;
+
+       WARN_ON_ONCE(!inode_is_locked(base->d_inode));
+
+       err = lookup_one_len_common(name, base, len, &this);
+       if (err)
+               return ERR_PTR(err);
+
+       return lookup_dcache(&this, base, 0);
+}
+EXPORT_SYMBOL(try_lookup_one_len);
+
 /**
  * lookup_one_len - filesystem helper to lookup single pathname component
  * @name:      pathname component to lookup
index ee81031cab29e3dd097e55a87a3d5c7b8824f66c..64c214fb9da67d5ba0ce6fb732a6c3df963823cf 100644 (file)
@@ -56,8 +56,8 @@ __be32 nfs4_callback_getattr(void *argp, void *resp,
        res->change_attr = delegation->change_attr;
        if (nfs_have_writebacks(inode))
                res->change_attr++;
-       res->ctime = inode->i_ctime;
-       res->mtime = inode->i_mtime;
+       res->ctime = timespec64_to_timespec(inode->i_ctime);
+       res->mtime = timespec64_to_timespec(inode->i_mtime);
        res->bitmap[0] = (FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE) &
                args->bitmap[0];
        res->bitmap[1] = (FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY) &
index 1c5d8d31fc0a9d823fa351b371713206d41dd63a..666415d13d5215c731bb1b2ab3e67e879b37c4ee 100644 (file)
@@ -88,8 +88,8 @@ enum fscache_checkaux nfs_fscache_inode_check_aux(void *cookie_netfs_data,
                return FSCACHE_CHECKAUX_OBSOLETE;
 
        memset(&auxdata, 0, sizeof(auxdata));
-       auxdata.mtime = nfsi->vfs_inode.i_mtime;
-       auxdata.ctime = nfsi->vfs_inode.i_ctime;
+       auxdata.mtime = timespec64_to_timespec(nfsi->vfs_inode.i_mtime);
+       auxdata.ctime = timespec64_to_timespec(nfsi->vfs_inode.i_ctime);
 
        if (NFS_SERVER(&nfsi->vfs_inode)->nfs_client->rpc_ops->version == 4)
                auxdata.change_attr = inode_peek_iversion_raw(&nfsi->vfs_inode);
index b55fc7920c3b6a692affefebf75b6f43cedd9b01..4dc887813c71d312fe09df36ddbbd78a0b27024a 100644 (file)
@@ -237,8 +237,8 @@ void nfs_fscache_init_inode(struct inode *inode)
                return;
 
        memset(&auxdata, 0, sizeof(auxdata));
-       auxdata.mtime = nfsi->vfs_inode.i_mtime;
-       auxdata.ctime = nfsi->vfs_inode.i_ctime;
+       auxdata.mtime = timespec64_to_timespec(nfsi->vfs_inode.i_mtime);
+       auxdata.ctime = timespec64_to_timespec(nfsi->vfs_inode.i_ctime);
 
        if (NFS_SERVER(&nfsi->vfs_inode)->nfs_client->rpc_ops->version == 4)
                auxdata.change_attr = inode_peek_iversion_raw(&nfsi->vfs_inode);
@@ -262,8 +262,8 @@ void nfs_fscache_clear_inode(struct inode *inode)
        dfprintk(FSCACHE, "NFS: clear cookie (0x%p/0x%p)\n", nfsi, cookie);
 
        memset(&auxdata, 0, sizeof(auxdata));
-       auxdata.mtime = nfsi->vfs_inode.i_mtime;
-       auxdata.ctime = nfsi->vfs_inode.i_ctime;
+       auxdata.mtime = timespec64_to_timespec(nfsi->vfs_inode.i_mtime);
+       auxdata.ctime = timespec64_to_timespec(nfsi->vfs_inode.i_ctime);
        fscache_relinquish_cookie(cookie, &auxdata, false);
        nfsi->fscache = NULL;
 }
@@ -304,8 +304,8 @@ void nfs_fscache_open_file(struct inode *inode, struct file *filp)
                return;
 
        memset(&auxdata, 0, sizeof(auxdata));
-       auxdata.mtime = nfsi->vfs_inode.i_mtime;
-       auxdata.ctime = nfsi->vfs_inode.i_ctime;
+       auxdata.mtime = timespec64_to_timespec(nfsi->vfs_inode.i_mtime);
+       auxdata.ctime = timespec64_to_timespec(nfsi->vfs_inode.i_ctime);
 
        if (inode_is_open_for_write(inode)) {
                dfprintk(FSCACHE, "NFS: nfsi 0x%p disabling cache\n", nfsi);
index 73473d9bdfa499945540eda1296719646acc8cae..b65aee481d131d00734c057cd16f4532f2898211 100644 (file)
@@ -501,15 +501,15 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st
                nfsi->read_cache_jiffies = fattr->time_start;
                nfsi->attr_gencount = fattr->gencount;
                if (fattr->valid & NFS_ATTR_FATTR_ATIME)
-                       inode->i_atime = fattr->atime;
+                       inode->i_atime = timespec_to_timespec64(fattr->atime);
                else if (nfs_server_capable(inode, NFS_CAP_ATIME))
                        nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATIME);
                if (fattr->valid & NFS_ATTR_FATTR_MTIME)
-                       inode->i_mtime = fattr->mtime;
+                       inode->i_mtime = timespec_to_timespec64(fattr->mtime);
                else if (nfs_server_capable(inode, NFS_CAP_MTIME))
                        nfs_set_cache_invalid(inode, NFS_INO_INVALID_MTIME);
                if (fattr->valid & NFS_ATTR_FATTR_CTIME)
-                       inode->i_ctime = fattr->ctime;
+                       inode->i_ctime = timespec_to_timespec64(fattr->ctime);
                else if (nfs_server_capable(inode, NFS_CAP_CTIME))
                        nfs_set_cache_invalid(inode, NFS_INO_INVALID_CTIME);
                if (fattr->valid & NFS_ATTR_FATTR_CHANGE)
@@ -694,7 +694,7 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr,
                if ((attr->ia_valid & ATTR_GID) != 0)
                        inode->i_gid = attr->ia_gid;
                if (fattr->valid & NFS_ATTR_FATTR_CTIME)
-                       inode->i_ctime = fattr->ctime;
+                       inode->i_ctime = timespec_to_timespec64(fattr->ctime);
                else
                        nfs_set_cache_invalid(inode, NFS_INO_INVALID_CHANGE
                                        | NFS_INO_INVALID_CTIME);
@@ -705,14 +705,14 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr,
                NFS_I(inode)->cache_validity &= ~(NFS_INO_INVALID_ATIME
                                | NFS_INO_INVALID_CTIME);
                if (fattr->valid & NFS_ATTR_FATTR_ATIME)
-                       inode->i_atime = fattr->atime;
+                       inode->i_atime = timespec_to_timespec64(fattr->atime);
                else if (attr->ia_valid & ATTR_ATIME_SET)
                        inode->i_atime = attr->ia_atime;
                else
                        nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATIME);
 
                if (fattr->valid & NFS_ATTR_FATTR_CTIME)
-                       inode->i_ctime = fattr->ctime;
+                       inode->i_ctime = timespec_to_timespec64(fattr->ctime);
                else
                        nfs_set_cache_invalid(inode, NFS_INO_INVALID_CHANGE
                                        | NFS_INO_INVALID_CTIME);
@@ -721,14 +721,14 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr,
                NFS_I(inode)->cache_validity &= ~(NFS_INO_INVALID_MTIME
                                | NFS_INO_INVALID_CTIME);
                if (fattr->valid & NFS_ATTR_FATTR_MTIME)
-                       inode->i_mtime = fattr->mtime;
+                       inode->i_mtime = timespec_to_timespec64(fattr->mtime);
                else if (attr->ia_valid & ATTR_MTIME_SET)
                        inode->i_mtime = attr->ia_mtime;
                else
                        nfs_set_cache_invalid(inode, NFS_INO_INVALID_MTIME);
 
                if (fattr->valid & NFS_ATTR_FATTR_CTIME)
-                       inode->i_ctime = fattr->ctime;
+                       inode->i_ctime = timespec_to_timespec64(fattr->ctime);
                else
                        nfs_set_cache_invalid(inode, NFS_INO_INVALID_CHANGE
                                        | NFS_INO_INVALID_CTIME);
@@ -1351,6 +1351,8 @@ static bool nfs_file_has_buffered_writers(struct nfs_inode *nfsi)
 
 static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 {
+       struct timespec ts;
+
        if ((fattr->valid & NFS_ATTR_FATTR_PRECHANGE)
                        && (fattr->valid & NFS_ATTR_FATTR_CHANGE)
                        && inode_eq_iversion_raw(inode, fattr->pre_change_attr)) {
@@ -1359,16 +1361,18 @@ static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                        nfs_set_cache_invalid(inode, NFS_INO_INVALID_DATA);
        }
        /* If we have atomic WCC data, we may update some attributes */
+       ts = timespec64_to_timespec(inode->i_ctime);
        if ((fattr->valid & NFS_ATTR_FATTR_PRECTIME)
                        && (fattr->valid & NFS_ATTR_FATTR_CTIME)
-                       && timespec_equal(&inode->i_ctime, &fattr->pre_ctime)) {
-               memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
+                       && timespec_equal(&ts, &fattr->pre_ctime)) {
+               inode->i_ctime = timespec_to_timespec64(fattr->ctime);
        }
 
+       ts = timespec64_to_timespec(inode->i_mtime);
        if ((fattr->valid & NFS_ATTR_FATTR_PREMTIME)
                        && (fattr->valid & NFS_ATTR_FATTR_MTIME)
-                       && timespec_equal(&inode->i_mtime, &fattr->pre_mtime)) {
-               memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
+                       && timespec_equal(&ts, &fattr->pre_mtime)) {
+               inode->i_mtime = timespec_to_timespec64(fattr->mtime);
                if (S_ISDIR(inode->i_mode))
                        nfs_set_cache_invalid(inode, NFS_INO_INVALID_DATA);
        }
@@ -1394,7 +1398,7 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
        struct nfs_inode *nfsi = NFS_I(inode);
        loff_t cur_size, new_isize;
        unsigned long invalid = 0;
-
+       struct timespec ts;
 
        if (NFS_PROTO(inode)->have_delegation(inode, FMODE_READ))
                return 0;
@@ -1411,10 +1415,12 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
                        invalid |= NFS_INO_INVALID_CHANGE
                                | NFS_INO_REVAL_PAGECACHE;
 
-               if ((fattr->valid & NFS_ATTR_FATTR_MTIME) && !timespec_equal(&inode->i_mtime, &fattr->mtime))
+               ts = timespec64_to_timespec(inode->i_mtime);
+               if ((fattr->valid & NFS_ATTR_FATTR_MTIME) && !timespec_equal(&ts, &fattr->mtime))
                        invalid |= NFS_INO_INVALID_MTIME;
 
-               if ((fattr->valid & NFS_ATTR_FATTR_CTIME) && !timespec_equal(&inode->i_ctime, &fattr->ctime))
+               ts = timespec64_to_timespec(inode->i_ctime);
+               if ((fattr->valid & NFS_ATTR_FATTR_CTIME) && !timespec_equal(&ts, &fattr->ctime))
                        invalid |= NFS_INO_INVALID_CTIME;
 
                if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
@@ -1444,7 +1450,8 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
        if ((fattr->valid & NFS_ATTR_FATTR_NLINK) && inode->i_nlink != fattr->nlink)
                invalid |= NFS_INO_INVALID_OTHER;
 
-       if ((fattr->valid & NFS_ATTR_FATTR_ATIME) && !timespec_equal(&inode->i_atime, &fattr->atime))
+       ts = timespec64_to_timespec(inode->i_atime);
+       if ((fattr->valid & NFS_ATTR_FATTR_ATIME) && !timespec_equal(&ts, &fattr->atime))
                invalid |= NFS_INO_INVALID_ATIME;
 
        if (invalid != 0)
@@ -1716,12 +1723,12 @@ int nfs_post_op_update_inode_force_wcc_locked(struct inode *inode, struct nfs_fa
        }
        if ((fattr->valid & NFS_ATTR_FATTR_CTIME) != 0 &&
                        (fattr->valid & NFS_ATTR_FATTR_PRECTIME) == 0) {
-               memcpy(&fattr->pre_ctime, &inode->i_ctime, sizeof(fattr->pre_ctime));
+               fattr->pre_ctime = timespec64_to_timespec(inode->i_ctime);
                fattr->valid |= NFS_ATTR_FATTR_PRECTIME;
        }
        if ((fattr->valid & NFS_ATTR_FATTR_MTIME) != 0 &&
                        (fattr->valid & NFS_ATTR_FATTR_PREMTIME) == 0) {
-               memcpy(&fattr->pre_mtime, &inode->i_mtime, sizeof(fattr->pre_mtime));
+               fattr->pre_mtime = timespec64_to_timespec(inode->i_mtime);
                fattr->valid |= NFS_ATTR_FATTR_PREMTIME;
        }
        if ((fattr->valid & NFS_ATTR_FATTR_SIZE) != 0 &&
@@ -1884,7 +1891,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
        }
 
        if (fattr->valid & NFS_ATTR_FATTR_MTIME) {
-               memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
+               inode->i_mtime = timespec_to_timespec64(fattr->mtime);
        } else if (server->caps & NFS_CAP_MTIME) {
                nfsi->cache_validity |= save_cache_validity &
                                (NFS_INO_INVALID_MTIME
@@ -1893,7 +1900,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
        }
 
        if (fattr->valid & NFS_ATTR_FATTR_CTIME) {
-               memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
+               inode->i_ctime = timespec_to_timespec64(fattr->ctime);
        } else if (server->caps & NFS_CAP_CTIME) {
                nfsi->cache_validity |= save_cache_validity &
                                (NFS_INO_INVALID_CTIME
@@ -1931,7 +1938,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 
 
        if (fattr->valid & NFS_ATTR_FATTR_ATIME)
-               memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime));
+               inode->i_atime = timespec_to_timespec64(fattr->atime);
        else if (server->caps & NFS_CAP_ATIME) {
                nfsi->cache_validity |= save_cache_validity &
                                (NFS_INO_INVALID_ATIME
index 85e4b4a233f9d9b3f0bcab413c92458844c558e3..350675e3ed479e11af839fcbbc9b99e1d972b068 100644 (file)
@@ -354,6 +354,7 @@ static __be32 *xdr_time_not_set(__be32 *p)
 
 static void encode_sattr(struct xdr_stream *xdr, const struct iattr *attr)
 {
+       struct timespec ts;
        __be32 *p;
 
        p = xdr_reserve_space(xdr, NFS_sattr_sz << 2);
@@ -375,17 +376,21 @@ static void encode_sattr(struct xdr_stream *xdr, const struct iattr *attr)
        else
                *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
 
-       if (attr->ia_valid & ATTR_ATIME_SET)
-               p = xdr_encode_time(p, &attr->ia_atime);
-       else if (attr->ia_valid & ATTR_ATIME)
-               p = xdr_encode_current_server_time(p, &attr->ia_atime);
-       else
+       if (attr->ia_valid & ATTR_ATIME_SET) {
+               ts = timespec64_to_timespec(attr->ia_atime);
+               p = xdr_encode_time(p, &ts);
+       } else if (attr->ia_valid & ATTR_ATIME) {
+               ts = timespec64_to_timespec(attr->ia_atime);
+               p = xdr_encode_current_server_time(p, &ts);
+       } else
                p = xdr_time_not_set(p);
-       if (attr->ia_valid & ATTR_MTIME_SET)
-               xdr_encode_time(p, &attr->ia_mtime);
-       else if (attr->ia_valid & ATTR_MTIME)
-               xdr_encode_current_server_time(p, &attr->ia_mtime);
-       else
+       if (attr->ia_valid & ATTR_MTIME_SET) {
+               ts = timespec64_to_timespec(attr->ia_atime);
+               xdr_encode_time(p, &ts);
+       } else if (attr->ia_valid & ATTR_MTIME) {
+               ts = timespec64_to_timespec(attr->ia_mtime);
+               xdr_encode_current_server_time(p, &ts);
+       } else
                xdr_time_not_set(p);
 }
 
index 09ee36dd84262971296138b9945dc843b5926645..64e4fa33d89f0e347155db74507862ec6f09fcc8 100644 (file)
@@ -561,6 +561,7 @@ static __be32 *xdr_decode_nfstime3(__be32 *p, struct timespec *timep)
  */
 static void encode_sattr3(struct xdr_stream *xdr, const struct iattr *attr)
 {
+       struct timespec ts;
        u32 nbytes;
        __be32 *p;
 
@@ -610,8 +611,10 @@ static void encode_sattr3(struct xdr_stream *xdr, const struct iattr *attr)
                *p++ = xdr_zero;
 
        if (attr->ia_valid & ATTR_ATIME_SET) {
+               struct timespec ts;
                *p++ = xdr_two;
-               p = xdr_encode_nfstime3(p, &attr->ia_atime);
+               ts = timespec64_to_timespec(attr->ia_atime);
+               p = xdr_encode_nfstime3(p, &ts);
        } else if (attr->ia_valid & ATTR_ATIME) {
                *p++ = xdr_one;
        } else
@@ -619,7 +622,8 @@ static void encode_sattr3(struct xdr_stream *xdr, const struct iattr *attr)
 
        if (attr->ia_valid & ATTR_MTIME_SET) {
                *p++ = xdr_two;
-               xdr_encode_nfstime3(p, &attr->ia_mtime);
+               ts = timespec64_to_timespec(attr->ia_mtime);
+               xdr_encode_nfstime3(p, &ts);
        } else if (attr->ia_valid & ATTR_MTIME) {
                *p = xdr_one;
        } else
index 738a7be019d2f696737ba6ccd46d04e996644c22..cd41d2577a049b489496b24a05ec2e28b959ee9d 100644 (file)
@@ -1069,6 +1069,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
                                const struct nfs_server *server,
                                const uint32_t attrmask[])
 {
+       struct timespec ts;
        char owner_name[IDMAP_NAMESZ];
        char owner_group[IDMAP_NAMESZ];
        int owner_namelen = 0;
@@ -1157,14 +1158,16 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
        if (bmval[1] & FATTR4_WORD1_TIME_ACCESS_SET) {
                if (iap->ia_valid & ATTR_ATIME_SET) {
                        *p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME);
-                       p = xdr_encode_nfstime4(p, &iap->ia_atime);
+                       ts = timespec64_to_timespec(iap->ia_atime);
+                       p = xdr_encode_nfstime4(p, &ts);
                } else
                        *p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
        }
        if (bmval[1] & FATTR4_WORD1_TIME_MODIFY_SET) {
                if (iap->ia_valid & ATTR_MTIME_SET) {
                        *p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME);
-                       p = xdr_encode_nfstime4(p, &iap->ia_mtime);
+                       ts = timespec64_to_timespec(iap->ia_mtime);
+                       p = xdr_encode_nfstime4(p, &ts);
                } else
                        *p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
        }
index 77ccaad1399bfea610fd7c8a533f931326218577..4fb1f72a25fb3de83d2d3c5c8e38dff4ec4eac20 100644 (file)
@@ -121,13 +121,15 @@ nfsd4_block_commit_blocks(struct inode *inode, struct nfsd4_layoutcommit *lcp,
 {
        loff_t new_size = lcp->lc_last_wr + 1;
        struct iattr iattr = { .ia_valid = 0 };
+       struct timespec ts;
        int error;
 
+       ts = timespec64_to_timespec(inode->i_mtime);
        if (lcp->lc_mtime.tv_nsec == UTIME_NOW ||
-           timespec_compare(&lcp->lc_mtime, &inode->i_mtime) < 0)
-               lcp->lc_mtime = current_time(inode);
+           timespec_compare(&lcp->lc_mtime, &ts) < 0)
+               lcp->lc_mtime = timespec64_to_timespec(current_time(inode));
        iattr.ia_valid |= ATTR_ATIME | ATTR_CTIME | ATTR_MTIME;
-       iattr.ia_atime = iattr.ia_ctime = iattr.ia_mtime = lcp->lc_mtime;
+       iattr.ia_atime = iattr.ia_ctime = iattr.ia_mtime = timespec_to_timespec64(lcp->lc_mtime);
 
        if (new_size > i_size_read(inode)) {
                iattr.ia_valid |= ATTR_SIZE;
index 3192b544a441506567423dc3b92c0200a76b80cf..9b973f4f7d01c5f67d7042c72a1663780f8f7b42 100644 (file)
@@ -165,6 +165,7 @@ static __be32 *
 encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
              struct kstat *stat)
 {
+       struct timespec ts;
        *p++ = htonl(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]);
        *p++ = htonl((u32) (stat->mode & S_IALLUGO));
        *p++ = htonl((u32) stat->nlink);
@@ -180,9 +181,12 @@ encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
        *p++ = htonl((u32) MINOR(stat->rdev));
        p = encode_fsid(p, fhp);
        p = xdr_encode_hyper(p, stat->ino);
-       p = encode_time3(p, &stat->atime);
-       p = encode_time3(p, &stat->mtime);
-       p = encode_time3(p, &stat->ctime);
+       ts = timespec64_to_timespec(stat->atime);
+       p = encode_time3(p, &ts);
+       ts = timespec64_to_timespec(stat->mtime);
+       p = encode_time3(p, &ts);
+       ts = timespec64_to_timespec(stat->ctime);
+       p = encode_time3(p, &ts);
 
        return p;
 }
@@ -271,8 +275,8 @@ void fill_pre_wcc(struct svc_fh *fhp)
                stat.size  = inode->i_size;
        }
 
-       fhp->fh_pre_mtime = stat.mtime;
-       fhp->fh_pre_ctime = stat.ctime;
+       fhp->fh_pre_mtime = timespec64_to_timespec(stat.mtime);
+       fhp->fh_pre_ctime = timespec64_to_timespec(stat.ctime);
        fhp->fh_pre_size  = stat.size;
        fhp->fh_pre_change = nfsd4_change_attribute(&stat, inode);
        fhp->fh_pre_saved = true;
index 59d471025949d2480e8fd7b091eb09f9eab18437..a96843c59fc146f1abb8c3a623984f29a083fefb 100644 (file)
@@ -320,6 +320,7 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
                   struct iattr *iattr, struct nfs4_acl **acl,
                   struct xdr_netobj *label, int *umask)
 {
+       struct timespec ts;
        int expected_len, len = 0;
        u32 dummy32;
        char *buf;
@@ -421,7 +422,8 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
                switch (dummy32) {
                case NFS4_SET_TO_CLIENT_TIME:
                        len += 12;
-                       status = nfsd4_decode_time(argp, &iattr->ia_atime);
+                       status = nfsd4_decode_time(argp, &ts);
+                       iattr->ia_atime = timespec_to_timespec64(ts);
                        if (status)
                                return status;
                        iattr->ia_valid |= (ATTR_ATIME | ATTR_ATIME_SET);
@@ -440,7 +442,8 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
                switch (dummy32) {
                case NFS4_SET_TO_CLIENT_TIME:
                        len += 12;
-                       status = nfsd4_decode_time(argp, &iattr->ia_mtime);
+                       status = nfsd4_decode_time(argp, &ts);
+                       iattr->ia_mtime = timespec_to_timespec64(ts);
                        if (status)
                                return status;
                        iattr->ia_valid |= (ATTR_MTIME | ATTR_MTIME_SET);
index a43e8260520af9980e8c3374781c937c9d8df3b0..6b2e8b73d36e3a4459e6b76bf057543884673a86 100644 (file)
@@ -131,7 +131,7 @@ encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
 {
        struct dentry   *dentry = fhp->fh_dentry;
        int type;
-       struct timespec time;
+       struct timespec64 time;
        u32 f;
 
        type = (stat->mode & S_IFMT);
index 63a1ca4b9deee22a786822229b8421bcdcf74e31..e2bea2ac5dfb2809ae9460edce3a58916456c9ef 100644 (file)
@@ -79,12 +79,11 @@ static void dnotify_recalc_inode_mask(struct fsnotify_mark *fsn_mark)
  */
 static int dnotify_handle_event(struct fsnotify_group *group,
                                struct inode *inode,
-                               struct fsnotify_mark *inode_mark,
-                               struct fsnotify_mark *vfsmount_mark,
                                u32 mask, const void *data, int data_type,
                                const unsigned char *file_name, u32 cookie,
                                struct fsnotify_iter_info *iter_info)
 {
+       struct fsnotify_mark *inode_mark = fsnotify_iter_inode_mark(iter_info);
        struct dnotify_mark *dn_mark;
        struct dnotify_struct *dn;
        struct dnotify_struct **prev;
@@ -95,7 +94,8 @@ static int dnotify_handle_event(struct fsnotify_group *group,
        if (!S_ISDIR(inode->i_mode))
                return 0;
 
-       BUG_ON(vfsmount_mark);
+       if (WARN_ON(fsnotify_iter_vfsmount_mark(iter_info)))
+               return 0;
 
        dn_mark = container_of(inode_mark, struct dnotify_mark, fsn_mark);
 
@@ -319,7 +319,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
                dn_mark = container_of(fsn_mark, struct dnotify_mark, fsn_mark);
                spin_lock(&fsn_mark->lock);
        } else {
-               error = fsnotify_add_mark_locked(new_fsn_mark, inode, NULL, 0);
+               error = fsnotify_add_inode_mark_locked(new_fsn_mark, inode, 0);
                if (error) {
                        mutex_unlock(&dnotify_group->mark_mutex);
                        goto out_err;
index d94e8031fe5fb8e95a168a475ad0069df3016465..f90842efea13c95390e85cb22897cadbaa376700 100644 (file)
@@ -87,17 +87,17 @@ static int fanotify_get_response(struct fsnotify_group *group,
        return ret;
 }
 
-static bool fanotify_should_send_event(struct fsnotify_mark *inode_mark,
-                                      struct fsnotify_mark *vfsmnt_mark,
-                                      u32 event_mask,
-                                      const void *data, int data_type)
+static bool fanotify_should_send_event(struct fsnotify_iter_info *iter_info,
+                                      u32 event_mask, const void *data,
+                                      int data_type)
 {
        __u32 marks_mask = 0, marks_ignored_mask = 0;
        const struct path *path = data;
+       struct fsnotify_mark *mark;
+       int type;
 
-       pr_debug("%s: inode_mark=%p vfsmnt_mark=%p mask=%x data=%p"
-                " data_type=%d\n", __func__, inode_mark, vfsmnt_mark,
-                event_mask, data, data_type);
+       pr_debug("%s: report_mask=%x mask=%x data=%p data_type=%d\n",
+                __func__, iter_info->report_mask, event_mask, data, data_type);
 
        /* if we don't have enough info to send an event to userspace say no */
        if (data_type != FSNOTIFY_EVENT_PATH)
@@ -108,20 +108,21 @@ static bool fanotify_should_send_event(struct fsnotify_mark *inode_mark,
            !d_can_lookup(path->dentry))
                return false;
 
-       /*
-        * if the event is for a child and this inode doesn't care about
-        * events on the child, don't send it!
-        */
-       if (inode_mark &&
-           (!(event_mask & FS_EVENT_ON_CHILD) ||
-            (inode_mark->mask & FS_EVENT_ON_CHILD))) {
-               marks_mask |= inode_mark->mask;
-               marks_ignored_mask |= inode_mark->ignored_mask;
-       }
+       fsnotify_foreach_obj_type(type) {
+               if (!fsnotify_iter_should_report_type(iter_info, type))
+                       continue;
+               mark = iter_info->marks[type];
+               /*
+                * if the event is for a child and this inode doesn't care about
+                * events on the child, don't send it!
+                */
+               if (type == FSNOTIFY_OBJ_TYPE_INODE &&
+                   (event_mask & FS_EVENT_ON_CHILD) &&
+                   !(mark->mask & FS_EVENT_ON_CHILD))
+                       continue;
 
-       if (vfsmnt_mark) {
-               marks_mask |= vfsmnt_mark->mask;
-               marks_ignored_mask |= vfsmnt_mark->ignored_mask;
+               marks_mask |= mark->mask;
+               marks_ignored_mask |= mark->ignored_mask;
        }
 
        if (d_is_dir(path->dentry) &&
@@ -178,8 +179,6 @@ init: __maybe_unused
 
 static int fanotify_handle_event(struct fsnotify_group *group,
                                 struct inode *inode,
-                                struct fsnotify_mark *inode_mark,
-                                struct fsnotify_mark *fanotify_mark,
                                 u32 mask, const void *data, int data_type,
                                 const unsigned char *file_name, u32 cookie,
                                 struct fsnotify_iter_info *iter_info)
@@ -199,8 +198,7 @@ static int fanotify_handle_event(struct fsnotify_group *group,
        BUILD_BUG_ON(FAN_ACCESS_PERM != FS_ACCESS_PERM);
        BUILD_BUG_ON(FAN_ONDIR != FS_ISDIR);
 
-       if (!fanotify_should_send_event(inode_mark, fanotify_mark, mask, data,
-                                       data_type))
+       if (!fanotify_should_send_event(iter_info, mask, data, data_type))
                return 0;
 
        pr_debug("%s: group=%p inode=%p mask=%x\n", __func__, group, inode,
index d478629c728beabe160468903fe59ca7500c2f77..10aac1942c9f32e537c9b102429c10340daaa323 100644 (file)
@@ -77,7 +77,7 @@ static void inotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark)
        struct inotify_inode_mark *inode_mark;
        struct inode *inode;
 
-       if (!(mark->connector->flags & FSNOTIFY_OBJ_TYPE_INODE))
+       if (mark->connector->type != FSNOTIFY_OBJ_TYPE_INODE)
                return;
 
        inode_mark = container_of(mark, struct inotify_inode_mark, fsn_mark);
@@ -116,7 +116,7 @@ static void fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark)
        if (mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)
                mflags |= FAN_MARK_IGNORED_SURV_MODIFY;
 
-       if (mark->connector->flags & FSNOTIFY_OBJ_TYPE_INODE) {
+       if (mark->connector->type == FSNOTIFY_OBJ_TYPE_INODE) {
                inode = igrab(mark->connector->inode);
                if (!inode)
                        return;
@@ -126,7 +126,7 @@ static void fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark)
                show_mark_fhandle(m, inode);
                seq_putc(m, '\n');
                iput(inode);
-       } else if (mark->connector->flags & FSNOTIFY_OBJ_TYPE_VFSMOUNT) {
+       } else if (mark->connector->type == FSNOTIFY_OBJ_TYPE_VFSMOUNT) {
                struct mount *mnt = real_mount(mark->connector->mnt);
 
                seq_printf(m, "fanotify mnt_id:%x mflags:%x mask:%x ignored_mask:%x\n",
index 613ec7e5a46582e4e2e03b1d623e9822017ddc5a..f174397b63a046f32ca24a7be30080c4ff5fe009 100644 (file)
@@ -184,8 +184,6 @@ int __fsnotify_parent(const struct path *path, struct dentry *dentry, __u32 mask
 EXPORT_SYMBOL_GPL(__fsnotify_parent);
 
 static int send_to_group(struct inode *to_tell,
-                        struct fsnotify_mark *inode_mark,
-                        struct fsnotify_mark *vfsmount_mark,
                         __u32 mask, const void *data,
                         int data_is, u32 cookie,
                         const unsigned char *file_name,
@@ -195,48 +193,45 @@ static int send_to_group(struct inode *to_tell,
        __u32 test_mask = (mask & ~FS_EVENT_ON_CHILD);
        __u32 marks_mask = 0;
        __u32 marks_ignored_mask = 0;
+       struct fsnotify_mark *mark;
+       int type;
 
-       if (unlikely(!inode_mark && !vfsmount_mark)) {
-               BUG();
+       if (WARN_ON(!iter_info->report_mask))
                return 0;
-       }
 
        /* clear ignored on inode modification */
        if (mask & FS_MODIFY) {
-               if (inode_mark &&
-                   !(inode_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY))
-                       inode_mark->ignored_mask = 0;
-               if (vfsmount_mark &&
-                   !(vfsmount_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY))
-                       vfsmount_mark->ignored_mask = 0;
-       }
-
-       /* does the inode mark tell us to do something? */
-       if (inode_mark) {
-               group = inode_mark->group;
-               marks_mask |= inode_mark->mask;
-               marks_ignored_mask |= inode_mark->ignored_mask;
+               fsnotify_foreach_obj_type(type) {
+                       if (!fsnotify_iter_should_report_type(iter_info, type))
+                               continue;
+                       mark = iter_info->marks[type];
+                       if (mark &&
+                           !(mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY))
+                               mark->ignored_mask = 0;
+               }
        }
 
-       /* does the vfsmount_mark tell us to do something? */
-       if (vfsmount_mark) {
-               group = vfsmount_mark->group;
-               marks_mask |= vfsmount_mark->mask;
-               marks_ignored_mask |= vfsmount_mark->ignored_mask;
+       fsnotify_foreach_obj_type(type) {
+               if (!fsnotify_iter_should_report_type(iter_info, type))
+                       continue;
+               mark = iter_info->marks[type];
+               /* does the object mark tell us to do something? */
+               if (mark) {
+                       group = mark->group;
+                       marks_mask |= mark->mask;
+                       marks_ignored_mask |= mark->ignored_mask;
+               }
        }
 
-       pr_debug("%s: group=%p to_tell=%p mask=%x inode_mark=%p"
-                " vfsmount_mark=%p marks_mask=%x marks_ignored_mask=%x"
+       pr_debug("%s: group=%p to_tell=%p mask=%x marks_mask=%x marks_ignored_mask=%x"
                 " data=%p data_is=%d cookie=%d\n",
-                __func__, group, to_tell, mask, inode_mark, vfsmount_mark,
-                marks_mask, marks_ignored_mask, data,
-                data_is, cookie);
+                __func__, group, to_tell, mask, marks_mask, marks_ignored_mask,
+                data, data_is, cookie);
 
        if (!(test_mask & marks_mask & ~marks_ignored_mask))
                return 0;
 
-       return group->ops->handle_event(group, to_tell, inode_mark,
-                                       vfsmount_mark, mask, data, data_is,
+       return group->ops->handle_event(group, to_tell, mask, data, data_is,
                                        file_name, cookie, iter_info);
 }
 
@@ -263,6 +258,57 @@ static struct fsnotify_mark *fsnotify_next_mark(struct fsnotify_mark *mark)
        return hlist_entry_safe(node, struct fsnotify_mark, obj_list);
 }
 
+/*
+ * iter_info is a multi head priority queue of marks.
+ * Pick a subset of marks from queue heads, all with the
+ * same group and set the report_mask for selected subset.
+ * Returns the report_mask of the selected subset.
+ */
+static unsigned int fsnotify_iter_select_report_types(
+               struct fsnotify_iter_info *iter_info)
+{
+       struct fsnotify_group *max_prio_group = NULL;
+       struct fsnotify_mark *mark;
+       int type;
+
+       /* Choose max prio group among groups of all queue heads */
+       fsnotify_foreach_obj_type(type) {
+               mark = iter_info->marks[type];
+               if (mark &&
+                   fsnotify_compare_groups(max_prio_group, mark->group) > 0)
+                       max_prio_group = mark->group;
+       }
+
+       if (!max_prio_group)
+               return 0;
+
+       /* Set the report mask for marks from same group as max prio group */
+       iter_info->report_mask = 0;
+       fsnotify_foreach_obj_type(type) {
+               mark = iter_info->marks[type];
+               if (mark &&
+                   fsnotify_compare_groups(max_prio_group, mark->group) == 0)
+                       fsnotify_iter_set_report_type(iter_info, type);
+       }
+
+       return iter_info->report_mask;
+}
+
+/*
+ * Pop from iter_info multi head queue, the marks that were iterated in the
+ * current iteration step.
+ */
+static void fsnotify_iter_next(struct fsnotify_iter_info *iter_info)
+{
+       int type;
+
+       fsnotify_foreach_obj_type(type) {
+               if (fsnotify_iter_should_report_type(iter_info, type))
+                       iter_info->marks[type] =
+                               fsnotify_next_mark(iter_info->marks[type]);
+       }
+}
+
 /*
  * This is the main call to fsnotify.  The VFS calls into hook specific functions
  * in linux/fsnotify.h.  Those functions then in turn call here.  Here will call
@@ -307,15 +353,15 @@ int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is,
 
        if ((mask & FS_MODIFY) ||
            (test_mask & to_tell->i_fsnotify_mask)) {
-               iter_info.inode_mark =
+               iter_info.marks[FSNOTIFY_OBJ_TYPE_INODE] =
                        fsnotify_first_mark(&to_tell->i_fsnotify_marks);
        }
 
        if (mnt && ((mask & FS_MODIFY) ||
                    (test_mask & mnt->mnt_fsnotify_mask))) {
-               iter_info.inode_mark =
+               iter_info.marks[FSNOTIFY_OBJ_TYPE_INODE] =
                        fsnotify_first_mark(&to_tell->i_fsnotify_marks);
-               iter_info.vfsmount_mark =
+               iter_info.marks[FSNOTIFY_OBJ_TYPE_VFSMOUNT] =
                        fsnotify_first_mark(&mnt->mnt_fsnotify_marks);
        }
 
@@ -324,32 +370,14 @@ int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is,
         * ignore masks are properly reflected for mount mark notifications.
         * That's why this traversal is so complicated...
         */
-       while (iter_info.inode_mark || iter_info.vfsmount_mark) {
-               struct fsnotify_mark *inode_mark = iter_info.inode_mark;
-               struct fsnotify_mark *vfsmount_mark = iter_info.vfsmount_mark;
-
-               if (inode_mark && vfsmount_mark) {
-                       int cmp = fsnotify_compare_groups(inode_mark->group,
-                                                         vfsmount_mark->group);
-                       if (cmp > 0)
-                               inode_mark = NULL;
-                       else if (cmp < 0)
-                               vfsmount_mark = NULL;
-               }
-
-               ret = send_to_group(to_tell, inode_mark, vfsmount_mark, mask,
-                                   data, data_is, cookie, file_name,
-                                   &iter_info);
+       while (fsnotify_iter_select_report_types(&iter_info)) {
+               ret = send_to_group(to_tell, mask, data, data_is, cookie,
+                                   file_name, &iter_info);
 
                if (ret && (mask & ALL_FSNOTIFY_PERM_EVENTS))
                        goto out;
 
-               if (inode_mark)
-                       iter_info.inode_mark =
-                               fsnotify_next_mark(iter_info.inode_mark);
-               if (vfsmount_mark)
-                       iter_info.vfsmount_mark =
-                               fsnotify_next_mark(iter_info.vfsmount_mark);
+               fsnotify_iter_next(&iter_info);
        }
        ret = 0;
 out:
index 60f365dc1408bb535a41b08a84cc059349a408e2..34515d2c4ba3902e4a8910ff5cb11fa08f6c754d 100644 (file)
@@ -9,12 +9,6 @@
 
 #include "../mount.h"
 
-struct fsnotify_iter_info {
-       struct fsnotify_mark *inode_mark;
-       struct fsnotify_mark *vfsmount_mark;
-       int srcu_idx;
-};
-
 /* destroy all events sitting in this groups notification queue */
 extern void fsnotify_flush_notify(struct fsnotify_group *group);
 
index b7a4b6a69efa97f5c698ee1c93cb0b3992d80e49..aa5468f23e45ceea0b524019d2c0968b72c02eea 100644 (file)
@@ -67,7 +67,7 @@ void fsnotify_destroy_group(struct fsnotify_group *group)
        fsnotify_group_stop_queueing(group);
 
        /* Clear all marks for this group and queue them for destruction */
-       fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_ALL_TYPES);
+       fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_ALL_TYPES_MASK);
 
        /*
         * Some marks can still be pinned when waiting for response from
index c00d2caca8948662a06bfd715187d8640c774b3b..7e4578d35b613ce97b87a53e50b2b34df0561e37 100644 (file)
@@ -25,8 +25,6 @@ extern void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark,
                                           struct fsnotify_group *group);
 extern int inotify_handle_event(struct fsnotify_group *group,
                                struct inode *inode,
-                               struct fsnotify_mark *inode_mark,
-                               struct fsnotify_mark *vfsmount_mark,
                                u32 mask, const void *data, int data_type,
                                const unsigned char *file_name, u32 cookie,
                                struct fsnotify_iter_info *iter_info);
index 40dedb37a1f3093f97ebca766c78284b4ba6385a..9ab6dde38a14c346b000716786f1552f87f85698 100644 (file)
@@ -65,12 +65,11 @@ static int inotify_merge(struct list_head *list,
 
 int inotify_handle_event(struct fsnotify_group *group,
                         struct inode *inode,
-                        struct fsnotify_mark *inode_mark,
-                        struct fsnotify_mark *vfsmount_mark,
                         u32 mask, const void *data, int data_type,
                         const unsigned char *file_name, u32 cookie,
                         struct fsnotify_iter_info *iter_info)
 {
+       struct fsnotify_mark *inode_mark = fsnotify_iter_inode_mark(iter_info);
        struct inotify_inode_mark *i_mark;
        struct inotify_event_info *event;
        struct fsnotify_event *fsn_event;
@@ -78,7 +77,8 @@ int inotify_handle_event(struct fsnotify_group *group,
        int len = 0;
        int alloc_len = sizeof(struct inotify_event_info);
 
-       BUG_ON(vfsmount_mark);
+       if (WARN_ON(fsnotify_iter_vfsmount_mark(iter_info)))
+               return 0;
 
        if ((inode_mark->mask & FS_EXCL_UNLINK) &&
            (data_type == FSNOTIFY_EVENT_PATH)) {
index ef32f36579589090535cd046ae3a193b77bb830d..1cf5b779d862dc81f9b00454d06babd8fc3acb1f 100644 (file)
@@ -485,10 +485,14 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark,
                                    struct fsnotify_group *group)
 {
        struct inotify_inode_mark *i_mark;
+       struct fsnotify_iter_info iter_info = { };
+
+       fsnotify_iter_set_report_type_mark(&iter_info, FSNOTIFY_OBJ_TYPE_INODE,
+                                          fsn_mark);
 
        /* Queue ignore event for the watch */
-       inotify_handle_event(group, NULL, fsn_mark, NULL, FS_IN_IGNORED,
-                            NULL, FSNOTIFY_EVENT_NONE, NULL, 0, NULL);
+       inotify_handle_event(group, NULL, FS_IN_IGNORED, NULL,
+                            FSNOTIFY_EVENT_NONE, NULL, 0, &iter_info);
 
        i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark);
        /* remove this mark from the idr */
@@ -578,7 +582,7 @@ static int inotify_new_watch(struct fsnotify_group *group,
        }
 
        /* we are on the idr, now get on the inode */
-       ret = fsnotify_add_mark_locked(&tmp_i_mark->fsn_mark, inode, NULL, 0);
+       ret = fsnotify_add_inode_mark_locked(&tmp_i_mark->fsn_mark, inode, 0);
        if (ret) {
                /* we failed to get on the inode, get off the idr */
                inotify_remove_from_idr(group, tmp_i_mark);
index e9191b416434e68d7794bb5dcf8784c1a402f144..61f4c5fa34c7c8129f1e76963b96422de72f4141 100644 (file)
@@ -119,9 +119,9 @@ static void __fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)
                if (mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED)
                        new_mask |= mark->mask;
        }
-       if (conn->flags & FSNOTIFY_OBJ_TYPE_INODE)
+       if (conn->type == FSNOTIFY_OBJ_TYPE_INODE)
                conn->inode->i_fsnotify_mask = new_mask;
-       else if (conn->flags & FSNOTIFY_OBJ_TYPE_VFSMOUNT)
+       else if (conn->type == FSNOTIFY_OBJ_TYPE_VFSMOUNT)
                real_mount(conn->mnt)->mnt_fsnotify_mask = new_mask;
 }
 
@@ -139,7 +139,7 @@ void fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)
        spin_lock(&conn->lock);
        __fsnotify_recalc_mask(conn);
        spin_unlock(&conn->lock);
-       if (conn->flags & FSNOTIFY_OBJ_TYPE_INODE)
+       if (conn->type == FSNOTIFY_OBJ_TYPE_INODE)
                __fsnotify_update_child_dentry_flags(conn->inode);
 }
 
@@ -166,18 +166,18 @@ static struct inode *fsnotify_detach_connector_from_object(
 {
        struct inode *inode = NULL;
 
-       if (conn->flags & FSNOTIFY_OBJ_TYPE_INODE) {
+       if (conn->type == FSNOTIFY_OBJ_TYPE_INODE) {
                inode = conn->inode;
                rcu_assign_pointer(inode->i_fsnotify_marks, NULL);
                inode->i_fsnotify_mask = 0;
                conn->inode = NULL;
-               conn->flags &= ~FSNOTIFY_OBJ_TYPE_INODE;
-       } else if (conn->flags & FSNOTIFY_OBJ_TYPE_VFSMOUNT) {
+               conn->type = FSNOTIFY_OBJ_TYPE_DETACHED;
+       } else if (conn->type == FSNOTIFY_OBJ_TYPE_VFSMOUNT) {
                rcu_assign_pointer(real_mount(conn->mnt)->mnt_fsnotify_marks,
                                   NULL);
                real_mount(conn->mnt)->mnt_fsnotify_mask = 0;
                conn->mnt = NULL;
-               conn->flags &= ~FSNOTIFY_OBJ_TYPE_VFSMOUNT;
+               conn->type = FSNOTIFY_OBJ_TYPE_DETACHED;
        }
 
        return inode;
@@ -294,12 +294,12 @@ static void fsnotify_put_mark_wake(struct fsnotify_mark *mark)
 
 bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info)
 {
-       /* This can fail if mark is being removed */
-       if (!fsnotify_get_mark_safe(iter_info->inode_mark))
-               return false;
-       if (!fsnotify_get_mark_safe(iter_info->vfsmount_mark)) {
-               fsnotify_put_mark_wake(iter_info->inode_mark);
-               return false;
+       int type;
+
+       fsnotify_foreach_obj_type(type) {
+               /* This can fail if mark is being removed */
+               if (!fsnotify_get_mark_safe(iter_info->marks[type]))
+                       goto fail;
        }
 
        /*
@@ -310,13 +310,20 @@ bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info)
        srcu_read_unlock(&fsnotify_mark_srcu, iter_info->srcu_idx);
 
        return true;
+
+fail:
+       for (type--; type >= 0; type--)
+               fsnotify_put_mark_wake(iter_info->marks[type]);
+       return false;
 }
 
 void fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info)
 {
+       int type;
+
        iter_info->srcu_idx = srcu_read_lock(&fsnotify_mark_srcu);
-       fsnotify_put_mark_wake(iter_info->inode_mark);
-       fsnotify_put_mark_wake(iter_info->vfsmount_mark);
+       fsnotify_foreach_obj_type(type)
+               fsnotify_put_mark_wake(iter_info->marks[type]);
 }
 
 /*
@@ -442,10 +449,10 @@ static int fsnotify_attach_connector_to_object(
        spin_lock_init(&conn->lock);
        INIT_HLIST_HEAD(&conn->list);
        if (inode) {
-               conn->flags = FSNOTIFY_OBJ_TYPE_INODE;
+               conn->type = FSNOTIFY_OBJ_TYPE_INODE;
                conn->inode = igrab(inode);
        } else {
-               conn->flags = FSNOTIFY_OBJ_TYPE_VFSMOUNT;
+               conn->type = FSNOTIFY_OBJ_TYPE_VFSMOUNT;
                conn->mnt = mnt;
        }
        /*
@@ -479,8 +486,7 @@ static struct fsnotify_mark_connector *fsnotify_grab_connector(
        if (!conn)
                goto out;
        spin_lock(&conn->lock);
-       if (!(conn->flags & (FSNOTIFY_OBJ_TYPE_INODE |
-                            FSNOTIFY_OBJ_TYPE_VFSMOUNT))) {
+       if (conn->type == FSNOTIFY_OBJ_TYPE_DETACHED) {
                spin_unlock(&conn->lock);
                srcu_read_unlock(&fsnotify_mark_srcu, idx);
                return NULL;
@@ -646,16 +652,16 @@ struct fsnotify_mark *fsnotify_find_mark(
        return NULL;
 }
 
-/* Clear any marks in a group with given type */
+/* Clear any marks in a group with given type mask */
 void fsnotify_clear_marks_by_group(struct fsnotify_group *group,
-                                  unsigned int type)
+                                  unsigned int type_mask)
 {
        struct fsnotify_mark *lmark, *mark;
        LIST_HEAD(to_free);
        struct list_head *head = &to_free;
 
        /* Skip selection step if we want to clear all marks. */
-       if (type == FSNOTIFY_OBJ_ALL_TYPES) {
+       if (type_mask == FSNOTIFY_OBJ_ALL_TYPES_MASK) {
                head = &group->marks_list;
                goto clear;
        }
@@ -670,7 +676,7 @@ void fsnotify_clear_marks_by_group(struct fsnotify_group *group,
         */
        mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING);
        list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) {
-               if (mark->connector->flags & type)
+               if ((1U << mark->connector->type) & type_mask)
                        list_move(&mark->g_list, &to_free);
        }
        mutex_unlock(&group->mark_mutex);
index 1c1ee489284b7028d2e373fb93aa25328bc7db64..decaf75d1cd583102aeb1ee298599888df5a2b71 100644 (file)
@@ -667,18 +667,18 @@ static int ntfs_read_locked_inode(struct inode *vi)
         * mtime is the last change of the data within the file. Not changed
         * when only metadata is changed, e.g. a rename doesn't affect mtime.
         */
-       vi->i_mtime = ntfs2utc(si->last_data_change_time);
+       vi->i_mtime = timespec_to_timespec64(ntfs2utc(si->last_data_change_time));
        /*
         * ctime is the last change of the metadata of the file. This obviously
         * always changes, when mtime is changed. ctime can be changed on its
         * own, mtime is then not changed, e.g. when a file is renamed.
         */
-       vi->i_ctime = ntfs2utc(si->last_mft_change_time);
+       vi->i_ctime = timespec_to_timespec64(ntfs2utc(si->last_mft_change_time));
        /*
         * Last access to the data within the file. Not changed during a rename
         * for example but changed whenever the file is written to.
         */
-       vi->i_atime = ntfs2utc(si->last_access_time);
+       vi->i_atime = timespec_to_timespec64(ntfs2utc(si->last_access_time));
 
        /* Find the attribute list attribute if present. */
        ntfs_attr_reinit_search_ctx(ctx);
@@ -2804,11 +2804,11 @@ done:
         * for real.
         */
        if (!IS_NOCMTIME(VFS_I(base_ni)) && !IS_RDONLY(VFS_I(base_ni))) {
-               struct timespec now = current_time(VFS_I(base_ni));
+               struct timespec64 now = current_time(VFS_I(base_ni));
                int sync_it = 0;
 
-               if (!timespec_equal(&VFS_I(base_ni)->i_mtime, &now) ||
-                   !timespec_equal(&VFS_I(base_ni)->i_ctime, &now))
+               if (!timespec64_equal(&VFS_I(base_ni)->i_mtime, &now) ||
+                   !timespec64_equal(&VFS_I(base_ni)->i_ctime, &now))
                        sync_it = 1;
                VFS_I(base_ni)->i_mtime = now;
                VFS_I(base_ni)->i_ctime = now;
@@ -2923,14 +2923,14 @@ int ntfs_setattr(struct dentry *dentry, struct iattr *attr)
                }
        }
        if (ia_valid & ATTR_ATIME)
-               vi->i_atime = timespec_trunc(attr->ia_atime,
-                               vi->i_sb->s_time_gran);
+               vi->i_atime = timespec64_trunc(attr->ia_atime,
+                                              vi->i_sb->s_time_gran);
        if (ia_valid & ATTR_MTIME)
-               vi->i_mtime = timespec_trunc(attr->ia_mtime,
-                               vi->i_sb->s_time_gran);
+               vi->i_mtime = timespec64_trunc(attr->ia_mtime,
+                                              vi->i_sb->s_time_gran);
        if (ia_valid & ATTR_CTIME)
-               vi->i_ctime = timespec_trunc(attr->ia_ctime,
-                               vi->i_sb->s_time_gran);
+               vi->i_ctime = timespec64_trunc(attr->ia_ctime,
+                                              vi->i_sb->s_time_gran);
        mark_inode_dirty(vi);
 out:
        return err;
@@ -2997,7 +2997,7 @@ int __ntfs_write_inode(struct inode *vi, int sync)
        si = (STANDARD_INFORMATION*)((u8*)ctx->attr +
                        le16_to_cpu(ctx->attr->data.resident.value_offset));
        /* Update the access times if they have changed. */
-       nt = utc2ntfs(vi->i_mtime);
+       nt = utc2ntfs(timespec64_to_timespec(vi->i_mtime));
        if (si->last_data_change_time != nt) {
                ntfs_debug("Updating mtime for inode 0x%lx: old = 0x%llx, "
                                "new = 0x%llx", vi->i_ino, (long long)
@@ -3006,7 +3006,7 @@ int __ntfs_write_inode(struct inode *vi, int sync)
                si->last_data_change_time = nt;
                modified = true;
        }
-       nt = utc2ntfs(vi->i_ctime);
+       nt = utc2ntfs(timespec64_to_timespec(vi->i_ctime));
        if (si->last_mft_change_time != nt) {
                ntfs_debug("Updating ctime for inode 0x%lx: old = 0x%llx, "
                                "new = 0x%llx", vi->i_ino, (long long)
@@ -3015,7 +3015,7 @@ int __ntfs_write_inode(struct inode *vi, int sync)
                si->last_mft_change_time = nt;
                modified = true;
        }
-       nt = utc2ntfs(vi->i_atime);
+       nt = utc2ntfs(timespec64_to_timespec(vi->i_atime));
        if (si->last_access_time != nt) {
                ntfs_debug("Updating atime for inode 0x%lx: old = 0x%llx, "
                                "new = 0x%llx", vi->i_ino,
index 68728de1286460b0ead492d5b2f773258cccc46d..0ff424c6d17c806841e9cd5f48323a7d92536407 100644 (file)
@@ -2140,6 +2140,7 @@ static void __ocfs2_stuff_meta_lvb(struct inode *inode)
        struct ocfs2_inode_info *oi = OCFS2_I(inode);
        struct ocfs2_lock_res *lockres = &oi->ip_inode_lockres;
        struct ocfs2_meta_lvb *lvb;
+       struct timespec ts;
 
        lvb = ocfs2_dlm_lvb(&lockres->l_lksb);
 
@@ -2160,12 +2161,15 @@ static void __ocfs2_stuff_meta_lvb(struct inode *inode)
        lvb->lvb_igid      = cpu_to_be32(i_gid_read(inode));
        lvb->lvb_imode     = cpu_to_be16(inode->i_mode);
        lvb->lvb_inlink    = cpu_to_be16(inode->i_nlink);
+       ts = timespec64_to_timespec(inode->i_atime);
        lvb->lvb_iatime_packed  =
-               cpu_to_be64(ocfs2_pack_timespec(&inode->i_atime));
+               cpu_to_be64(ocfs2_pack_timespec(&ts));
+       ts = timespec64_to_timespec(inode->i_ctime);
        lvb->lvb_ictime_packed =
-               cpu_to_be64(ocfs2_pack_timespec(&inode->i_ctime));
+               cpu_to_be64(ocfs2_pack_timespec(&ts));
+       ts = timespec64_to_timespec(inode->i_mtime);
        lvb->lvb_imtime_packed =
-               cpu_to_be64(ocfs2_pack_timespec(&inode->i_mtime));
+               cpu_to_be64(ocfs2_pack_timespec(&ts));
        lvb->lvb_iattr    = cpu_to_be32(oi->ip_attr);
        lvb->lvb_idynfeatures = cpu_to_be16(oi->ip_dyn_features);
        lvb->lvb_igeneration = cpu_to_be32(inode->i_generation);
@@ -2183,6 +2187,7 @@ static void ocfs2_unpack_timespec(struct timespec *spec,
 
 static void ocfs2_refresh_inode_from_lvb(struct inode *inode)
 {
+       struct timespec ts;
        struct ocfs2_inode_info *oi = OCFS2_I(inode);
        struct ocfs2_lock_res *lockres = &oi->ip_inode_lockres;
        struct ocfs2_meta_lvb *lvb;
@@ -2210,12 +2215,15 @@ static void ocfs2_refresh_inode_from_lvb(struct inode *inode)
        i_gid_write(inode, be32_to_cpu(lvb->lvb_igid));
        inode->i_mode    = be16_to_cpu(lvb->lvb_imode);
        set_nlink(inode, be16_to_cpu(lvb->lvb_inlink));
-       ocfs2_unpack_timespec(&inode->i_atime,
+       ocfs2_unpack_timespec(&ts,
                              be64_to_cpu(lvb->lvb_iatime_packed));
-       ocfs2_unpack_timespec(&inode->i_mtime,
+       inode->i_atime = timespec_to_timespec64(ts);
+       ocfs2_unpack_timespec(&ts,
                              be64_to_cpu(lvb->lvb_imtime_packed));
-       ocfs2_unpack_timespec(&inode->i_ctime,
+       inode->i_mtime = timespec_to_timespec64(ts);
+       ocfs2_unpack_timespec(&ts,
                              be64_to_cpu(lvb->lvb_ictime_packed));
+       inode->i_ctime = timespec_to_timespec64(ts);
        spin_unlock(&oi->ip_lock);
 }
 
index a2a8603d27e0c1fc8cb1f4261ebe0a3ee6c36908..255f758af03a0998dd2e233397dde23fc6740760 100644 (file)
@@ -222,7 +222,7 @@ static int ocfs2_sync_file(struct file *file, loff_t start, loff_t end,
 int ocfs2_should_update_atime(struct inode *inode,
                              struct vfsmount *vfsmnt)
 {
-       struct timespec now;
+       struct timespec64 now;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 
        if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb))
@@ -248,8 +248,8 @@ int ocfs2_should_update_atime(struct inode *inode,
                return 0;
 
        if (vfsmnt->mnt_flags & MNT_RELATIME) {
-               if ((timespec_compare(&inode->i_atime, &inode->i_mtime) <= 0) ||
-                   (timespec_compare(&inode->i_atime, &inode->i_ctime) <= 0))
+               if ((timespec64_compare(&inode->i_atime, &inode->i_mtime) <= 0) ||
+                   (timespec64_compare(&inode->i_atime, &inode->i_ctime) <= 0))
                        return 1;
 
                return 0;
index 74b37cbbd5d4a1c750a6adc1d75906a776963f9a..33ee8cb32f8314a8e3a90710a3f4bcebfa3fdb8e 100644 (file)
@@ -719,37 +719,6 @@ struct ORANGEFS_dev_map_desc32 {
        __s32 count;
 };
 
-static unsigned long translate_dev_map26(unsigned long args, long *error)
-{
-       struct ORANGEFS_dev_map_desc32 __user *p32 = (void __user *)args;
-       /*
-        * Depending on the architecture, allocate some space on the
-        * user-call-stack based on our expected layout.
-        */
-       struct ORANGEFS_dev_map_desc __user *p =
-           compat_alloc_user_space(sizeof(*p));
-       compat_uptr_t addr;
-
-       *error = 0;
-       /* get the ptr from the 32 bit user-space */
-       if (get_user(addr, &p32->ptr))
-               goto err;
-       /* try to put that into a 64-bit layout */
-       if (put_user(compat_ptr(addr), &p->ptr))
-               goto err;
-       /* copy the remaining fields */
-       if (copy_in_user(&p->total_size, &p32->total_size, sizeof(__s32)))
-               goto err;
-       if (copy_in_user(&p->size, &p32->size, sizeof(__s32)))
-               goto err;
-       if (copy_in_user(&p->count, &p32->count, sizeof(__s32)))
-               goto err;
-       return (unsigned long)p;
-err:
-       *error = -EFAULT;
-       return 0;
-}
-
 /*
  * 32 bit user-space apps' ioctl handlers when kernel modules
  * is compiled as a 64 bit one
@@ -758,25 +727,26 @@ static long orangefs_devreq_compat_ioctl(struct file *filp, unsigned int cmd,
                                      unsigned long args)
 {
        long ret;
-       unsigned long arg = args;
 
        /* Check for properly constructed commands */
        ret = check_ioctl_command(cmd);
        if (ret < 0)
                return ret;
        if (cmd == ORANGEFS_DEV_MAP) {
-               /*
-                * convert the arguments to what we expect internally
-                * in kernel space
-                */
-               arg = translate_dev_map26(args, &ret);
-               if (ret < 0) {
-                       gossip_err("Could not translate dev map\n");
-                       return ret;
-               }
+               struct ORANGEFS_dev_map_desc desc;
+               struct ORANGEFS_dev_map_desc32 d32;
+
+               if (copy_from_user(&d32, (void __user *)args, sizeof(d32)))
+                       return -EFAULT;
+
+               desc.ptr = compat_ptr(d32.ptr);
+               desc.total_size = d32.total_size;
+               desc.size = d32.size;
+               desc.count = d32.count;
+               return orangefs_bufmap_initialize(&desc);
        }
        /* no other ioctl requires translation */
-       return dispatch_ioctl_command(cmd, arg);
+       return dispatch_ioctl_command(cmd, args);
 }
 
 #endif /* CONFIG_COMPAT is in .config */
index d6db252e62003fbd7be2a50e42e85a2ee8bcdf60..6e4d2af8f5bcffee89b75d9e9672bb0ca86eb6e6 100644 (file)
@@ -297,7 +297,7 @@ int orangefs_permission(struct inode *inode, int mask)
        return generic_permission(inode, mask);
 }
 
-int orangefs_update_time(struct inode *inode, struct timespec *time, int flags)
+int orangefs_update_time(struct inode *inode, struct timespec64 *time, int flags)
 {
        struct iattr iattr;
        gossip_debug(GOSSIP_INODE_DEBUG, "orangefs_update_time: %pU\n",
index 004511617b6d76e577ae7b84620fcc0d66f63f1e..17b24ad6b264b1733e2ee081a1bb44ab85253e46 100644 (file)
@@ -342,7 +342,7 @@ int orangefs_getattr(const struct path *path, struct kstat *stat,
 
 int orangefs_permission(struct inode *inode, int mask);
 
-int orangefs_update_time(struct inode *, struct timespec *, int);
+int orangefs_update_time(struct inode *, struct timespec64 *, int);
 
 /*
  * defined in xattr.c
index 079a465796f3ef95e318b3929b83fab005f42df7..dd28079f518c0c3d09865969e854fa07952286fe 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Documentation/ABI/stable/orangefs-sysfs:
+ * Documentation/ABI/stable/sysfs-fs-orangefs:
  *
  * What:               /sys/fs/orangefs/perf_counter_reset
  * Date:               June 2015
index 1db5b3b458a19c2a45bebf0d571e4091574c2393..ed16a898caeb8d59ef3daad075c96774a7648db7 100644 (file)
@@ -416,7 +416,7 @@ int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags)
        return err;
 }
 
-int ovl_update_time(struct inode *inode, struct timespec *ts, int flags)
+int ovl_update_time(struct inode *inode, struct timespec64 *ts, int flags)
 {
        if (flags & S_ATIME) {
                struct ovl_fs *ofs = inode->i_sb->s_fs_info;
index 3c5e9f18b0d9f368025a299124def2e47f9bc4c4..7538b9b56237b46f6cb3f8ed00dc36cecd4b5c94 100644 (file)
@@ -325,7 +325,7 @@ int ovl_xattr_get(struct dentry *dentry, struct inode *inode, const char *name,
 ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size);
 struct posix_acl *ovl_get_acl(struct inode *inode, int type);
 int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags);
-int ovl_update_time(struct inode *inode, struct timespec *ts, int flags);
+int ovl_update_time(struct inode *inode, struct timespec64 *ts, int flags);
 bool ovl_is_private_xattr(const char *name);
 
 struct ovl_inode_params {
index 80aa42506b8b7fa32902d8a61a04c28172c30995..aaffc0c302162db0fc9d682c071469f55326dc1d 100644 (file)
@@ -235,6 +235,10 @@ static ssize_t get_mm_cmdline(struct mm_struct *mm, char __user *buf,
        if (env_start != arg_end || env_start >= env_end)
                env_start = env_end = arg_end;
 
+       /* .. and limit it to a maximum of one page of slop */
+       if (env_end >= arg_end + PAGE_SIZE)
+               env_end = arg_end + PAGE_SIZE - 1;
+
        /* We're not going to care if "*ppos" has high bits set */
        pos = arg_start + *ppos;
 
@@ -254,10 +258,19 @@ static ssize_t get_mm_cmdline(struct mm_struct *mm, char __user *buf,
        while (count) {
                int got;
                size_t size = min_t(size_t, PAGE_SIZE, count);
+               long offset;
 
-               got = access_remote_vm(mm, pos, page, size, FOLL_ANON);
-               if (got <= 0)
+               /*
+                * Are we already starting past the official end?
+                * We always include the last byte that is *supposed*
+                * to be NUL
+                */
+               offset = (pos >= arg_end) ? pos - arg_end + 1 : 0;
+
+               got = access_remote_vm(mm, pos - offset, page, size + offset, FOLL_ANON);
+               if (got <= offset)
                        break;
+               got -= offset;
 
                /* Don't walk past a NUL character once you hit arg_end */
                if (pos + got >= arg_end) {
@@ -276,12 +289,17 @@ static ssize_t get_mm_cmdline(struct mm_struct *mm, char __user *buf,
                                n = arg_end - pos - 1;
 
                        /* Cut off at first NUL after 'n' */
-                       got = n + strnlen(page+n, got-n);
-                       if (!got)
+                       got = n + strnlen(page+n, offset+got-n);
+                       if (got < offset)
                                break;
+                       got -= offset;
+
+                       /* Include the NUL if it existed */
+                       if (got < size)
+                               got++;
                }
 
-               got -= copy_to_user(buf, page, got);
+               got -= copy_to_user(buf, page+offset, got);
                if (unlikely(!got)) {
                        if (!len)
                                len = -EFAULT;
@@ -2439,14 +2457,11 @@ static struct dentry *proc_pident_lookup(struct inode *dir,
        for (p = ents; p < last; p++) {
                if (p->len != dentry->d_name.len)
                        continue;
-               if (!memcmp(dentry->d_name.name, p->name, p->len))
+               if (!memcmp(dentry->d_name.name, p->name, p->len)) {
+                       res = proc_pident_instantiate(dentry, task, p);
                        break;
+               }
        }
-       if (p >= last)
-               goto out;
-
-       res = proc_pident_instantiate(dentry, task, p);
-out:
        put_task_struct(task);
 out_no_task:
        return res;
index 7b4d9714f2485a5c53397bf9dc198419b8b30464..6ac1c92997ea2a20c3af8959c6920218f16a846d 100644 (file)
@@ -409,7 +409,7 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent,
        if (!ent)
                goto out;
 
-       if (qstr.len + 1 <= sizeof(ent->inline_name)) {
+       if (qstr.len + 1 <= SIZEOF_PDE_INLINE_NAME) {
                ent->name = ent->inline_name;
        } else {
                ent->name = kmalloc(qstr.len + 1, GFP_KERNEL);
@@ -740,3 +740,27 @@ void *PDE_DATA(const struct inode *inode)
        return __PDE_DATA(inode);
 }
 EXPORT_SYMBOL(PDE_DATA);
+
+/*
+ * Pull a user buffer into memory and pass it to the file's write handler if
+ * one is supplied.  The ->write() method is permitted to modify the
+ * kernel-side buffer.
+ */
+ssize_t proc_simple_write(struct file *f, const char __user *ubuf, size_t size,
+                         loff_t *_pos)
+{
+       struct proc_dir_entry *pde = PDE(file_inode(f));
+       char *buf;
+       int ret;
+
+       if (!pde->write)
+               return -EACCES;
+       if (size == 0 || size > PAGE_SIZE - 1)
+               return -EINVAL;
+       buf = memdup_user_nul(ubuf, size);
+       if (IS_ERR(buf))
+               return PTR_ERR(buf);
+       ret = pde->write(f, buf, size);
+       kfree(buf);
+       return ret == 0 ? size : ret;
+}
index 2cf3b74391ca5774a04cabe2b70e1e84ec7b3002..85ffbd27f2883a8e6fb3dfe8275c2e1a36ac3ffe 100644 (file)
@@ -105,9 +105,8 @@ void __init proc_init_kmemcache(void)
                kmem_cache_create("pde_opener", sizeof(struct pde_opener), 0,
                                  SLAB_ACCOUNT|SLAB_PANIC, NULL);
        proc_dir_entry_cache = kmem_cache_create_usercopy(
-               "proc_dir_entry", sizeof(struct proc_dir_entry), 0, SLAB_PANIC,
-               offsetof(struct proc_dir_entry, inline_name),
-               sizeof_field(struct proc_dir_entry, inline_name), NULL);
+               "proc_dir_entry", SIZEOF_PDE_SLOT, 0, SLAB_PANIC,
+               OFFSETOF_PDE_NAME, SIZEOF_PDE_INLINE_NAME, NULL);
 }
 
 static int proc_show_options(struct seq_file *seq, struct dentry *root)
index 50cb22a08c2f91224e635f8ae34b27e85761aeff..da3dbfa09e79c2f82a4f601f2eb103c00f716a23 100644 (file)
@@ -48,6 +48,7 @@ struct proc_dir_entry {
                const struct seq_operations *seq_ops;
                int (*single_show)(struct seq_file *, void *);
        };
+       proc_write_t write;
        void *data;
        unsigned int state_size;
        unsigned int low_ino;
@@ -61,14 +62,20 @@ struct proc_dir_entry {
        char *name;
        umode_t mode;
        u8 namelen;
-#ifdef CONFIG_64BIT
-#define SIZEOF_PDE_INLINE_NAME (192-155)
-#else
-#define SIZEOF_PDE_INLINE_NAME (128-95)
-#endif
-       char inline_name[SIZEOF_PDE_INLINE_NAME];
+       char inline_name[];
 } __randomize_layout;
 
+#define OFFSETOF_PDE_NAME offsetof(struct proc_dir_entry, inline_name)
+#define SIZEOF_PDE_SLOT                                        \
+       (OFFSETOF_PDE_NAME + 34 <= 64 ? 64 :            \
+        OFFSETOF_PDE_NAME + 34 <= 128 ? 128 :          \
+        OFFSETOF_PDE_NAME + 34 <= 192 ? 192 :          \
+        OFFSETOF_PDE_NAME + 34 <= 256 ? 256 :          \
+        OFFSETOF_PDE_NAME + 34 <= 512 ? 512 :          \
+        0)
+
+#define SIZEOF_PDE_INLINE_NAME (SIZEOF_PDE_SLOT - OFFSETOF_PDE_NAME)
+
 extern struct kmem_cache *proc_dir_entry_cache;
 void pde_free(struct proc_dir_entry *pde);
 
@@ -189,6 +196,7 @@ static inline bool is_empty_pde(const struct proc_dir_entry *pde)
 {
        return S_ISDIR(pde->mode) && !pde->proc_iops;
 }
+extern ssize_t proc_simple_write(struct file *, const char __user *, size_t, loff_t *);
 
 /*
  * inode.c
index 7d94fa005b0d9a85c198887ebfa8227e4c7f1262..d5e0fcb3439e91b8c722b7193c0d8a59e2ecbe98 100644 (file)
@@ -46,6 +46,9 @@ static int seq_open_net(struct inode *inode, struct file *file)
 
        WARN_ON_ONCE(state_size < sizeof(*p));
 
+       if (file->f_mode & FMODE_WRITE && !PDE(inode)->write)
+               return -EACCES;
+
        net = get_proc_net(inode);
        if (!net)
                return -ENXIO;
@@ -73,6 +76,7 @@ static int seq_release_net(struct inode *ino, struct file *f)
 static const struct file_operations proc_net_seq_fops = {
        .open           = seq_open_net,
        .read           = seq_read,
+       .write          = proc_simple_write,
        .llseek         = seq_lseek,
        .release        = seq_release_net,
 };
@@ -93,6 +97,50 @@ struct proc_dir_entry *proc_create_net_data(const char *name, umode_t mode,
 }
 EXPORT_SYMBOL_GPL(proc_create_net_data);
 
+/**
+ * proc_create_net_data_write - Create a writable net_ns-specific proc file
+ * @name: The name of the file.
+ * @mode: The file's access mode.
+ * @parent: The parent directory in which to create.
+ * @ops: The seq_file ops with which to read the file.
+ * @write: The write method which which to 'modify' the file.
+ * @data: Data for retrieval by PDE_DATA().
+ *
+ * Create a network namespaced proc file in the @parent directory with the
+ * specified @name and @mode that allows reading of a file that displays a
+ * series of elements and also provides for the file accepting writes that have
+ * some arbitrary effect.
+ *
+ * The functions in the @ops table are used to iterate over items to be
+ * presented and extract the readable content using the seq_file interface.
+ *
+ * The @write function is called with the data copied into a kernel space
+ * scratch buffer and has a NUL appended for convenience.  The buffer may be
+ * modified by the @write function.  @write should return 0 on success.
+ *
+ * The @data value is accessible from the @show and @write functions by calling
+ * PDE_DATA() on the file inode.  The network namespace must be accessed by
+ * calling seq_file_net() on the seq_file struct.
+ */
+struct proc_dir_entry *proc_create_net_data_write(const char *name, umode_t mode,
+                                                 struct proc_dir_entry *parent,
+                                                 const struct seq_operations *ops,
+                                                 proc_write_t write,
+                                                 unsigned int state_size, void *data)
+{
+       struct proc_dir_entry *p;
+
+       p = proc_create_reg(name, mode, &parent, data);
+       if (!p)
+               return NULL;
+       p->proc_fops = &proc_net_seq_fops;
+       p->seq_ops = ops;
+       p->state_size = state_size;
+       p->write = write;
+       return proc_register(parent, p);
+}
+EXPORT_SYMBOL_GPL(proc_create_net_data_write);
+
 static int single_open_net(struct inode *inode, struct file *file)
 {
        struct proc_dir_entry *de = PDE(inode);
@@ -119,6 +167,7 @@ static int single_release_net(struct inode *ino, struct file *f)
 static const struct file_operations proc_net_single_fops = {
        .open           = single_open_net,
        .read           = seq_read,
+       .write          = proc_simple_write,
        .llseek         = seq_lseek,
        .release        = single_release_net,
 };
@@ -138,6 +187,49 @@ struct proc_dir_entry *proc_create_net_single(const char *name, umode_t mode,
 }
 EXPORT_SYMBOL_GPL(proc_create_net_single);
 
+/**
+ * proc_create_net_single_write - Create a writable net_ns-specific proc file
+ * @name: The name of the file.
+ * @mode: The file's access mode.
+ * @parent: The parent directory in which to create.
+ * @show: The seqfile show method with which to read the file.
+ * @write: The write method which which to 'modify' the file.
+ * @data: Data for retrieval by PDE_DATA().
+ *
+ * Create a network-namespaced proc file in the @parent directory with the
+ * specified @name and @mode that allows reading of a file that displays a
+ * single element rather than a series and also provides for the file accepting
+ * writes that have some arbitrary effect.
+ *
+ * The @show function is called to extract the readable content via the
+ * seq_file interface.
+ *
+ * The @write function is called with the data copied into a kernel space
+ * scratch buffer and has a NUL appended for convenience.  The buffer may be
+ * modified by the @write function.  @write should return 0 on success.
+ *
+ * The @data value is accessible from the @show and @write functions by calling
+ * PDE_DATA() on the file inode.  The network namespace must be accessed by
+ * calling seq_file_single_net() on the seq_file struct.
+ */
+struct proc_dir_entry *proc_create_net_single_write(const char *name, umode_t mode,
+                                                   struct proc_dir_entry *parent,
+                                                   int (*show)(struct seq_file *, void *),
+                                                   proc_write_t write,
+                                                   void *data)
+{
+       struct proc_dir_entry *p;
+
+       p = proc_create_reg(name, mode, &parent, data);
+       if (!p)
+               return NULL;
+       p->proc_fops = &proc_net_single_fops;
+       p->single_show = show;
+       p->write = write;
+       return proc_register(parent, p);
+}
+EXPORT_SYMBOL_GPL(proc_create_net_single_write);
+
 static struct net *get_proc_task_net(struct inode *dir)
 {
        struct task_struct *task;
index 61b7340b357a2aad54e6c9b5eca97b8c9bd7a425..f4b1a9d2eca6010be2838197dc9741ec67a3857e 100644 (file)
@@ -204,8 +204,7 @@ struct proc_dir_entry proc_root = {
        .proc_fops      = &proc_root_operations,
        .parent         = &proc_root,
        .subdir         = RB_ROOT,
-       .name           = proc_root.inline_name,
-       .inline_name    = "/proc",
+       .name           = "/proc",
 };
 
 int pid_ns_prepare_proc(struct pid_namespace *ns)
index 3bd12f955867e5faf865b32f1197054d6a99dde9..3f723cb478af31c721ec263b4db9fb3e9ac17054 100644 (file)
@@ -10,7 +10,7 @@
 static int uptime_proc_show(struct seq_file *m, void *v)
 {
        struct timespec uptime;
-       struct timespec idle;
+       struct timespec64 idle;
        u64 nsec;
        u32 rem;
        int i;
index dc720573fd5308802eacd0ba181b93f96799e95e..c238ab8ba31d6139a9b19c087e6041d3e1b8dffc 100644 (file)
@@ -328,7 +328,7 @@ void pstore_record_init(struct pstore_record *record,
        record->psi = psinfo;
 
        /* Report zeroed timestamp if called before timekeeping has resumed. */
-       record->time = ns_to_timespec(ktime_get_real_fast_ns());
+       record->time = ns_to_timespec64(ktime_get_real_fast_ns());
 }
 
 /*
index 49b2bc1148683bd0a986e74e17bfb101fbd59b33..bbd1e357c23df64b385f4baf119e649342c9c50e 100644 (file)
@@ -153,21 +153,23 @@ ramoops_get_next_prz(struct persistent_ram_zone *przs[], uint *c, uint max,
        return prz;
 }
 
-static int ramoops_read_kmsg_hdr(char *buffer, struct timespec *time,
+static int ramoops_read_kmsg_hdr(char *buffer, struct timespec64 *time,
                                  bool *compressed)
 {
        char data_type;
        int header_length = 0;
 
-       if (sscanf(buffer, RAMOOPS_KERNMSG_HDR "%lu.%lu-%c\n%n", &time->tv_sec,
-                       &time->tv_nsec, &data_type, &header_length) == 3) {
+       if (sscanf(buffer, RAMOOPS_KERNMSG_HDR "%lld.%lu-%c\n%n",
+                  (time64_t *)&time->tv_sec, &time->tv_nsec, &data_type,
+                  &header_length) == 3) {
                if (data_type == 'C')
                        *compressed = true;
                else
                        *compressed = false;
-       } else if (sscanf(buffer, RAMOOPS_KERNMSG_HDR "%lu.%lu\n%n",
-                       &time->tv_sec, &time->tv_nsec, &header_length) == 2) {
-                       *compressed = false;
+       } else if (sscanf(buffer, RAMOOPS_KERNMSG_HDR "%lld.%lu\n%n",
+                         (time64_t *)&time->tv_sec, &time->tv_nsec,
+                         &header_length) == 2) {
+               *compressed = false;
        } else {
                time->tv_sec = 0;
                time->tv_nsec = 0;
@@ -360,8 +362,8 @@ static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz,
        char *hdr;
        size_t len;
 
-       hdr = kasprintf(GFP_ATOMIC, RAMOOPS_KERNMSG_HDR "%lu.%lu-%c\n",
-               record->time.tv_sec,
+       hdr = kasprintf(GFP_ATOMIC, RAMOOPS_KERNMSG_HDR "%lld.%06lu-%c\n",
+               (time64_t)record->time.tv_sec,
                record->time.tv_nsec / 1000,
                record->compressed ? 'C' : 'D');
        WARN_ON_ONCE(!hdr);
index 5089dac0266020d705e54dcb8f06ca1a998ccec2..97f3fc4fdd79e8b1b1fa2ad3be41a394742780ee 100644 (file)
@@ -1316,7 +1316,7 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        int jbegin_count;
        umode_t old_inode_mode;
        unsigned long savelink = 1;
-       struct timespec ctime;
+       struct timespec64 ctime;
 
        if (flags & ~RENAME_NOREPLACE)
                return -EINVAL;
index 5dbf5324bdda53377e57d38661ec3a835256c85f..ff94fad477e461435e335030dd7baf99c0783636 100644 (file)
@@ -451,10 +451,10 @@ int reiserfs_commit_write(struct file *f, struct page *page,
 
 static void update_ctime(struct inode *inode)
 {
-       struct timespec now = current_time(inode);
+       struct timespec64 now = current_time(inode);
 
        if (inode_unhashed(inode) || !inode->i_nlink ||
-           timespec_equal(&inode->i_ctime, &now))
+           timespec64_equal(&inode->i_ctime, &now))
                return;
 
        inode->i_ctime = current_time(inode);
index cbb42f77a2bd221d8ab7c9cb2b6dc0e047b321e2..4fcd1498acf522d75cced6ea13d22b9d78c9b43b 100644 (file)
@@ -259,10 +259,8 @@ static const struct file_operations signalfd_fops = {
        .llseek         = noop_llseek,
 };
 
-static int do_signalfd4(int ufd, sigset_t __user *user_mask, size_t sizemask,
-                       int flags)
+static int do_signalfd4(int ufd, sigset_t *mask, int flags)
 {
-       sigset_t sigmask;
        struct signalfd_ctx *ctx;
 
        /* Check the SFD_* constants for consistency.  */
@@ -272,18 +270,15 @@ static int do_signalfd4(int ufd, sigset_t __user *user_mask, size_t sizemask,
        if (flags & ~(SFD_CLOEXEC | SFD_NONBLOCK))
                return -EINVAL;
 
-       if (sizemask != sizeof(sigset_t) ||
-           copy_from_user(&sigmask, user_mask, sizeof(sigmask)))
-               return -EINVAL;
-       sigdelsetmask(&sigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
-       signotset(&sigmask);
+       sigdelsetmask(mask, sigmask(SIGKILL) | sigmask(SIGSTOP));
+       signotset(mask);
 
        if (ufd == -1) {
                ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
                if (!ctx)
                        return -ENOMEM;
 
-               ctx->sigmask = sigmask;
+               ctx->sigmask = *mask;
 
                /*
                 * When we call this, the initialization must be complete, since
@@ -303,7 +298,7 @@ static int do_signalfd4(int ufd, sigset_t __user *user_mask, size_t sizemask,
                        return -EINVAL;
                }
                spin_lock_irq(&current->sighand->siglock);
-               ctx->sigmask = sigmask;
+               ctx->sigmask = *mask;
                spin_unlock_irq(&current->sighand->siglock);
 
                wake_up(&current->sighand->signalfd_wqh);
@@ -316,46 +311,51 @@ static int do_signalfd4(int ufd, sigset_t __user *user_mask, size_t sizemask,
 SYSCALL_DEFINE4(signalfd4, int, ufd, sigset_t __user *, user_mask,
                size_t, sizemask, int, flags)
 {
-       return do_signalfd4(ufd, user_mask, sizemask, flags);
+       sigset_t mask;
+
+       if (sizemask != sizeof(sigset_t) ||
+           copy_from_user(&mask, user_mask, sizeof(mask)))
+               return -EINVAL;
+       return do_signalfd4(ufd, &mask, flags);
 }
 
 SYSCALL_DEFINE3(signalfd, int, ufd, sigset_t __user *, user_mask,
                size_t, sizemask)
 {
-       return do_signalfd4(ufd, user_mask, sizemask, 0);
+       sigset_t mask;
+
+       if (sizemask != sizeof(sigset_t) ||
+           copy_from_user(&mask, user_mask, sizeof(mask)))
+               return -EINVAL;
+       return do_signalfd4(ufd, &mask, 0);
 }
 
 #ifdef CONFIG_COMPAT
 static long do_compat_signalfd4(int ufd,
-                       const compat_sigset_t __user *sigmask,
+                       const compat_sigset_t __user *user_mask,
                        compat_size_t sigsetsize, int flags)
 {
-       sigset_t tmp;
-       sigset_t __user *ksigmask;
+       sigset_t mask;
 
        if (sigsetsize != sizeof(compat_sigset_t))
                return -EINVAL;
-       if (get_compat_sigset(&tmp, sigmask))
-               return -EFAULT;
-       ksigmask = compat_alloc_user_space(sizeof(sigset_t));
-       if (copy_to_user(ksigmask, &tmp, sizeof(sigset_t)))
+       if (get_compat_sigset(&mask, user_mask))
                return -EFAULT;
-
-       return do_signalfd4(ufd, ksigmask, sizeof(sigset_t), flags);
+       return do_signalfd4(ufd, &mask, flags);
 }
 
 COMPAT_SYSCALL_DEFINE4(signalfd4, int, ufd,
-                    const compat_sigset_t __user *, sigmask,
+                    const compat_sigset_t __user *, user_mask,
                     compat_size_t, sigsetsize,
                     int, flags)
 {
-       return do_compat_signalfd4(ufd, sigmask, sigsetsize, flags);
+       return do_compat_signalfd4(ufd, user_mask, sigsetsize, flags);
 }
 
 COMPAT_SYSCALL_DEFINE3(signalfd, int, ufd,
-                    const compat_sigset_t __user *,sigmask,
+                    const compat_sigset_t __user *, user_mask,
                     compat_size_t, sigsetsize)
 {
-       return do_compat_signalfd4(ufd, sigmask, sigsetsize, 0);
+       return do_compat_signalfd4(ufd, user_mask, sigsetsize, 0);
 }
 #endif
index 2365ab073a2708982ba3eb74a008039aff67687f..b3daa971f59771d6adf248a192db7d6e3121b015 100644 (file)
@@ -1243,38 +1243,26 @@ static int pipe_to_user(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
  * For lack of a better implementation, implement vmsplice() to userspace
  * as a simple copy of the pipes pages to the user iov.
  */
-static long vmsplice_to_user(struct file *file, const struct iovec __user *uiov,
-                            unsigned long nr_segs, unsigned int flags)
+static long vmsplice_to_user(struct file *file, struct iov_iter *iter,
+                            unsigned int flags)
 {
-       struct pipe_inode_info *pipe;
-       struct splice_desc sd;
-       long ret;
-       struct iovec iovstack[UIO_FASTIOV];
-       struct iovec *iov = iovstack;
-       struct iov_iter iter;
+       struct pipe_inode_info *pipe = get_pipe_info(file);
+       struct splice_desc sd = {
+               .total_len = iov_iter_count(iter),
+               .flags = flags,
+               .u.data = iter
+       };
+       long ret = 0;
 
-       pipe = get_pipe_info(file);
        if (!pipe)
                return -EBADF;
 
-       ret = import_iovec(READ, uiov, nr_segs,
-                          ARRAY_SIZE(iovstack), &iov, &iter);
-       if (ret < 0)
-               return ret;
-
-       sd.total_len = iov_iter_count(&iter);
-       sd.len = 0;
-       sd.flags = flags;
-       sd.u.data = &iter;
-       sd.pos = 0;
-
        if (sd.total_len) {
                pipe_lock(pipe);
                ret = __splice_from_pipe(pipe, &sd, pipe_to_user);
                pipe_unlock(pipe);
        }
 
-       kfree(iov);
        return ret;
 }
 
@@ -1283,14 +1271,11 @@ static long vmsplice_to_user(struct file *file, const struct iovec __user *uiov,
  * as splice-from-memory, where the regular splice is splice-from-file (or
  * to file). In both cases the output is a pipe, naturally.
  */
-static long vmsplice_to_pipe(struct file *file, const struct iovec __user *uiov,
-                            unsigned long nr_segs, unsigned int flags)
+static long vmsplice_to_pipe(struct file *file, struct iov_iter *iter,
+                            unsigned int flags)
 {
        struct pipe_inode_info *pipe;
-       struct iovec iovstack[UIO_FASTIOV];
-       struct iovec *iov = iovstack;
-       struct iov_iter from;
-       long ret;
+       long ret = 0;
        unsigned buf_flag = 0;
 
        if (flags & SPLICE_F_GIFT)
@@ -1300,22 +1285,31 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *uiov,
        if (!pipe)
                return -EBADF;
 
-       ret = import_iovec(WRITE, uiov, nr_segs,
-                          ARRAY_SIZE(iovstack), &iov, &from);
-       if (ret < 0)
-               return ret;
-
        pipe_lock(pipe);
        ret = wait_for_space(pipe, flags);
        if (!ret)
-               ret = iter_to_pipe(&from, pipe, buf_flag);
+               ret = iter_to_pipe(iter, pipe, buf_flag);
        pipe_unlock(pipe);
        if (ret > 0)
                wakeup_pipe_readers(pipe);
-       kfree(iov);
        return ret;
 }
 
+static int vmsplice_type(struct fd f, int *type)
+{
+       if (!f.file)
+               return -EBADF;
+       if (f.file->f_mode & FMODE_WRITE) {
+               *type = WRITE;
+       } else if (f.file->f_mode & FMODE_READ) {
+               *type = READ;
+       } else {
+               fdput(f);
+               return -EBADF;
+       }
+       return 0;
+}
+
 /*
  * Note that vmsplice only really supports true splicing _from_ user memory
  * to a pipe, not the other way around. Splicing from user memory is a simple
@@ -1332,57 +1326,69 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *uiov,
  * Currently we punt and implement it as a normal copy, see pipe_to_user().
  *
  */
-static long do_vmsplice(int fd, const struct iovec __user *iov,
-                       unsigned long nr_segs, unsigned int flags)
+static long do_vmsplice(struct file *f, struct iov_iter *iter, unsigned int flags)
 {
-       struct fd f;
-       long error;
-
        if (unlikely(flags & ~SPLICE_F_ALL))
                return -EINVAL;
-       if (unlikely(nr_segs > UIO_MAXIOV))
-               return -EINVAL;
-       else if (unlikely(!nr_segs))
-               return 0;
 
-       error = -EBADF;
-       f = fdget(fd);
-       if (f.file) {
-               if (f.file->f_mode & FMODE_WRITE)
-                       error = vmsplice_to_pipe(f.file, iov, nr_segs, flags);
-               else if (f.file->f_mode & FMODE_READ)
-                       error = vmsplice_to_user(f.file, iov, nr_segs, flags);
-
-               fdput(f);
-       }
+       if (!iov_iter_count(iter))
+               return 0;
 
-       return error;
+       if (iov_iter_rw(iter) == WRITE)
+               return vmsplice_to_pipe(f, iter, flags);
+       else
+               return vmsplice_to_user(f, iter, flags);
 }
 
-SYSCALL_DEFINE4(vmsplice, int, fd, const struct iovec __user *, iov,
+SYSCALL_DEFINE4(vmsplice, int, fd, const struct iovec __user *, uiov,
                unsigned long, nr_segs, unsigned int, flags)
 {
-       return do_vmsplice(fd, iov, nr_segs, flags);
+       struct iovec iovstack[UIO_FASTIOV];
+       struct iovec *iov = iovstack;
+       struct iov_iter iter;
+       long error;
+       struct fd f;
+       int type;
+
+       f = fdget(fd);
+       error = vmsplice_type(f, &type);
+       if (error)
+               return error;
+
+       error = import_iovec(type, uiov, nr_segs,
+                            ARRAY_SIZE(iovstack), &iov, &iter);
+       if (!error) {
+               error = do_vmsplice(f.file, &iter, flags);
+               kfree(iov);
+       }
+       fdput(f);
+       return error;
 }
 
 #ifdef CONFIG_COMPAT
 COMPAT_SYSCALL_DEFINE4(vmsplice, int, fd, const struct compat_iovec __user *, iov32,
                    unsigned int, nr_segs, unsigned int, flags)
 {
-       unsigned i;
-       struct iovec __user *iov;
-       if (nr_segs > UIO_MAXIOV)
-               return -EINVAL;
-       iov = compat_alloc_user_space(nr_segs * sizeof(struct iovec));
-       for (i = 0; i < nr_segs; i++) {
-               struct compat_iovec v;
-               if (get_user(v.iov_base, &iov32[i].iov_base) ||
-                   get_user(v.iov_len, &iov32[i].iov_len) ||
-                   put_user(compat_ptr(v.iov_base), &iov[i].iov_base) ||
-                   put_user(v.iov_len, &iov[i].iov_len))
-                       return -EFAULT;
+       struct iovec iovstack[UIO_FASTIOV];
+       struct iovec *iov = iovstack;
+       struct iov_iter iter;
+       long error;
+       struct fd f;
+       int type;
+
+       f = fdget(fd);
+       error = vmsplice_type(f, &type);
+       if (error)
+               return error;
+
+       error = compat_import_iovec(type, iov32, nr_segs,
+                            ARRAY_SIZE(iovstack), &iov, &iter);
+       if (!error) {
+               error = do_vmsplice(f.file, &iter, flags);
+               kfree(iov);
        }
-       return do_vmsplice(fd, iov, nr_segs, flags);
+       fdput(f);
+       return error;
 }
 #endif
 
index 4e267cc21c77c652b155636ca5967820a96dba1e..9da224d4f2da1d7de9f2bf292e7afa504a9668f3 100644 (file)
@@ -1276,7 +1276,7 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry,
                                        .dirtied_ino = 3 };
        struct ubifs_budget_req ino_req = { .dirtied_ino = 1,
                        .dirtied_ino_d = ALIGN(old_inode_ui->data_len, 8) };
-       struct timespec time;
+       struct timespec64 time;
        unsigned int uninitialized_var(saved_nlink);
        struct fscrypt_name old_nm, new_nm;
 
@@ -1504,7 +1504,7 @@ static int ubifs_xrename(struct inode *old_dir, struct dentry *old_dentry,
        int sync = IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir);
        struct inode *fst_inode = d_inode(old_dentry);
        struct inode *snd_inode = d_inode(new_dentry);
-       struct timespec time;
+       struct timespec64 time;
        int err;
        struct fscrypt_name fst_nm, snd_nm;
 
index 28b80713a163e3e59355559e1be4ea7a8228990b..fd7eb6fe90904fa9a57bd46711124f54af475849 100644 (file)
@@ -1089,14 +1089,14 @@ static void do_attr_changes(struct inode *inode, const struct iattr *attr)
        if (attr->ia_valid & ATTR_GID)
                inode->i_gid = attr->ia_gid;
        if (attr->ia_valid & ATTR_ATIME)
-               inode->i_atime = timespec_trunc(attr->ia_atime,
-                                               inode->i_sb->s_time_gran);
+               inode->i_atime = timespec64_trunc(attr->ia_atime,
+                                                 inode->i_sb->s_time_gran);
        if (attr->ia_valid & ATTR_MTIME)
-               inode->i_mtime = timespec_trunc(attr->ia_mtime,
-                                               inode->i_sb->s_time_gran);
+               inode->i_mtime = timespec64_trunc(attr->ia_mtime,
+                                                 inode->i_sb->s_time_gran);
        if (attr->ia_valid & ATTR_CTIME)
-               inode->i_ctime = timespec_trunc(attr->ia_ctime,
-                                               inode->i_sb->s_time_gran);
+               inode->i_ctime = timespec64_trunc(attr->ia_ctime,
+                                                 inode->i_sb->s_time_gran);
        if (attr->ia_valid & ATTR_MODE) {
                umode_t mode = attr->ia_mode;
 
@@ -1367,8 +1367,9 @@ out:
 static inline int mctime_update_needed(const struct inode *inode,
                                       const struct timespec *now)
 {
-       if (!timespec_equal(&inode->i_mtime, now) ||
-           !timespec_equal(&inode->i_ctime, now))
+       struct timespec64 now64 = timespec_to_timespec64(*now);
+       if (!timespec64_equal(&inode->i_mtime, &now64) ||
+           !timespec64_equal(&inode->i_ctime, &now64))
                return 1;
        return 0;
 }
@@ -1380,7 +1381,7 @@ static inline int mctime_update_needed(const struct inode *inode,
  *
  * This function updates time of the inode.
  */
-int ubifs_update_time(struct inode *inode, struct timespec *time,
+int ubifs_update_time(struct inode *inode, struct timespec64 *time,
                             int flags)
 {
        struct ubifs_inode *ui = ubifs_inode(inode);
@@ -1424,7 +1425,7 @@ int ubifs_update_time(struct inode *inode, struct timespec *time,
  */
 static int update_mctime(struct inode *inode)
 {
-       struct timespec now = current_time(inode);
+       struct timespec now = timespec64_to_timespec(current_time(inode));
        struct ubifs_inode *ui = ubifs_inode(inode);
        struct ubifs_info *c = inode->i_sb->s_fs_info;
 
@@ -1518,7 +1519,7 @@ static vm_fault_t ubifs_vm_page_mkwrite(struct vm_fault *vmf)
        struct page *page = vmf->page;
        struct inode *inode = file_inode(vmf->vma->vm_file);
        struct ubifs_info *c = inode->i_sb->s_fs_info;
-       struct timespec now = current_time(inode);
+       struct timespec now = timespec64_to_timespec(current_time(inode));
        struct ubifs_budget_req req = { .new_page = 1 };
        int err, update_time;
 
index 209d6369ae71cdd7c6686a419e18f0eae5544211..04bf84d71e7bbae5339d4f7ceea70406be7d1cc8 100644 (file)
@@ -1738,7 +1738,7 @@ int ubifs_calc_dark(const struct ubifs_info *c, int spc);
 int ubifs_fsync(struct file *file, loff_t start, loff_t end, int datasync);
 int ubifs_setattr(struct dentry *dentry, struct iattr *attr);
 #ifdef CONFIG_UBIFS_ATIME_SUPPORT
-int ubifs_update_time(struct inode *inode, struct timespec *time, int flags);
+int ubifs_update_time(struct inode *inode, struct timespec64 *time, int flags);
 #endif
 
 /* dir.c */
index b7a0d4b4bda144015c5f59ce42108b1d2660c07f..56569023783b3503fe37b414287eadcbd4efa176 100644 (file)
@@ -124,8 +124,8 @@ struct inode *udf_new_inode(struct inode *dir, umode_t mode)
                iinfo->i_alloc_type = ICBTAG_FLAG_AD_SHORT;
        else
                iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG;
-       inode->i_mtime = inode->i_atime = inode->i_ctime =
-               iinfo->i_crtime = current_time(inode);
+       inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
+       iinfo->i_crtime = timespec64_to_timespec(inode->i_mtime);
        if (unlikely(insert_inode_locked(inode) < 0)) {
                make_bad_inode(inode);
                iput(inode);
index c80765d62f7e9028a3ba2ac282ba2d8c615acbaa..7f39d17352c9697863f02140f7cf7ec1120a2215 100644 (file)
@@ -1271,6 +1271,7 @@ static int udf_read_inode(struct inode *inode, bool hidden_inode)
        struct udf_inode_info *iinfo = UDF_I(inode);
        struct udf_sb_info *sbi = UDF_SB(inode->i_sb);
        struct kernel_lb_addr *iloc = &iinfo->i_location;
+       struct timespec ts;
        unsigned int link_count;
        unsigned int indirections = 0;
        int bs = inode->i_sb->s_blocksize;
@@ -1443,15 +1444,12 @@ reread:
                inode->i_blocks = le64_to_cpu(fe->logicalBlocksRecorded) <<
                        (inode->i_sb->s_blocksize_bits - 9);
 
-               if (!udf_disk_stamp_to_time(&inode->i_atime, fe->accessTime))
-                       inode->i_atime = sbi->s_record_time;
-
-               if (!udf_disk_stamp_to_time(&inode->i_mtime,
-                                           fe->modificationTime))
-                       inode->i_mtime = sbi->s_record_time;
-
-               if (!udf_disk_stamp_to_time(&inode->i_ctime, fe->attrTime))
-                       inode->i_ctime = sbi->s_record_time;
+               udf_disk_stamp_to_time(&ts, fe->accessTime);
+               inode->i_atime = timespec_to_timespec64(ts);
+               udf_disk_stamp_to_time(&ts, fe->modificationTime);
+               inode->i_mtime = timespec_to_timespec64(ts);
+               udf_disk_stamp_to_time(&ts, fe->attrTime);
+               inode->i_ctime = timespec_to_timespec64(ts);
 
                iinfo->i_unique = le64_to_cpu(fe->uniqueID);
                iinfo->i_lenEAttr = le32_to_cpu(fe->lengthExtendedAttr);
@@ -1461,18 +1459,13 @@ reread:
                inode->i_blocks = le64_to_cpu(efe->logicalBlocksRecorded) <<
                    (inode->i_sb->s_blocksize_bits - 9);
 
-               if (!udf_disk_stamp_to_time(&inode->i_atime, efe->accessTime))
-                       inode->i_atime = sbi->s_record_time;
-
-               if (!udf_disk_stamp_to_time(&inode->i_mtime,
-                                           efe->modificationTime))
-                       inode->i_mtime = sbi->s_record_time;
-
-               if (!udf_disk_stamp_to_time(&iinfo->i_crtime, efe->createTime))
-                       iinfo->i_crtime = sbi->s_record_time;
-
-               if (!udf_disk_stamp_to_time(&inode->i_ctime, efe->attrTime))
-                       inode->i_ctime = sbi->s_record_time;
+               udf_disk_stamp_to_time(&ts, efe->accessTime);
+               inode->i_atime = timespec_to_timespec64(ts);
+               udf_disk_stamp_to_time(&ts, efe->modificationTime);
+               inode->i_mtime = timespec_to_timespec64(ts);
+               udf_disk_stamp_to_time(&iinfo->i_crtime, efe->createTime);
+               udf_disk_stamp_to_time(&ts, efe->attrTime);
+               inode->i_ctime = timespec_to_timespec64(ts);
 
                iinfo->i_unique = le64_to_cpu(efe->uniqueID);
                iinfo->i_lenEAttr = le32_to_cpu(efe->lengthExtendedAttr);
@@ -1722,9 +1715,12 @@ static int udf_update_inode(struct inode *inode, int do_sync)
                       inode->i_sb->s_blocksize - sizeof(struct fileEntry));
                fe->logicalBlocksRecorded = cpu_to_le64(lb_recorded);
 
-               udf_time_to_disk_stamp(&fe->accessTime, inode->i_atime);
-               udf_time_to_disk_stamp(&fe->modificationTime, inode->i_mtime);
-               udf_time_to_disk_stamp(&fe->attrTime, inode->i_ctime);
+               udf_time_to_disk_stamp(&fe->accessTime,
+                                      timespec64_to_timespec(inode->i_atime));
+               udf_time_to_disk_stamp(&fe->modificationTime,
+                                      timespec64_to_timespec(inode->i_mtime));
+               udf_time_to_disk_stamp(&fe->attrTime,
+                                      timespec64_to_timespec(inode->i_ctime));
                memset(&(fe->impIdent), 0, sizeof(struct regid));
                strcpy(fe->impIdent.ident, UDF_ID_DEVELOPER);
                fe->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
@@ -1743,14 +1739,17 @@ static int udf_update_inode(struct inode *inode, int do_sync)
                efe->objectSize = cpu_to_le64(inode->i_size);
                efe->logicalBlocksRecorded = cpu_to_le64(lb_recorded);
 
-               udf_adjust_time(iinfo, inode->i_atime);
-               udf_adjust_time(iinfo, inode->i_mtime);
-               udf_adjust_time(iinfo, inode->i_ctime);
+               udf_adjust_time(iinfo, timespec64_to_timespec(inode->i_atime));
+               udf_adjust_time(iinfo, timespec64_to_timespec(inode->i_mtime));
+               udf_adjust_time(iinfo, timespec64_to_timespec(inode->i_ctime));
 
-               udf_time_to_disk_stamp(&efe->accessTime, inode->i_atime);
-               udf_time_to_disk_stamp(&efe->modificationTime, inode->i_mtime);
+               udf_time_to_disk_stamp(&efe->accessTime,
+                                      timespec64_to_timespec(inode->i_atime));
+               udf_time_to_disk_stamp(&efe->modificationTime,
+                                      timespec64_to_timespec(inode->i_mtime));
                udf_time_to_disk_stamp(&efe->createTime, iinfo->i_crtime);
-               udf_time_to_disk_stamp(&efe->attrTime, inode->i_ctime);
+               udf_time_to_disk_stamp(&efe->attrTime,
+                                      timespec64_to_timespec(inode->i_ctime));
 
                memset(&(efe->impIdent), 0, sizeof(efe->impIdent));
                strcpy(efe->impIdent.ident, UDF_ID_DEVELOPER);
index fc77ea736da70b759bc39b3f4af1b51d7372eb55..0c504c8031d36a0de5a3add21cb294722b621a60 100644 (file)
@@ -862,6 +862,9 @@ static int udf_load_pvoldesc(struct super_block *sb, sector_t block)
        struct buffer_head *bh;
        uint16_t ident;
        int ret = -ENOMEM;
+#ifdef UDFFS_DEBUG
+       struct timestamp *ts;
+#endif
 
        outstr = kmalloc(128, GFP_NOFS);
        if (!outstr)
@@ -880,15 +883,15 @@ static int udf_load_pvoldesc(struct super_block *sb, sector_t block)
 
        pvoldesc = (struct primaryVolDesc *)bh->b_data;
 
-       if (udf_disk_stamp_to_time(&UDF_SB(sb)->s_record_time,
-                             pvoldesc->recordingDateAndTime)) {
+       udf_disk_stamp_to_time(&UDF_SB(sb)->s_record_time,
+                             pvoldesc->recordingDateAndTime);
 #ifdef UDFFS_DEBUG
-               struct timestamp *ts = &pvoldesc->recordingDateAndTime;
-               udf_debug("recording time %04u/%02u/%02u %02u:%02u (%x)\n",
-                         le16_to_cpu(ts->year), ts->month, ts->day, ts->hour,
-                         ts->minute, le16_to_cpu(ts->typeAndTimezone));
+       ts = &pvoldesc->recordingDateAndTime;
+       udf_debug("recording time %04u/%02u/%02u %02u:%02u (%x)\n",
+                 le16_to_cpu(ts->year), ts->month, ts->day, ts->hour,
+                 ts->minute, le16_to_cpu(ts->typeAndTimezone));
 #endif
-       }
+
 
        ret = udf_dstrCS0toChar(sb, outstr, 31, pvoldesc->volIdent, 32);
        if (ret < 0)
index fc8d1b3384d25767df9d083ab1088a3dbbc52d5c..bae311b59400459338d2c60f9e962429066e1483 100644 (file)
@@ -253,8 +253,8 @@ extern struct long_ad *udf_get_filelongad(uint8_t *, int, uint32_t *, int);
 extern struct short_ad *udf_get_fileshortad(uint8_t *, int, uint32_t *, int);
 
 /* udftime.c */
-extern struct timespec *udf_disk_stamp_to_time(struct timespec *dest,
+extern void udf_disk_stamp_to_time(struct timespec *dest,
                                                struct timestamp src);
-extern struct timestamp *udf_time_to_disk_stamp(struct timestamp *dest, struct timespec src);
+extern void udf_time_to_disk_stamp(struct timestamp *dest, struct timespec src);
 
 #endif                         /* __UDF_DECL_H */
index 0927a4b2ecafba09171d62adf90edd13b791b668..67b33ac5d41bdd5d4078dcdb7f1e3ab5ec2f16c1 100644 (file)
@@ -40,7 +40,7 @@
 #include <linux/kernel.h>
 #include <linux/time.h>
 
-struct timespec *
+void
 udf_disk_stamp_to_time(struct timespec *dest, struct timestamp src)
 {
        u16 typeAndTimezone = le16_to_cpu(src.typeAndTimezone);
@@ -67,10 +67,9 @@ udf_disk_stamp_to_time(struct timespec *dest, struct timestamp src)
         * recorded with bogus sub-second values.
         */
        dest->tv_nsec %= NSEC_PER_SEC;
-       return dest;
 }
 
-struct timestamp *
+void
 udf_time_to_disk_stamp(struct timestamp *dest, struct timespec ts)
 {
        long seconds;
@@ -79,9 +78,6 @@ udf_time_to_disk_stamp(struct timestamp *dest, struct timespec ts)
 
        offset = -sys_tz.tz_minuteswest;
 
-       if (!dest)
-               return NULL;
-
        dest->typeAndTimezone = cpu_to_le16(0x1000 | (offset & 0x0FFF));
 
        seconds = ts.tv_sec + offset * 60;
@@ -97,7 +93,6 @@ udf_time_to_disk_stamp(struct timestamp *dest, struct timespec ts)
                                        dest->centiseconds * 10000) / 100;
        dest->microseconds = (ts.tv_nsec / 1000 - dest->centiseconds * 10000 -
                              dest->hundredsOfMicroseconds * 100);
-       return dest;
 }
 
 /* EOF */
index 4a2e5e13c5699610535a1b3b727455c50e97eb3c..7a96c4e0ab5c621f38d9e034622d26ebd8d95437 100644 (file)
@@ -761,7 +761,7 @@ xfs_ialloc(
        xfs_inode_t     *ip;
        uint            flags;
        int             error;
-       struct timespec tv;
+       struct timespec64 tv;
        struct inode    *inode;
 
        /*
index 1fce707406c6352175c6218ca6dd09140bedac27..0fa29f39d658a7fcd8a8886689ab8e1b67a5db7e 100644 (file)
@@ -1042,7 +1042,7 @@ xfs_vn_setattr(
 STATIC int
 xfs_vn_update_time(
        struct inode            *inode,
-       struct timespec         *now,
+       struct timespec64       *now,
        int                     flags)
 {
        struct xfs_inode        *ip = XFS_I(inode);
index e2963a6033b2acf9e5f1fc6def1f5f0089d52db4..542927321a61b5e2ff52b30faca74dac268c1722 100644 (file)
@@ -58,7 +58,7 @@ xfs_trans_ichgtime(
        int                     flags)
 {
        struct inode            *inode = VFS_I(ip);
-       struct timespec         tv;
+       struct timespec64 tv;
 
        ASSERT(tp);
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
index 2480469ce8fb34a15e724cbd78f9b29fc8defb37..e0a9c236887281d793acff2ea457d2290c56cb4e 100644 (file)
@@ -1,6 +1,6 @@
 /* Asymmetric public-key cryptography key subtype
  *
- * See Documentation/security/asymmetric-keys.txt
+ * See Documentation/crypto/asymmetric-keys.txt
  *
  * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
index b38240716d411745b9e11e2d68030b1ae4a948fb..1cb77cd5135e3272b141eedabcd52dafc97a180e 100644 (file)
@@ -1,6 +1,6 @@
 /* Asymmetric Public-key cryptography key type interface
  *
- * See Documentation/security/asymmetric-keys.txt
+ * See Documentation/crypto/asymmetric-keys.txt
  *
  * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
index a89df3be16863302dcedde84da6f0dbc278fde8c..65e3832f96b2529784599a66e7c87273211d6e0e 100644 (file)
@@ -1,6 +1,6 @@
 /* Generic associative array implementation.
  *
- * See Documentation/assoc_array.txt for information.
+ * See Documentation/core-api/assoc_array.rst for information.
  *
  * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
index 711275e6681c7829aba18c5e1c07f05d3bc36996..a00a06550c10ccbc6229be83779d231acb4487f0 100644 (file)
@@ -1,6 +1,6 @@
 /* Private definitions for the generic associative array implementation.
  *
- * See Documentation/assoc_array.txt for information.
+ * See Documentation/core-api/assoc_array.rst for information.
  *
  * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
index fb355173f3c73a6e15a211a8d6f20a879a07d300..e3147eb74222b868a014f498f1186a7a6c661804 100644 (file)
@@ -281,8 +281,6 @@ void blk_freeze_queue_start(struct request_queue *q);
 void blk_mq_freeze_queue_wait(struct request_queue *q);
 int blk_mq_freeze_queue_wait_timeout(struct request_queue *q,
                                     unsigned long timeout);
-int blk_mq_tagset_iter(struct blk_mq_tag_set *set, void *data,
-               int (reinit_request)(void *, struct request *));
 
 int blk_mq_map_queues(struct blk_mq_tag_set *set);
 void blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set, int nr_hw_queues);
index bca3a92eb55f5bc88c47c65343d595479cebb9c4..9154570edf2963628f873d7404930450735ff41a 100644 (file)
@@ -127,6 +127,8 @@ typedef __u32 __bitwise req_flags_t;
 #define RQF_ZONE_WRITE_LOCKED  ((__force req_flags_t)(1 << 19))
 /* already slept for hybrid poll */
 #define RQF_MQ_POLL_SLEPT      ((__force req_flags_t)(1 << 20))
+/* ->timeout has been called, don't expire again */
+#define RQF_TIMED_OUT          ((__force req_flags_t)(1 << 21))
 
 /* flags that prevent us from merging requests: */
 #define RQF_NOMERGE_FLAGS \
@@ -560,7 +562,6 @@ struct request_queue {
        unsigned int            dma_alignment;
 
        struct blk_queue_tag    *queue_tags;
-       struct list_head        tag_busy_list;
 
        unsigned int            nr_sorted;
        unsigned int            in_flight[2];
@@ -1373,7 +1374,6 @@ extern void blk_queue_end_tag(struct request_queue *, struct request *);
 extern int blk_queue_init_tags(struct request_queue *, int, struct blk_queue_tag *, int);
 extern void blk_queue_free_tags(struct request_queue *);
 extern int blk_queue_resize_tags(struct request_queue *, int);
-extern void blk_queue_invalidate_tags(struct request_queue *);
 extern struct blk_queue_tag *blk_init_tags(int, int);
 extern void blk_free_tags(struct blk_queue_tag *);
 
index 7ecfc88314d835605d72189e7458f362bb6a1632..4903deb0777a746068ecd7f5cc5a472276885cfe 100644 (file)
@@ -628,6 +628,7 @@ int ceph_flags_to_mode(int flags);
                                 CEPH_CAP_XATTR_SHARED)
 #define CEPH_STAT_CAP_INLINE_DATA (CEPH_CAP_FILE_SHARED | \
                                   CEPH_CAP_FILE_RD)
+#define CEPH_STAT_RSTAT CEPH_CAP_FILE_WREXTEND
 
 #define CEPH_CAP_ANY_SHARED (CEPH_CAP_AUTH_SHARED |                    \
                              CEPH_CAP_LINK_SHARED |                    \
index 96bb3228598927c0cb089b5f4fa88da445cd1b26..0d6ee04b4c417c3fcd82c320ce3c7f2a75254d13 100644 (file)
@@ -170,6 +170,7 @@ struct ceph_osd_request {
        u64             r_tid;              /* unique for this client */
        struct rb_node  r_node;
        struct rb_node  r_mc_node;          /* map check */
+       struct work_struct r_complete_work;
        struct ceph_osd *r_osd;
 
        struct ceph_osd_request_target r_t;
@@ -201,7 +202,6 @@ struct ceph_osd_request {
        struct timespec r_mtime;              /* ditto */
        u64 r_data_offset;                    /* ditto */
        bool r_linger;                        /* don't resend on failure */
-       bool r_abort_on_full;                 /* return ENOSPC when full */
 
        /* internal */
        unsigned long r_stamp;                /* jiffies, send or check time */
@@ -347,6 +347,8 @@ struct ceph_osd_client {
        struct rb_root         linger_map_checks;
        atomic_t               num_requests;
        atomic_t               num_homeless;
+       bool                   abort_on_full; /* abort w/ ENOSPC when full */
+       int                    abort_err;
        struct delayed_work    timeout_work;
        struct delayed_work    osds_timeout_work;
 #ifdef CONFIG_DEBUG_FS
@@ -359,6 +361,7 @@ struct ceph_osd_client {
        struct ceph_msgpool     msgpool_op_reply;
 
        struct workqueue_struct *notify_wq;
+       struct workqueue_struct *completion_wq;
 };
 
 static inline bool ceph_osdmap_flag(struct ceph_osd_client *osdc, int flag)
@@ -378,6 +381,7 @@ extern void ceph_osdc_handle_reply(struct ceph_osd_client *osdc,
 extern void ceph_osdc_handle_map(struct ceph_osd_client *osdc,
                                 struct ceph_msg *msg);
 void ceph_osdc_update_epoch_barrier(struct ceph_osd_client *osdc, u32 eb);
+void ceph_osdc_abort_requests(struct ceph_osd_client *osdc, int err);
 
 extern void osd_req_op_init(struct ceph_osd_request *osd_req,
                            unsigned int which, u16 opcode, u32 flags);
@@ -440,7 +444,7 @@ extern void osd_req_op_cls_response_data_pages(struct ceph_osd_request *,
                                        struct page **pages, u64 length,
                                        u32 alignment, bool pages_from_pool,
                                        bool own_pages);
-extern void osd_req_op_cls_init(struct ceph_osd_request *osd_req,
+extern int osd_req_op_cls_init(struct ceph_osd_request *osd_req,
                                        unsigned int which, u16 opcode,
                                        const char *class, const char *method);
 extern int osd_req_op_xattr_init(struct ceph_osd_request *osd_req, unsigned int which,
index e71fb222c7c3640e46426dc5a0de96d6814d96df..5675b1f09bc5c2fa813f4e8e714a791f2666ab1c 100644 (file)
@@ -279,10 +279,10 @@ bool ceph_osds_changed(const struct ceph_osds *old_acting,
                       const struct ceph_osds *new_acting,
                       bool any_change);
 
-int __ceph_object_locator_to_pg(struct ceph_pg_pool_info *pi,
-                               const struct ceph_object_id *oid,
-                               const struct ceph_object_locator *oloc,
-                               struct ceph_pg *raw_pgid);
+void __ceph_object_locator_to_pg(struct ceph_pg_pool_info *pi,
+                                const struct ceph_object_id *oid,
+                                const struct ceph_object_locator *oloc,
+                                struct ceph_pg *raw_pgid);
 int ceph_object_locator_to_pg(struct ceph_osdmap *osdmap,
                              const struct ceph_object_id *oid,
                              const struct ceph_object_locator *oloc,
index 7cf262a421c3f4105424b4d7a12116108b6b9251..b3233e8202f9c2cec17556e71213eb1bc025ca23 100644 (file)
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 /*
- * See Documentation/circular-buffers.txt for more information.
+ * See Documentation/core-api/circular-buffers.rst for more information.
  */
 
 #ifndef _LINUX_CIRC_BUF_H
index 7207de8c4e9aea1e653f804e29cbe6ed7f989aca..5c91108846db20894ab70dafe43b7922fe08fb1f 100644 (file)
@@ -207,9 +207,9 @@ struct iattr {
        kuid_t          ia_uid;
        kgid_t          ia_gid;
        loff_t          ia_size;
-       struct timespec ia_atime;
-       struct timespec ia_mtime;
-       struct timespec ia_ctime;
+       struct timespec64 ia_atime;
+       struct timespec64 ia_mtime;
+       struct timespec64 ia_ctime;
 
        /*
         * Not an attribute, but an auxiliary info for filesystems wanting to
@@ -604,9 +604,9 @@ struct inode {
        };
        dev_t                   i_rdev;
        loff_t                  i_size;
-       struct timespec         i_atime;
-       struct timespec         i_mtime;
-       struct timespec         i_ctime;
+       struct timespec64       i_atime;
+       struct timespec64       i_mtime;
+       struct timespec64       i_ctime;
        spinlock_t              i_lock; /* i_blocks, i_bytes, maybe i_size */
        unsigned short          i_bytes;
        unsigned int            i_blkbits;
@@ -1093,7 +1093,7 @@ extern int vfs_lock_file(struct file *, unsigned int, struct file_lock *, struct
 extern int vfs_cancel_lock(struct file *filp, struct file_lock *fl);
 extern int locks_lock_inode_wait(struct inode *inode, struct file_lock *fl);
 extern int __break_lease(struct inode *inode, unsigned int flags, unsigned int type);
-extern void lease_get_mtime(struct inode *, struct timespec *time);
+extern void lease_get_mtime(struct inode *, struct timespec64 *time);
 extern int generic_setlease(struct file *, long, struct file_lock **, void **priv);
 extern int vfs_setlease(struct file *, long, struct file_lock **, void **);
 extern int lease_modify(struct file_lock *, int, struct list_head *);
@@ -1208,7 +1208,8 @@ static inline int __break_lease(struct inode *inode, unsigned int mode, unsigned
        return 0;
 }
 
-static inline void lease_get_mtime(struct inode *inode, struct timespec *time)
+static inline void lease_get_mtime(struct inode *inode,
+                                  struct timespec64 *time)
 {
        return;
 }
@@ -1478,7 +1479,8 @@ static inline void i_gid_write(struct inode *inode, gid_t gid)
        inode->i_gid = make_kgid(inode->i_sb->s_user_ns, gid);
 }
 
-extern struct timespec current_time(struct inode *inode);
+extern struct timespec64 timespec64_trunc(struct timespec64 t, unsigned gran);
+extern struct timespec64 current_time(struct inode *inode);
 
 /*
  * Snapshotting support.
@@ -1773,7 +1775,7 @@ struct inode_operations {
        ssize_t (*listxattr) (struct dentry *, char *, size_t);
        int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
                      u64 len);
-       int (*update_time)(struct inode *, struct timespec *, int);
+       int (*update_time)(struct inode *, struct timespec64 *, int);
        int (*atomic_open)(struct inode *, struct dentry *,
                           struct file *, unsigned open_flag,
                           umode_t create_mode, int *opened);
@@ -2217,7 +2219,7 @@ extern int current_umask(void);
 
 extern void ihold(struct inode * inode);
 extern void iput(struct inode *);
-extern int generic_update_time(struct inode *, struct timespec *, int);
+extern int generic_update_time(struct inode *, struct timespec64 *, int);
 
 /* /sys/fs */
 extern struct kobject *fs_kobj;
index e64c0294f50bf82dd50d447e37a5c77f86eabc26..b38964a7a521e5d204db057a4cd3ac09ac97f3e5 100644 (file)
@@ -98,8 +98,6 @@ struct fsnotify_iter_info;
 struct fsnotify_ops {
        int (*handle_event)(struct fsnotify_group *group,
                            struct inode *inode,
-                           struct fsnotify_mark *inode_mark,
-                           struct fsnotify_mark *vfsmount_mark,
                            u32 mask, const void *data, int data_type,
                            const unsigned char *file_name, u32 cookie,
                            struct fsnotify_iter_info *iter_info);
@@ -201,6 +199,57 @@ struct fsnotify_group {
 #define FSNOTIFY_EVENT_PATH    1
 #define FSNOTIFY_EVENT_INODE   2
 
+enum fsnotify_obj_type {
+       FSNOTIFY_OBJ_TYPE_INODE,
+       FSNOTIFY_OBJ_TYPE_VFSMOUNT,
+       FSNOTIFY_OBJ_TYPE_COUNT,
+       FSNOTIFY_OBJ_TYPE_DETACHED = FSNOTIFY_OBJ_TYPE_COUNT
+};
+
+#define FSNOTIFY_OBJ_TYPE_INODE_FL     (1U << FSNOTIFY_OBJ_TYPE_INODE)
+#define FSNOTIFY_OBJ_TYPE_VFSMOUNT_FL  (1U << FSNOTIFY_OBJ_TYPE_VFSMOUNT)
+#define FSNOTIFY_OBJ_ALL_TYPES_MASK    ((1U << FSNOTIFY_OBJ_TYPE_COUNT) - 1)
+
+struct fsnotify_iter_info {
+       struct fsnotify_mark *marks[FSNOTIFY_OBJ_TYPE_COUNT];
+       unsigned int report_mask;
+       int srcu_idx;
+};
+
+static inline bool fsnotify_iter_should_report_type(
+               struct fsnotify_iter_info *iter_info, int type)
+{
+       return (iter_info->report_mask & (1U << type));
+}
+
+static inline void fsnotify_iter_set_report_type(
+               struct fsnotify_iter_info *iter_info, int type)
+{
+       iter_info->report_mask |= (1U << type);
+}
+
+static inline void fsnotify_iter_set_report_type_mark(
+               struct fsnotify_iter_info *iter_info, int type,
+               struct fsnotify_mark *mark)
+{
+       iter_info->marks[type] = mark;
+       iter_info->report_mask |= (1U << type);
+}
+
+#define FSNOTIFY_ITER_FUNCS(name, NAME) \
+static inline struct fsnotify_mark *fsnotify_iter_##name##_mark( \
+               struct fsnotify_iter_info *iter_info) \
+{ \
+       return (iter_info->report_mask & FSNOTIFY_OBJ_TYPE_##NAME##_FL) ? \
+               iter_info->marks[FSNOTIFY_OBJ_TYPE_##NAME] : NULL; \
+}
+
+FSNOTIFY_ITER_FUNCS(inode, INODE)
+FSNOTIFY_ITER_FUNCS(vfsmount, VFSMOUNT)
+
+#define fsnotify_foreach_obj_type(type) \
+       for (type = 0; type < FSNOTIFY_OBJ_TYPE_COUNT; type++)
+
 /*
  * Inode / vfsmount point to this structure which tracks all marks attached to
  * the inode / vfsmount. The reference to inode / vfsmount is held by this
@@ -209,11 +258,7 @@ struct fsnotify_group {
  */
 struct fsnotify_mark_connector {
        spinlock_t lock;
-#define FSNOTIFY_OBJ_TYPE_INODE                0x01
-#define FSNOTIFY_OBJ_TYPE_VFSMOUNT     0x02
-#define FSNOTIFY_OBJ_ALL_TYPES         (FSNOTIFY_OBJ_TYPE_INODE | \
-                                        FSNOTIFY_OBJ_TYPE_VFSMOUNT)
-       unsigned int flags;     /* Type of object [lock] */
+       unsigned int type;      /* Type of object [lock] */
        union { /* Object pointer [lock] */
                struct inode *inode;
                struct vfsmount *mnt;
@@ -356,7 +401,21 @@ extern struct fsnotify_mark *fsnotify_find_mark(
 extern int fsnotify_add_mark(struct fsnotify_mark *mark, struct inode *inode,
                             struct vfsmount *mnt, int allow_dups);
 extern int fsnotify_add_mark_locked(struct fsnotify_mark *mark,
-                                   struct inode *inode, struct vfsmount *mnt, int allow_dups);
+                                   struct inode *inode, struct vfsmount *mnt,
+                                   int allow_dups);
+/* attach the mark to the inode */
+static inline int fsnotify_add_inode_mark(struct fsnotify_mark *mark,
+                                         struct inode *inode,
+                                         int allow_dups)
+{
+       return fsnotify_add_mark(mark, inode, NULL, allow_dups);
+}
+static inline int fsnotify_add_inode_mark_locked(struct fsnotify_mark *mark,
+                                                struct inode *inode,
+                                                int allow_dups)
+{
+       return fsnotify_add_mark_locked(mark, inode, NULL, allow_dups);
+}
 /* given a group and a mark, flag mark to be freed when all references are dropped */
 extern void fsnotify_destroy_mark(struct fsnotify_mark *mark,
                                  struct fsnotify_group *group);
@@ -369,12 +428,12 @@ extern void fsnotify_clear_marks_by_group(struct fsnotify_group *group, unsigned
 /* run all the marks in a group, and clear all of the vfsmount marks */
 static inline void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group)
 {
-       fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_VFSMOUNT);
+       fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_VFSMOUNT_FL);
 }
 /* run all the marks in a group, and clear all of the inode marks */
 static inline void fsnotify_clear_inode_marks_by_group(struct fsnotify_group *group)
 {
-       fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_INODE);
+       fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_INODE_FL);
 }
 extern void fsnotify_get_mark(struct fsnotify_mark *mark);
 extern void fsnotify_put_mark(struct fsnotify_mark *mark);
index 9c3c9a319e48b439f6d7013bb444ee20aeece52a..8154f4920fcb9de96a24ec7b85d9b92f56968122 100644 (file)
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Ftrace header.  For implementation details beyond the random comments
- * scattered below, see: Documentation/trace/ftrace-design.txt
+ * scattered below, see: Documentation/trace/ftrace-design.rst
  */
 
 #ifndef _LINUX_FTRACE_H
diff --git a/include/linux/i2c-gpio.h b/include/linux/i2c-gpio.h
deleted file mode 100644 (file)
index 352c142..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * i2c-gpio interface to platform code
- *
- * Copyright (C) 2007 Atmel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#ifndef _LINUX_I2C_GPIO_H
-#define _LINUX_I2C_GPIO_H
-
-/**
- * struct i2c_gpio_platform_data - Platform-dependent data for i2c-gpio
- * @udelay: signal toggle delay. SCL frequency is (500 / udelay) kHz
- * @timeout: clock stretching timeout in jiffies. If the slave keeps
- *     SCL low for longer than this, the transfer will time out.
- * @sda_is_open_drain: SDA is configured as open drain, i.e. the pin
- *     isn't actively driven high when setting the output value high.
- *     gpio_get_value() must return the actual pin state even if the
- *     pin is configured as an output.
- * @scl_is_open_drain: SCL is set up as open drain. Same requirements
- *     as for sda_is_open_drain apply.
- * @scl_is_output_only: SCL output drivers cannot be turned off.
- */
-struct i2c_gpio_platform_data {
-       int             udelay;
-       int             timeout;
-       unsigned int    sda_is_open_drain:1;
-       unsigned int    scl_is_open_drain:1;
-       unsigned int    scl_is_output_only:1;
-};
-
-#endif /* _LINUX_I2C_GPIO_H */
diff --git a/include/linux/i2c-mux-gpio.h b/include/linux/i2c-mux-gpio.h
deleted file mode 100644 (file)
index 4406108..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * i2c-mux-gpio interface to platform code
- *
- * Peter Korsgaard <peter.korsgaard@barco.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _LINUX_I2C_MUX_GPIO_H
-#define _LINUX_I2C_MUX_GPIO_H
-
-/* MUX has no specific idle mode */
-#define I2C_MUX_GPIO_NO_IDLE   ((unsigned)-1)
-
-/**
- * struct i2c_mux_gpio_platform_data - Platform-dependent data for i2c-mux-gpio
- * @parent: Parent I2C bus adapter number
- * @base_nr: Base I2C bus number to number adapters from or zero for dynamic
- * @values: Array of bitmasks of GPIO settings (low/high) for each
- *     position
- * @n_values: Number of multiplexer positions (busses to instantiate)
- * @classes: Optional I2C auto-detection classes
- * @gpio_chip: Optional GPIO chip name; if set, GPIO pin numbers are given
- *     relative to the base GPIO number of that chip
- * @gpios: Array of GPIO numbers used to control MUX
- * @n_gpios: Number of GPIOs used to control MUX
- * @idle: Bitmask to write to MUX when idle or GPIO_I2CMUX_NO_IDLE if not used
- */
-struct i2c_mux_gpio_platform_data {
-       int parent;
-       int base_nr;
-       const unsigned *values;
-       int n_values;
-       const unsigned *classes;
-       char *gpio_chip;
-       const unsigned *gpios;
-       int n_gpios;
-       unsigned idle;
-};
-
-#endif /* _LINUX_I2C_MUX_GPIO_H */
diff --git a/include/linux/i2c-ocores.h b/include/linux/i2c-ocores.h
deleted file mode 100644 (file)
index 01edd96..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * i2c-ocores.h - definitions for the i2c-ocores interface
- *
- * Peter Korsgaard <jacmet@sunsite.dk>
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2.  This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#ifndef _LINUX_I2C_OCORES_H
-#define _LINUX_I2C_OCORES_H
-
-struct ocores_i2c_platform_data {
-       u32 reg_shift; /* register offset shift value */
-       u32 reg_io_width; /* register io read/write width */
-       u32 clock_khz; /* input clock in kHz */
-       bool big_endian; /* registers are big endian */
-       u8 num_devices; /* number of devices in the devices list */
-       struct i2c_board_info const *devices; /* devices connected to the bus */
-};
-
-#endif /* _LINUX_I2C_OCORES_H */
diff --git a/include/linux/i2c-omap.h b/include/linux/i2c-omap.h
deleted file mode 100644 (file)
index 3444265..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __I2C_OMAP_H__
-#define __I2C_OMAP_H__
-
-#include <linux/platform_device.h>
-
-/*
- * Version 2 of the I2C peripheral unit has a different register
- * layout and extra registers.  The ID register in the V2 peripheral
- * unit on the OMAP4430 reports the same ID as the V1 peripheral
- * unit on the OMAP3530, so we must inform the driver which IP
- * version we know it is running on from platform / cpu-specific
- * code using these constants in the hwmod class definition.
- */
-
-#define OMAP_I2C_IP_VERSION_1 1
-#define OMAP_I2C_IP_VERSION_2 2
-
-/* struct omap_i2c_bus_platform_data .flags meanings */
-
-#define OMAP_I2C_FLAG_NO_FIFO                  BIT(0)
-#define OMAP_I2C_FLAG_SIMPLE_CLOCK             BIT(1)
-#define OMAP_I2C_FLAG_16BIT_DATA_REG           BIT(2)
-#define OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK        BIT(5)
-#define OMAP_I2C_FLAG_FORCE_19200_INT_CLK      BIT(6)
-/* how the CPU address bus must be translated for I2C unit access */
-#define OMAP_I2C_FLAG_BUS_SHIFT_NONE 0
-#define OMAP_I2C_FLAG_BUS_SHIFT_1              BIT(7)
-#define OMAP_I2C_FLAG_BUS_SHIFT_2              BIT(8)
-#define OMAP_I2C_FLAG_BUS_SHIFT__SHIFT 7
-
-struct omap_i2c_bus_platform_data {
-       u32             clkrate;
-       u32             rev;
-       u32             flags;
-       void            (*set_mpu_wkup_lat)(struct device *dev, long set);
-};
-
-#endif
diff --git a/include/linux/i2c-pca-platform.h b/include/linux/i2c-pca-platform.h
deleted file mode 100644 (file)
index c373294..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef I2C_PCA9564_PLATFORM_H
-#define I2C_PCA9564_PLATFORM_H
-
-struct i2c_pca9564_pf_platform_data {
-       int i2c_clock_speed;    /* values are defined in linux/i2c-algo-pca.h */
-       int timeout;            /* timeout in jiffies */
-};
-
-#endif /* I2C_PCA9564_PLATFORM_H */
diff --git a/include/linux/i2c-pnx.h b/include/linux/i2c-pnx.h
deleted file mode 100644 (file)
index 5388326..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Header file for I2C support on PNX010x/4008.
- *
- * Author: Dennis Kovalev <dkovalev@ru.mvista.com>
- *
- * 2004-2006 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#ifndef __I2C_PNX_H__
-#define __I2C_PNX_H__
-
-struct platform_device;
-struct clk;
-
-struct i2c_pnx_mif {
-       int                     ret;            /* Return value */
-       int                     mode;           /* Interface mode */
-       struct completion       complete;       /* I/O completion */
-       struct timer_list       timer;          /* Timeout */
-       u8 *                    buf;            /* Data buffer */
-       int                     len;            /* Length of data buffer */
-       int                     order;          /* RX Bytes to order via TX */
-};
-
-struct i2c_pnx_algo_data {
-       void __iomem            *ioaddr;
-       struct i2c_pnx_mif      mif;
-       int                     last;
-       struct clk              *clk;
-       struct i2c_adapter      adapter;
-       int                     irq;
-       u32                     timeout;
-};
-
-#endif /* __I2C_PNX_H__ */
diff --git a/include/linux/i2c-xiic.h b/include/linux/i2c-xiic.h
deleted file mode 100644 (file)
index 4f9f225..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * i2c-xiic.h
- * Copyright (c) 2009 Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/* Supports:
- * Xilinx IIC
- */
-
-#ifndef _LINUX_I2C_XIIC_H
-#define _LINUX_I2C_XIIC_H
-
-/**
- * struct xiic_i2c_platform_data - Platform data of the Xilinx I2C driver
- * @num_devices:       Number of devices that shall be added when the driver
- *                     is probed.
- * @devices:           The actuall devices to add.
- *
- * This purpose of this platform data struct is to be able to provide a number
- * of devices that should be added to the I2C bus. The reason is that sometimes
- * the I2C board info is not enough, a new PCI board can for instance be
- * plugged into a standard PC, and the bus number might be unknown at
- * early init time.
- */
-struct xiic_i2c_platform_data {
-       u8                              num_devices;
-       struct i2c_board_info const     *devices;
-};
-
-#endif /* _LINUX_I2C_XIIC_H */
index 44ad14e016b556f66e4c92adddecd45199794519..254cd34eeae22a0b4a961a376b39bc74031aebb1 100644 (file)
@@ -394,7 +394,6 @@ static inline bool i2c_detect_slave_mode(struct device *dev) { return false; }
  * @addr: stored in i2c_client.addr
  * @dev_name: Overrides the default <busnr>-<addr> dev_name if set
  * @platform_data: stored in i2c_client.dev.platform_data
- * @archdata: copied into i2c_client.dev.archdata
  * @of_node: pointer to OpenFirmware device node
  * @fwnode: device node supplied by the platform firmware
  * @properties: additional device properties for the device
@@ -419,7 +418,6 @@ struct i2c_board_info {
        unsigned short  addr;
        const char      *dev_name;
        void            *platform_data;
-       struct dev_archdata     *archdata;
        struct device_node *of_node;
        struct fwnode_handle *fwnode;
        const struct property_entry *properties;
@@ -903,6 +901,9 @@ extern const struct of_device_id
 *i2c_of_match_device(const struct of_device_id *matches,
                     struct i2c_client *client);
 
+int of_i2c_get_board_info(struct device *dev, struct device_node *node,
+                         struct i2c_board_info *info);
+
 #else
 
 static inline struct i2c_client *of_find_i2c_device_by_node(struct device_node *node)
@@ -927,6 +928,13 @@ static inline const struct of_device_id
        return NULL;
 }
 
+static inline int of_i2c_get_board_info(struct device *dev,
+                                       struct device_node *node,
+                                       struct i2c_board_info *info)
+{
+       return -ENOTSUPP;
+}
+
 #endif /* CONFIG_OF */
 
 #if IS_ENABLED(CONFIG_ACPI)
index 3ecf6f5e3a5f01eb81a67d7456868d43e1fd64ce..b76a1807028ddcdd41df38064a174d36d8748646 100644 (file)
@@ -22,13 +22,27 @@ enum kcov_mode {
        KCOV_MODE_TRACE_CMP = 3,
 };
 
+#define KCOV_IN_CTXSW  (1 << 30)
+
 void kcov_task_init(struct task_struct *t);
 void kcov_task_exit(struct task_struct *t);
 
+#define kcov_prepare_switch(t)                 \
+do {                                           \
+       (t)->kcov_mode |= KCOV_IN_CTXSW;        \
+} while (0)
+
+#define kcov_finish_switch(t)                  \
+do {                                           \
+       (t)->kcov_mode &= ~KCOV_IN_CTXSW;       \
+} while (0)
+
 #else
 
 static inline void kcov_task_init(struct task_struct *t) {}
 static inline void kcov_task_exit(struct task_struct *t) {}
+static inline void kcov_prepare_switch(struct task_struct *t) {}
+static inline void kcov_finish_switch(struct task_struct *t) {}
 
 #endif /* CONFIG_KCOV */
 #endif /* _LINUX_KCOV_H */
index 4f52ec7557254e7a1f2c90dfe4edd63efa6bf8f6..6c6fb116e9258859951b5e96ee6d3da33a274cc4 100644 (file)
@@ -53,6 +53,7 @@ enum memcg_memory_event {
        MEMCG_HIGH,
        MEMCG_MAX,
        MEMCG_OOM,
+       MEMCG_OOM_KILL,
        MEMCG_SWAP_MAX,
        MEMCG_SWAP_FAIL,
        MEMCG_NR_MEMORY_EVENTS,
@@ -720,11 +721,8 @@ static inline void count_memcg_event_mm(struct mm_struct *mm,
 
        rcu_read_lock();
        memcg = mem_cgroup_from_task(rcu_dereference(mm->owner));
-       if (likely(memcg)) {
+       if (likely(memcg))
                count_memcg_events(memcg, idx, 1);
-               if (idx == OOM_KILL)
-                       cgroup_file_notify(&memcg->events_file);
-       }
        rcu_read_unlock();
 }
 
@@ -735,6 +733,21 @@ static inline void memcg_memory_event(struct mem_cgroup *memcg,
        cgroup_file_notify(&memcg->events_file);
 }
 
+static inline void memcg_memory_event_mm(struct mm_struct *mm,
+                                        enum memcg_memory_event event)
+{
+       struct mem_cgroup *memcg;
+
+       if (mem_cgroup_disabled())
+               return;
+
+       rcu_read_lock();
+       memcg = mem_cgroup_from_task(rcu_dereference(mm->owner));
+       if (likely(memcg))
+               memcg_memory_event(memcg, event);
+       rcu_read_unlock();
+}
+
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 void mem_cgroup_split_huge_fixup(struct page *head);
 #endif
@@ -756,6 +769,11 @@ static inline void memcg_memory_event(struct mem_cgroup *memcg,
 {
 }
 
+static inline void memcg_memory_event_mm(struct mm_struct *mm,
+                                        enum memcg_memory_event event)
+{
+}
+
 static inline enum mem_cgroup_protection mem_cgroup_protected(
        struct mem_cgroup *root, struct mem_cgroup *memcg)
 {
index 2014bd19f28eff41ae37b80eba324644c537e291..96a71a648eed991530489ecea56b89d8755b395c 100644 (file)
@@ -501,6 +501,7 @@ enum dmi_field {
        DMI_PRODUCT_VERSION,
        DMI_PRODUCT_SERIAL,
        DMI_PRODUCT_UUID,
+       DMI_PRODUCT_SKU,
        DMI_PRODUCT_FAMILY,
        DMI_BOARD_VENDOR,
        DMI_BOARD_NAME,
index a982bb7cd4806f887811b4928e1154f654cd0474..a78606e8e3df7c155410da7a366490354fb9dcb6 100644 (file)
@@ -81,6 +81,7 @@ extern void done_path_create(struct path *, struct dentry *);
 extern struct dentry *kern_path_locked(const char *, struct path *);
 extern int kern_path_mountpoint(int, const char *, struct path *, unsigned int);
 
+extern struct dentry *try_lookup_one_len(const char *, struct dentry *, int);
 extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
 extern struct dentry *lookup_one_len_unlocked(const char *, struct dentry *, int);
 
index 04551af2ff2309345cfae37a718cdfe4d25e1c8e..dd2052f0efb7742f881cdcf334edc570c7d4d790 100644 (file)
@@ -345,7 +345,7 @@ nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family)
 
        rcu_read_lock();
        nat_hook = rcu_dereference(nf_nat_hook);
-       if (nat_hook->decode_session)
+       if (nat_hook && nat_hook->decode_session)
                nat_hook->decode_session(skb, fl);
        rcu_read_unlock();
 #endif
index bfb3531fd88a4f7811e6ef9fffbaff672dfa6c53..8ce271e187b62f034e6b49140f81e5a8b0d90119 100644 (file)
@@ -23,6 +23,9 @@
 /* Set is defined with timeout support: timeout value may be 0 */
 #define IPSET_NO_TIMEOUT       UINT_MAX
 
+/* Max timeout value, see msecs_to_jiffies() in jiffies.h */
+#define IPSET_MAX_TIMEOUT      (UINT_MAX >> 1)/MSEC_PER_SEC
+
 #define ip_set_adt_opt_timeout(opt, set)       \
 ((opt)->ext.timeout != IPSET_NO_TIMEOUT ? (opt)->ext.timeout : (set)->timeout)
 
@@ -32,11 +35,10 @@ ip_set_timeout_uget(struct nlattr *tb)
        unsigned int timeout = ip_set_get_h32(tb);
 
        /* Normalize to fit into jiffies */
-       if (timeout > UINT_MAX/MSEC_PER_SEC)
-               timeout = UINT_MAX/MSEC_PER_SEC;
+       if (timeout > IPSET_MAX_TIMEOUT)
+               timeout = IPSET_MAX_TIMEOUT;
 
-       /* Userspace supplied TIMEOUT parameter: adjust crazy size */
-       return timeout == IPSET_NO_TIMEOUT ? IPSET_NO_TIMEOUT - 1 : timeout;
+       return timeout;
 }
 
 static inline bool
@@ -65,8 +67,14 @@ ip_set_timeout_set(unsigned long *timeout, u32 value)
 static inline u32
 ip_set_timeout_get(const unsigned long *timeout)
 {
-       return *timeout == IPSET_ELEM_PERMANENT ? 0 :
-               jiffies_to_msecs(*timeout - jiffies)/MSEC_PER_SEC;
+       u32 t;
+
+       if (*timeout == IPSET_ELEM_PERMANENT)
+               return 0;
+
+       t = jiffies_to_msecs(*timeout - jiffies)/MSEC_PER_SEC;
+       /* Zero value in userspace means no timeout */
+       return t == 0 ? 1 : t;
 }
 
 #endif /* __KERNEL__ */
diff --git a/include/linux/platform_data/i2c-gpio.h b/include/linux/platform_data/i2c-gpio.h
new file mode 100644 (file)
index 0000000..352c142
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * i2c-gpio interface to platform code
+ *
+ * Copyright (C) 2007 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef _LINUX_I2C_GPIO_H
+#define _LINUX_I2C_GPIO_H
+
+/**
+ * struct i2c_gpio_platform_data - Platform-dependent data for i2c-gpio
+ * @udelay: signal toggle delay. SCL frequency is (500 / udelay) kHz
+ * @timeout: clock stretching timeout in jiffies. If the slave keeps
+ *     SCL low for longer than this, the transfer will time out.
+ * @sda_is_open_drain: SDA is configured as open drain, i.e. the pin
+ *     isn't actively driven high when setting the output value high.
+ *     gpio_get_value() must return the actual pin state even if the
+ *     pin is configured as an output.
+ * @scl_is_open_drain: SCL is set up as open drain. Same requirements
+ *     as for sda_is_open_drain apply.
+ * @scl_is_output_only: SCL output drivers cannot be turned off.
+ */
+struct i2c_gpio_platform_data {
+       int             udelay;
+       int             timeout;
+       unsigned int    sda_is_open_drain:1;
+       unsigned int    scl_is_open_drain:1;
+       unsigned int    scl_is_output_only:1;
+};
+
+#endif /* _LINUX_I2C_GPIO_H */
diff --git a/include/linux/platform_data/i2c-mux-gpio.h b/include/linux/platform_data/i2c-mux-gpio.h
new file mode 100644 (file)
index 0000000..4406108
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * i2c-mux-gpio interface to platform code
+ *
+ * Peter Korsgaard <peter.korsgaard@barco.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _LINUX_I2C_MUX_GPIO_H
+#define _LINUX_I2C_MUX_GPIO_H
+
+/* MUX has no specific idle mode */
+#define I2C_MUX_GPIO_NO_IDLE   ((unsigned)-1)
+
+/**
+ * struct i2c_mux_gpio_platform_data - Platform-dependent data for i2c-mux-gpio
+ * @parent: Parent I2C bus adapter number
+ * @base_nr: Base I2C bus number to number adapters from or zero for dynamic
+ * @values: Array of bitmasks of GPIO settings (low/high) for each
+ *     position
+ * @n_values: Number of multiplexer positions (busses to instantiate)
+ * @classes: Optional I2C auto-detection classes
+ * @gpio_chip: Optional GPIO chip name; if set, GPIO pin numbers are given
+ *     relative to the base GPIO number of that chip
+ * @gpios: Array of GPIO numbers used to control MUX
+ * @n_gpios: Number of GPIOs used to control MUX
+ * @idle: Bitmask to write to MUX when idle or GPIO_I2CMUX_NO_IDLE if not used
+ */
+struct i2c_mux_gpio_platform_data {
+       int parent;
+       int base_nr;
+       const unsigned *values;
+       int n_values;
+       const unsigned *classes;
+       char *gpio_chip;
+       const unsigned *gpios;
+       int n_gpios;
+       unsigned idle;
+};
+
+#endif /* _LINUX_I2C_MUX_GPIO_H */
diff --git a/include/linux/platform_data/i2c-ocores.h b/include/linux/platform_data/i2c-ocores.h
new file mode 100644 (file)
index 0000000..01edd96
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * i2c-ocores.h - definitions for the i2c-ocores interface
+ *
+ * Peter Korsgaard <jacmet@sunsite.dk>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef _LINUX_I2C_OCORES_H
+#define _LINUX_I2C_OCORES_H
+
+struct ocores_i2c_platform_data {
+       u32 reg_shift; /* register offset shift value */
+       u32 reg_io_width; /* register io read/write width */
+       u32 clock_khz; /* input clock in kHz */
+       bool big_endian; /* registers are big endian */
+       u8 num_devices; /* number of devices in the devices list */
+       struct i2c_board_info const *devices; /* devices connected to the bus */
+};
+
+#endif /* _LINUX_I2C_OCORES_H */
diff --git a/include/linux/platform_data/i2c-omap.h b/include/linux/platform_data/i2c-omap.h
new file mode 100644 (file)
index 0000000..3444265
--- /dev/null
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __I2C_OMAP_H__
+#define __I2C_OMAP_H__
+
+#include <linux/platform_device.h>
+
+/*
+ * Version 2 of the I2C peripheral unit has a different register
+ * layout and extra registers.  The ID register in the V2 peripheral
+ * unit on the OMAP4430 reports the same ID as the V1 peripheral
+ * unit on the OMAP3530, so we must inform the driver which IP
+ * version we know it is running on from platform / cpu-specific
+ * code using these constants in the hwmod class definition.
+ */
+
+#define OMAP_I2C_IP_VERSION_1 1
+#define OMAP_I2C_IP_VERSION_2 2
+
+/* struct omap_i2c_bus_platform_data .flags meanings */
+
+#define OMAP_I2C_FLAG_NO_FIFO                  BIT(0)
+#define OMAP_I2C_FLAG_SIMPLE_CLOCK             BIT(1)
+#define OMAP_I2C_FLAG_16BIT_DATA_REG           BIT(2)
+#define OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK        BIT(5)
+#define OMAP_I2C_FLAG_FORCE_19200_INT_CLK      BIT(6)
+/* how the CPU address bus must be translated for I2C unit access */
+#define OMAP_I2C_FLAG_BUS_SHIFT_NONE 0
+#define OMAP_I2C_FLAG_BUS_SHIFT_1              BIT(7)
+#define OMAP_I2C_FLAG_BUS_SHIFT_2              BIT(8)
+#define OMAP_I2C_FLAG_BUS_SHIFT__SHIFT 7
+
+struct omap_i2c_bus_platform_data {
+       u32             clkrate;
+       u32             rev;
+       u32             flags;
+       void            (*set_mpu_wkup_lat)(struct device *dev, long set);
+};
+
+#endif
diff --git a/include/linux/platform_data/i2c-pca-platform.h b/include/linux/platform_data/i2c-pca-platform.h
new file mode 100644 (file)
index 0000000..c373294
--- /dev/null
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef I2C_PCA9564_PLATFORM_H
+#define I2C_PCA9564_PLATFORM_H
+
+struct i2c_pca9564_pf_platform_data {
+       int i2c_clock_speed;    /* values are defined in linux/i2c-algo-pca.h */
+       int timeout;            /* timeout in jiffies */
+};
+
+#endif /* I2C_PCA9564_PLATFORM_H */
diff --git a/include/linux/platform_data/i2c-xiic.h b/include/linux/platform_data/i2c-xiic.h
new file mode 100644 (file)
index 0000000..4f9f225
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * i2c-xiic.h
+ * Copyright (c) 2009 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Supports:
+ * Xilinx IIC
+ */
+
+#ifndef _LINUX_I2C_XIIC_H
+#define _LINUX_I2C_XIIC_H
+
+/**
+ * struct xiic_i2c_platform_data - Platform data of the Xilinx I2C driver
+ * @num_devices:       Number of devices that shall be added when the driver
+ *                     is probed.
+ * @devices:           The actuall devices to add.
+ *
+ * This purpose of this platform data struct is to be able to provide a number
+ * of devices that should be added to the I2C bus. The reason is that sometimes
+ * the I2C board info is not enough, a new PCI board can for instance be
+ * plugged into a standard PC, and the bus number might be unknown at
+ * early init time.
+ */
+struct xiic_i2c_platform_data {
+       u8                              num_devices;
+       struct i2c_board_info const     *devices;
+};
+
+#endif /* _LINUX_I2C_XIIC_H */
index 2744cff1b297e198041e6982700d2dc9fb9d8c58..19f5cb618c55dbf7bd54f9b6785f2892aecbc28a 100644 (file)
@@ -58,11 +58,10 @@ struct mlxreg_hotplug_device {
  * struct mlxreg_core_data - attributes control data:
  *
  * @label: attribute label;
- * @label: attribute register offset;
  * @reg: attribute register;
  * @mask: attribute access mask;
- * @mode: access mode;
  * @bit: attribute effective bit;
+ * @mode: access mode;
  * @np - pointer to node platform associated with attribute;
  * @hpdev - hotplug device data;
  * @health_cntr: dynamic device health indication counter;
index 997b06634152611155c5e2b6bf093a24373f9e2e..18602cab77991326e2c6128e6a38b73c1bf97b8c 100644 (file)
@@ -7,7 +7,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
- * For further information, see the Documentation/spi/sc18is602 file.
+ * For further information, see the Documentation/spi/spi-sc18is602 file.
  */
 
 /**
index 7c686d335c12ec12c3bc31699db001f72eddfcf1..ee495d707f178fb3e403d37e30e47e9ab66ca350 100644 (file)
@@ -18,9 +18,6 @@
 
 #include <drm/drm_mode.h>
 
-struct sh_mobile_meram_cfg;
-struct sh_mobile_meram_info;
-
 enum shmob_drm_clk_source {
        SHMOB_DRM_CLK_BUS,
        SHMOB_DRM_CLK_PERIPHERAL,
@@ -93,7 +90,6 @@ struct shmob_drm_platform_data {
        struct shmob_drm_interface_data iface;
        struct shmob_drm_panel_data panel;
        struct shmob_drm_backlight_data backlight;
-       const struct sh_mobile_meram_cfg *meram;
 };
 
 #endif /* __SHMOB_DRM_H__ */
index e518352137e796127b4fa5eb7898fe67225e9d13..626fc65c433640c5d6c6302949c9a3028c84a6de 100644 (file)
@@ -14,6 +14,8 @@ struct seq_operations;
 
 #ifdef CONFIG_PROC_FS
 
+typedef int (*proc_write_t)(struct file *, char *, size_t);
+
 extern void proc_root_init(void);
 extern void proc_flush_task(struct task_struct *);
 
@@ -61,6 +63,16 @@ struct proc_dir_entry *proc_create_net_data(const char *name, umode_t mode,
 struct proc_dir_entry *proc_create_net_single(const char *name, umode_t mode,
                struct proc_dir_entry *parent,
                int (*show)(struct seq_file *, void *), void *data);
+struct proc_dir_entry *proc_create_net_data_write(const char *name, umode_t mode,
+                                                 struct proc_dir_entry *parent,
+                                                 const struct seq_operations *ops,
+                                                 proc_write_t write,
+                                                 unsigned int state_size, void *data);
+struct proc_dir_entry *proc_create_net_single_write(const char *name, umode_t mode,
+                                                   struct proc_dir_entry *parent,
+                                                   int (*show)(struct seq_file *, void *),
+                                                   proc_write_t write,
+                                                   void *data);
 
 #else /* CONFIG_PROC_FS */
 
index 61f806a7fe29ec570a1c8f066767ef31c67b3042..a15bc4d487528f4f4301fdb9f30d465799637652 100644 (file)
@@ -71,7 +71,7 @@ struct pstore_record {
        struct pstore_info      *psi;
        enum pstore_type_id     type;
        u64                     id;
-       struct timespec         time;
+       struct timespec64       time;
        char                    *buf;
        ssize_t                 size;
        ssize_t                 ecc_notice_size;
index e4b257ff881bfe439a945d7487f5700f17a26740..bc8206a8f30e6b0c2172e3bc3da3a85cab536cdd 100644 (file)
@@ -109,7 +109,7 @@ static inline void hlist_nulls_add_head_rcu(struct hlist_nulls_node *n,
  *
  * The barrier() is needed to make sure compiler doesn't cache first element [1],
  * as this loop can be restarted [2]
- * [1] Documentation/atomic_ops.txt around line 114
+ * [1] Documentation/core-api/atomic_ops.rst around line 114
  * [2] Documentation/RCU/rculist_nulls.txt around line 146
  */
 #define hlist_nulls_for_each_entry_rcu(tpos, pos, head, member)                        \
index 16e4d984fe51948d092cb093538264a10b2f4135..87bf02d93a279a9b98df452c7ad78a0b54adc1db 100644 (file)
@@ -742,7 +742,7 @@ struct task_struct {
        pid_t                           pid;
        pid_t                           tgid;
 
-#ifdef CONFIG_CC_STACKPROTECTOR
+#ifdef CONFIG_STACKPROTECTOR
        /* Canary value for the -fstack-protector GCC feature: */
        unsigned long                   stack_canary;
 #endif
@@ -1130,7 +1130,7 @@ struct task_struct {
 
 #ifdef CONFIG_KCOV
        /* Coverage collection mode enabled for this task (0 if disabled): */
-       enum kcov_mode                  kcov_mode;
+       unsigned int                    kcov_mode;
 
        /* Size of the kcov_area: */
        unsigned int                    kcov_size;
index 4d759e1ddc335de2cc24d9ba5b55639b66cae39a..14e3fe4bd6a15a4b02f1a0c01268c70ca730ee0c 100644 (file)
@@ -600,6 +600,7 @@ struct memcg_cache_params {
                        struct memcg_cache_array __rcu *memcg_caches;
                        struct list_head __root_caches_node;
                        struct list_head children;
+                       bool dying;
                };
                struct {
                        struct mem_cgroup *memcg;
index 03696c729fb4feeff3fc597f0dfc55304d8a8692..6b792d080eee8f70ce27b5e7c726a98516560090 100644 (file)
@@ -6,7 +6,7 @@
 #include <linux/sched.h>
 #include <linux/random.h>
 
-#ifdef CONFIG_CC_STACKPROTECTOR
+#ifdef CONFIG_STACKPROTECTOR
 # include <asm/stackprotector.h>
 #else
 static inline void boot_init_stack_canary(void)
index 22484e44544d56c8e069b90861f4ce7699c4db66..765573dc17d659d36bf8418d1ba19e66c0c843a4 100644 (file)
@@ -41,10 +41,10 @@ struct kstat {
        kuid_t          uid;
        kgid_t          gid;
        loff_t          size;
-       struct timespec atime;
-       struct timespec mtime;
-       struct timespec ctime;
-       struct timespec btime;                  /* File creation time */
+       struct timespec64 atime;
+       struct timespec64 mtime;
+       struct timespec64 ctime;
+       struct timespec64 btime;                        /* File creation time */
        u64             blocks;
 };
 
index 4397c52ec4a496f61f7c26599a515276c0acc3ee..d23c5030901a2fe91a436a1e449273a543e015ca 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/types.h>
 
 struct file;
+struct task_struct;
 
 /* Descriptions of the types of units to
  * print in */
index c94f466d57ef1ee7b50d5afb57fc07407ea3833c..19a690b559ca1b1850336ffe5133e80db77121f2 100644 (file)
@@ -4,7 +4,7 @@
 /*
  * Kernel Tracepoint API.
  *
- * See Documentation/trace/tracepoints.txt.
+ * See Documentation/trace/tracepoints.rst.
  *
  * Copyright (C) 2008-2014 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
  *
index bbf32524ab279d8e353ca3d9d854a1ab2a12805c..fab02133a9197a43cd9df33728e657e1679c5e16 100644 (file)
@@ -35,7 +35,7 @@ static inline void virtio_rmb(bool weak_barriers)
        if (weak_barriers)
                virt_rmb();
        else
-               rmb();
+               dma_rmb();
 }
 
 static inline void virtio_wmb(bool weak_barriers)
@@ -43,7 +43,7 @@ static inline void virtio_wmb(bool weak_barriers)
        if (weak_barriers)
                virt_wmb();
        else
-               wmb();
+               dma_wmb();
 }
 
 static inline void virtio_store_mb(bool weak_barriers,
index 6d6e21dee46216baca029a4ccd686466a9589b60..a0bec23c6d5e4cd6a01bcec5104e12c27c895b62 100644 (file)
@@ -631,6 +631,7 @@ struct ip_vs_service {
 
        /* alternate persistence engine */
        struct ip_vs_pe __rcu   *pe;
+       int                     conntrack_afmask;
 
        struct rcu_head         rcu_head;
 };
@@ -1611,6 +1612,35 @@ static inline bool ip_vs_conn_uses_conntrack(struct ip_vs_conn *cp,
        return false;
 }
 
+static inline int ip_vs_register_conntrack(struct ip_vs_service *svc)
+{
+#if IS_ENABLED(CONFIG_NF_CONNTRACK)
+       int afmask = (svc->af == AF_INET6) ? 2 : 1;
+       int ret = 0;
+
+       if (!(svc->conntrack_afmask & afmask)) {
+               ret = nf_ct_netns_get(svc->ipvs->net, svc->af);
+               if (ret >= 0)
+                       svc->conntrack_afmask |= afmask;
+       }
+       return ret;
+#else
+       return 0;
+#endif
+}
+
+static inline void ip_vs_unregister_conntrack(struct ip_vs_service *svc)
+{
+#if IS_ENABLED(CONFIG_NF_CONNTRACK)
+       int afmask = (svc->af == AF_INET6) ? 2 : 1;
+
+       if (svc->conntrack_afmask & afmask) {
+               nf_ct_netns_put(svc->ipvs->net, svc->af);
+               svc->conntrack_afmask &= ~afmask;
+       }
+#endif
+}
+
 static inline int
 ip_vs_dest_conn_overhead(struct ip_vs_dest *dest)
 {
index 1910b657243027e3faf36dde94af7ac1b29a0843..3a188a0923a38189f010ebf7d99766d1bd6cea54 100644 (file)
@@ -20,7 +20,8 @@ unsigned int nf_conncount_lookup(struct net *net, struct hlist_head *head,
                                 bool *addit);
 
 bool nf_conncount_add(struct hlist_head *head,
-                     const struct nf_conntrack_tuple *tuple);
+                     const struct nf_conntrack_tuple *tuple,
+                     const struct nf_conntrack_zone *zone);
 
 void nf_conncount_cache_free(struct hlist_head *hhead);
 
diff --git a/include/net/netfilter/nft_dup.h b/include/net/netfilter/nft_dup.h
deleted file mode 100644 (file)
index 4d9d512..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _NFT_DUP_H_
-#define _NFT_DUP_H_
-
-struct nft_dup_inet {
-       enum nft_registers      sreg_addr:8;
-       enum nft_registers      sreg_dev:8;
-};
-
-#endif /* _NFT_DUP_H_ */
index ebf809eed33add7905ddd13abf98712a833ae0e0..dbe1b911a24d31e920f4c31d3c945857b760424b 100644 (file)
@@ -1133,6 +1133,11 @@ struct sctp_input_cb {
 };
 #define SCTP_INPUT_CB(__skb)   ((struct sctp_input_cb *)&((__skb)->cb[0]))
 
+struct sctp_output_cb {
+       struct sk_buff *last;
+};
+#define SCTP_OUTPUT_CB(__skb)  ((struct sctp_output_cb *)&((__skb)->cb[0]))
+
 static inline const struct sk_buff *sctp_gso_headskb(const struct sk_buff *skb)
 {
        const struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk;
index 70c273777fe9fe27b2ef1ba7c2c80970da8ea5c4..7f84ea3e217cf5e3f78698ee63bc9dced179caed 100644 (file)
@@ -109,8 +109,7 @@ struct tls_sw_context_rx {
 
        struct strparser strp;
        void (*saved_data_ready)(struct sock *sk);
-       unsigned int (*sk_poll)(struct file *file, struct socket *sock,
-                               struct poll_table_struct *wait);
+       __poll_t (*sk_poll_mask)(struct socket *sock, __poll_t events);
        struct sk_buff *recv_pkt;
        u8 control;
        bool decrypted;
@@ -225,8 +224,7 @@ void tls_sw_free_resources_tx(struct sock *sk);
 void tls_sw_free_resources_rx(struct sock *sk);
 int tls_sw_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
                   int nonblock, int flags, int *addr_len);
-unsigned int tls_sw_poll(struct file *file, struct socket *sock,
-                        struct poll_table_struct *wait);
+__poll_t tls_sw_poll_mask(struct socket *sock, __poll_t events);
 ssize_t tls_sw_splice_read(struct socket *sock, loff_t *ppos,
                           struct pipe_inode_info *pipe,
                           size_t len, unsigned int flags);
index 75846164290e9acaa9b2fbead09bdebc5422104c..d00221345c1988ff59de79f47401903d560c55e0 100644 (file)
@@ -109,7 +109,7 @@ struct iocb {
 #undef IFLITTLE
 
 struct __aio_sigset {
-       sigset_t __user *sigmask;
+       const sigset_t __user   *sigmask;
        size_t          sigsetsize;
 };
 
index c712eb6879f116010b09815753c750fa678afd87..336014bf8868c3f04b92cdbf31bdf2ccafc68a71 100644 (file)
@@ -112,7 +112,7 @@ enum ip_conntrack_status {
                                 IPS_EXPECTED | IPS_CONFIRMED | IPS_DYING |
                                 IPS_SEQ_ADJUST | IPS_TEMPLATE | IPS_OFFLOAD),
 
-       __IPS_MAX_BIT = 14,
+       __IPS_MAX_BIT = 15,
 };
 
 /* Connection tracking event types */
index c9bf74b94f3704ca66791df3564f01569ec4ba30..89438e68dc030fd0ecf579bf5158e1042435a6b7 100644 (file)
@@ -266,7 +266,7 @@ enum nft_rule_compat_attributes {
  * @NFT_SET_INTERVAL: set contains intervals
  * @NFT_SET_MAP: set is used as a dictionary
  * @NFT_SET_TIMEOUT: set uses timeouts
- * @NFT_SET_EVAL: set contains expressions for evaluation
+ * @NFT_SET_EVAL: set can be updated from the evaluation path
  * @NFT_SET_OBJECT: set contains stateful objects
  */
 enum nft_set_flags {
index 28b36545de2445c338d404ba15b207eb9d0eaab1..27e4e441caacdbd590a1afad65c6f5c1b3ec3edd 100644 (file)
  *     only the %NL80211_ATTR_IE data is used and updated with this command.
  *
  * @NL80211_CMD_SET_PMK: For offloaded 4-Way handshake, set the PMK or PMK-R0
- *     for the given authenticator address (specified with &NL80211_ATTR_MAC).
- *     When &NL80211_ATTR_PMKR0_NAME is set, &NL80211_ATTR_PMK specifies the
+ *     for the given authenticator address (specified with %NL80211_ATTR_MAC).
+ *     When %NL80211_ATTR_PMKR0_NAME is set, %NL80211_ATTR_PMK specifies the
  *     PMK-R0, otherwise it specifies the PMK.
  * @NL80211_CMD_DEL_PMK: For offloaded 4-Way handshake, delete the previously
  *     configured PMK for the authenticator address identified by
- *     &NL80211_ATTR_MAC.
+ *     %NL80211_ATTR_MAC.
  * @NL80211_CMD_PORT_AUTHORIZED: An event that indicates that the 4 way
  *     handshake was completed successfully by the driver. The BSSID is
- *     specified with &NL80211_ATTR_MAC. Drivers that support 4 way handshake
+ *     specified with %NL80211_ATTR_MAC. Drivers that support 4 way handshake
  *     offload should send this event after indicating 802.11 association with
- *     &NL80211_CMD_CONNECT or &NL80211_CMD_ROAM. If the 4 way handshake failed
- *     &NL80211_CMD_DISCONNECT should be indicated instead.
+ *     %NL80211_CMD_CONNECT or %NL80211_CMD_ROAM. If the 4 way handshake failed
+ *     %NL80211_CMD_DISCONNECT should be indicated instead.
  *
  * @NL80211_CMD_CONTROL_PORT_FRAME: Control Port (e.g. PAE) frame TX request
  *     and RX notification.  This command is used both as a request to transmit
  *     initiated the connection through the connect request.
  *
  * @NL80211_CMD_STA_OPMODE_CHANGED: An event that notify station's
- *     ht opmode or vht opmode changes using any of &NL80211_ATTR_SMPS_MODE,
- *     &NL80211_ATTR_CHANNEL_WIDTH,&NL80211_ATTR_NSS attributes with its
- *     address(specified in &NL80211_ATTR_MAC).
+ *     ht opmode or vht opmode changes using any of %NL80211_ATTR_SMPS_MODE,
+ *     %NL80211_ATTR_CHANNEL_WIDTH,%NL80211_ATTR_NSS attributes with its
+ *     address(specified in %NL80211_ATTR_MAC).
  *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
@@ -2218,7 +2218,7 @@ enum nl80211_commands {
  * @NL80211_ATTR_EXTERNAL_AUTH_ACTION: Identify the requested external
  *     authentication operation (u32 attribute with an
  *     &enum nl80211_external_auth_action value). This is used with the
- *     &NL80211_CMD_EXTERNAL_AUTH request event.
+ *     %NL80211_CMD_EXTERNAL_AUTH request event.
  * @NL80211_ATTR_EXTERNAL_AUTH_SUPPORT: Flag attribute indicating that the user
  *     space supports external authentication. This attribute shall be used
  *     only with %NL80211_CMD_CONNECT request. The driver may offload
@@ -3491,7 +3491,7 @@ enum nl80211_sched_scan_match_attr {
  * @NL80211_RRF_AUTO_BW: maximum available bandwidth should be calculated
  *     base on contiguous rules and wider channels will be allowed to cross
  *     multiple contiguous/overlapping frequency ranges.
- * @NL80211_RRF_IR_CONCURRENT: See &NL80211_FREQUENCY_ATTR_IR_CONCURRENT
+ * @NL80211_RRF_IR_CONCURRENT: See %NL80211_FREQUENCY_ATTR_IR_CONCURRENT
  * @NL80211_RRF_NO_HT40MINUS: channels can't be used in HT40- operation
  * @NL80211_RRF_NO_HT40PLUS: channels can't be used in HT40+ operation
  * @NL80211_RRF_NO_80MHZ: 80MHz operation not allowed
@@ -5643,11 +5643,11 @@ enum nl80211_nan_func_attributes {
  * @NL80211_NAN_SRF_INCLUDE: present if the include bit of the SRF set.
  *     This is a flag.
  * @NL80211_NAN_SRF_BF: Bloom Filter. Present if and only if
- *     &NL80211_NAN_SRF_MAC_ADDRS isn't present. This attribute is binary.
+ *     %NL80211_NAN_SRF_MAC_ADDRS isn't present. This attribute is binary.
  * @NL80211_NAN_SRF_BF_IDX: index of the Bloom Filter. Mandatory if
- *     &NL80211_NAN_SRF_BF is present. This is a u8.
+ *     %NL80211_NAN_SRF_BF is present. This is a u8.
  * @NL80211_NAN_SRF_MAC_ADDRS: list of MAC addresses for the SRF. Present if
- *     and only if &NL80211_NAN_SRF_BF isn't present. This is a nested
+ *     and only if %NL80211_NAN_SRF_BF isn't present. This is a nested
  *     attribute. Each nested attribute is a MAC address.
  * @NUM_NL80211_NAN_SRF_ATTR: internal
  * @NL80211_NAN_SRF_ATTR_MAX: highest NAN SRF attribute
index db9f15f5db047e643780ce23a0d33f9cc599ddf4..c0d7ea0bf5b62438ca8184551b64d5d29ad7951b 100644 (file)
@@ -170,7 +170,7 @@ struct prctl_mm_map {
  * asking selinux for a specific new context (e.g. with runcon) will result
  * in execve returning -EPERM.
  *
- * See Documentation/prctl/no_new_privs.txt for more details.
+ * See Documentation/userspace-api/no_new_privs.rst for more details.
  */
 #define PR_SET_NO_NEW_PRIVS    38
 #define PR_GET_NO_NEW_PRIVS    39
index 13d98e6e0db1a86f46cc7d77b5652bef0c8682d2..74e520fb944f7dbdf6426e75b5db5312a80b05ee 100644 (file)
@@ -230,6 +230,14 @@ struct uac1_output_terminal_descriptor {
 #define UAC_OUTPUT_TERMINAL_COMMUNICATION_SPEAKER      0x306
 #define UAC_OUTPUT_TERMINAL_LOW_FREQ_EFFECTS_SPEAKER   0x307
 
+/* Terminals - 2.4 Bi-directional Terminal Types */
+#define UAC_BIDIR_TERMINAL_UNDEFINED                   0x400
+#define UAC_BIDIR_TERMINAL_HANDSET                     0x401
+#define UAC_BIDIR_TERMINAL_HEADSET                     0x402
+#define UAC_BIDIR_TERMINAL_SPEAKER_PHONE               0x403
+#define UAC_BIDIR_TERMINAL_ECHO_SUPPRESSING            0x404
+#define UAC_BIDIR_TERMINAL_ECHO_CANCELING              0x405
+
 /* Set bControlSize = 2 as default setting */
 #define UAC_DT_FEATURE_UNIT_SIZE(ch)           (7 + ((ch) + 1) * 2)
 
index 308e2096291f8f109185848f3baea431253161da..449132c76b1cc809fc0c9d4cd90e3f56ed44442b 100644 (file)
 /* We've given up on this device. */
 #define VIRTIO_CONFIG_S_FAILED         0x80
 
-/* Some virtio feature bits (currently bits 28 through 32) are reserved for the
- * transport being used (eg. virtio_ring), the rest are per-device feature
- * bits. */
+/*
+ * Virtio feature bits VIRTIO_TRANSPORT_F_START through
+ * VIRTIO_TRANSPORT_F_END are reserved for the transport
+ * being used (e.g. virtio_ring, virtio_pci etc.), the
+ * rest are per-device feature bits.
+ */
 #define VIRTIO_TRANSPORT_F_START       28
-#define VIRTIO_TRANSPORT_F_END         34
+#define VIRTIO_TRANSPORT_F_END         38
 
 #ifndef VIRTIO_CONFIG_NO_LEGACY
 /* Do we get callbacks when the ring is completely used, even if we've
@@ -71,4 +74,9 @@
  * this is for compatibility with legacy systems.
  */
 #define VIRTIO_F_IOMMU_PLATFORM                33
+
+/*
+ * Does the device support Single Root I/O Virtualization?
+ */
+#define VIRTIO_F_SR_IOV                        37
 #endif /* _UAPI_LINUX_VIRTIO_CONFIG_H */
diff --git a/include/video/auo_k190xfb.h b/include/video/auo_k190xfb.h
deleted file mode 100644 (file)
index ac329ee..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Definitions for AUO-K190X framebuffer drivers
- *
- * Copyright (C) 2012 Heiko Stuebner <heiko@sntech.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _LINUX_VIDEO_AUO_K190XFB_H_
-#define _LINUX_VIDEO_AUO_K190XFB_H_
-
-/* Controller standby command needs a param */
-#define AUOK190X_QUIRK_STANDBYPARAM    (1 << 0)
-
-/* Controller standby is completely broken */
-#define AUOK190X_QUIRK_STANDBYBROKEN   (1 << 1)
-
-/*
- * Resolutions for the displays
- */
-#define AUOK190X_RESOLUTION_800_600            0
-#define AUOK190X_RESOLUTION_1024_768           1
-#define AUOK190X_RESOLUTION_600_800            4
-#define AUOK190X_RESOLUTION_768_1024           5
-
-/*
- * struct used by auok190x. board specific stuff comes from *board
- */
-struct auok190xfb_par {
-       struct fb_info *info;
-       struct auok190x_board *board;
-
-       struct regulator *regulator;
-
-       struct mutex io_lock;
-       struct delayed_work work;
-       wait_queue_head_t waitq;
-       int resolution;
-       int rotation;
-       int consecutive_threshold;
-       int update_cnt;
-
-       /* panel and controller informations */
-       int epd_type;
-       int panel_size_int;
-       int panel_size_float;
-       int panel_model;
-       int tcon_version;
-       int lut_version;
-
-       /* individual controller callbacks */
-       void (*update_partial)(struct auok190xfb_par *par, u16 y1, u16 y2);
-       void (*update_all)(struct auok190xfb_par *par);
-       bool (*need_refresh)(struct auok190xfb_par *par);
-       void (*init)(struct auok190xfb_par *par);
-       void (*recover)(struct auok190xfb_par *par);
-
-       int update_mode; /* mode to use for updates */
-       int last_mode; /* update mode last used */
-       int flash;
-
-       /* power management */
-       int autosuspend_delay;
-       bool standby;
-       bool manual_standby;
-};
-
-/**
- * Board specific platform-data
- * @init:              initialize the controller interface
- * @cleanup:           cleanup the controller interface
- * @wait_for_rdy:      wait until the controller is not busy anymore
- * @set_ctl:           change an interface control
- * @set_hdb:           write a value to the data register
- * @get_hdb:           read a value from the data register
- * @setup_irq:         method to setup the irq handling on the busy gpio
- * @gpio_nsleep:       sleep gpio
- * @gpio_nrst:         reset gpio
- * @gpio_nbusy:                busy gpio
- * @resolution:                one of the AUOK190X_RESOLUTION constants
- * @rotation:          rotation of the framebuffer
- * @quirks:            controller quirks to honor
- * @fps:               frames per second for defio
- */
-struct auok190x_board {
-       int (*init)(struct auok190xfb_par *);
-       void (*cleanup)(struct auok190xfb_par *);
-       int (*wait_for_rdy)(struct auok190xfb_par *);
-
-       void (*set_ctl)(struct auok190xfb_par *, unsigned char, u8);
-       void (*set_hdb)(struct auok190xfb_par *, u16);
-       u16 (*get_hdb)(struct auok190xfb_par *);
-
-       int (*setup_irq)(struct fb_info *);
-
-       int gpio_nsleep;
-       int gpio_nrst;
-       int gpio_nbusy;
-
-       int resolution;
-       int quirks;
-       int fps;
-};
-
-#endif
index f706b0fed399df1f6aec9dc56580cf3878e8cd72..84aa976ca4ea44e161fd3cd9f54b60d015761ca9 100644 (file)
@@ -3,7 +3,6 @@
 #define __ASM_SH_MOBILE_LCDC_H__
 
 #include <linux/fb.h>
-#include <video/sh_mobile_meram.h>
 
 /* Register definitions */
 #define _LDDCKR                        0x410
@@ -184,7 +183,6 @@ struct sh_mobile_lcdc_chan_cfg {
        struct sh_mobile_lcdc_panel_cfg panel_cfg;
        struct sh_mobile_lcdc_bl_info bl_info;
        struct sh_mobile_lcdc_sys_bus_cfg sys_bus_cfg; /* only for SYSn I/F */
-       const struct sh_mobile_meram_cfg *meram_cfg;
 
        struct platform_device *tx_dev; /* HDMI/DSI transmitter device */
 };
@@ -193,7 +191,6 @@ struct sh_mobile_lcdc_info {
        int clock_source;
        struct sh_mobile_lcdc_chan_cfg ch[2];
        struct sh_mobile_lcdc_overlay_cfg overlays[4];
-       struct sh_mobile_meram_info *meram_dev;
 };
 
 #endif /* __ASM_SH_MOBILE_LCDC_H__ */
diff --git a/include/video/sh_mobile_meram.h b/include/video/sh_mobile_meram.h
deleted file mode 100644 (file)
index f4efc21..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __VIDEO_SH_MOBILE_MERAM_H__
-#define __VIDEO_SH_MOBILE_MERAM_H__
-
-/* For sh_mobile_meram_info.addr_mode */
-enum {
-       SH_MOBILE_MERAM_MODE0 = 0,
-       SH_MOBILE_MERAM_MODE1
-};
-
-enum {
-       SH_MOBILE_MERAM_PF_NV = 0,
-       SH_MOBILE_MERAM_PF_RGB,
-       SH_MOBILE_MERAM_PF_NV24
-};
-
-
-struct sh_mobile_meram_priv;
-
-/*
- * struct sh_mobile_meram_info - MERAM platform data
- * @reserved_icbs: Bitmask of reserved ICBs (for instance used through UIO)
- */
-struct sh_mobile_meram_info {
-       int                             addr_mode;
-       u32                             reserved_icbs;
-       struct sh_mobile_meram_priv     *priv;
-       struct platform_device          *pdev;
-};
-
-/* icb config */
-struct sh_mobile_meram_icb_cfg {
-       unsigned int meram_size;        /* MERAM Buffer Size to use */
-};
-
-struct sh_mobile_meram_cfg {
-       struct sh_mobile_meram_icb_cfg icb[2];
-};
-
-#if defined(CONFIG_FB_SH_MOBILE_MERAM) || \
-    defined(CONFIG_FB_SH_MOBILE_MERAM_MODULE)
-unsigned long sh_mobile_meram_alloc(struct sh_mobile_meram_info *meram_dev,
-                                   size_t size);
-void sh_mobile_meram_free(struct sh_mobile_meram_info *meram_dev,
-                         unsigned long mem, size_t size);
-void *sh_mobile_meram_cache_alloc(struct sh_mobile_meram_info *dev,
-                                 const struct sh_mobile_meram_cfg *cfg,
-                                 unsigned int xres, unsigned int yres,
-                                 unsigned int pixelformat,
-                                 unsigned int *pitch);
-void sh_mobile_meram_cache_free(struct sh_mobile_meram_info *dev, void *data);
-void sh_mobile_meram_cache_update(struct sh_mobile_meram_info *dev, void *data,
-                                 unsigned long base_addr_y,
-                                 unsigned long base_addr_c,
-                                 unsigned long *icb_addr_y,
-                                 unsigned long *icb_addr_c);
-#else
-static inline unsigned long
-sh_mobile_meram_alloc(struct sh_mobile_meram_info *meram_dev, size_t size)
-{
-       return 0;
-}
-
-static inline void
-sh_mobile_meram_free(struct sh_mobile_meram_info *meram_dev,
-                    unsigned long mem, size_t size)
-{
-}
-
-static inline void *
-sh_mobile_meram_cache_alloc(struct sh_mobile_meram_info *dev,
-                           const struct sh_mobile_meram_cfg *cfg,
-                           unsigned int xres, unsigned int yres,
-                           unsigned int pixelformat,
-                           unsigned int *pitch)
-{
-       return ERR_PTR(-ENODEV);
-}
-
-static inline void
-sh_mobile_meram_cache_free(struct sh_mobile_meram_info *dev, void *data)
-{
-}
-
-static inline void
-sh_mobile_meram_cache_update(struct sh_mobile_meram_info *dev, void *data,
-                            unsigned long base_addr_y,
-                            unsigned long base_addr_c,
-                            unsigned long *icb_addr_y,
-                            unsigned long *icb_addr_c)
-{
-}
-#endif
-
-#endif /* __VIDEO_SH_MOBILE_MERAM_H__  */
index 2a9510ade70181a4c10b65bdfc834d831ef8b287..e2340a4130cf932d4cc74f7883a984fe735f732d 100644 (file)
@@ -317,7 +317,7 @@ struct xenkbd_position {
  * Linux [2] and Windows [3] multi-touch support.
  *
  * [1] https://cgit.freedesktop.org/wayland/wayland/tree/protocol/wayland.xml
- * [2] https://www.kernel.org/doc/Documentation/input/multi-touch-protocol.txt
+ * [2] https://www.kernel.org/doc/Documentation/input/multi-touch-protocol.rst
  * [3] https://msdn.microsoft.com/en-us/library/jj151564(v=vs.85).aspx
  *
  *
index 59a3cd1d3252426c24cc83f08b0960af75386fe5..5af1943ad782b415a3dd331161e9b2ecccf89210 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -85,6 +85,7 @@
 #include <linux/nsproxy.h>
 #include <linux/ipc_namespace.h>
 #include <linux/sched/wake_q.h>
+#include <linux/nospec.h>
 
 #include <linux/uaccess.h>
 #include "util.h"
@@ -368,6 +369,7 @@ static inline int sem_lock(struct sem_array *sma, struct sembuf *sops,
                              int nsops)
 {
        struct sem *sem;
+       int idx;
 
        if (nsops != 1) {
                /* Complex operation - acquire a full lock */
@@ -385,7 +387,8 @@ static inline int sem_lock(struct sem_array *sma, struct sembuf *sops,
         *
         * Both facts are tracked by use_global_mode.
         */
-       sem = &sma->sems[sops->sem_num];
+       idx = array_index_nospec(sops->sem_num, sma->sem_nsems);
+       sem = &sma->sems[idx];
 
        /*
         * Initial check for use_global_lock. Just an optimization,
@@ -638,7 +641,8 @@ static int perform_atomic_semop_slow(struct sem_array *sma, struct sem_queue *q)
        un = q->undo;
 
        for (sop = sops; sop < sops + nsops; sop++) {
-               curr = &sma->sems[sop->sem_num];
+               int idx = array_index_nospec(sop->sem_num, sma->sem_nsems);
+               curr = &sma->sems[idx];
                sem_op = sop->sem_op;
                result = curr->semval;
 
@@ -718,7 +722,9 @@ static int perform_atomic_semop(struct sem_array *sma, struct sem_queue *q)
         * until the operations can go through.
         */
        for (sop = sops; sop < sops + nsops; sop++) {
-               curr = &sma->sems[sop->sem_num];
+               int idx = array_index_nospec(sop->sem_num, sma->sem_nsems);
+
+               curr = &sma->sems[idx];
                sem_op = sop->sem_op;
                result = curr->semval;
 
@@ -1356,6 +1362,7 @@ static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum,
                return -EIDRM;
        }
 
+       semnum = array_index_nospec(semnum, sma->sem_nsems);
        curr = &sma->sems[semnum];
 
        ipc_assert_locked_object(&sma->sem_perm);
@@ -1509,6 +1516,8 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                err = -EIDRM;
                goto out_unlock;
        }
+
+       semnum = array_index_nospec(semnum, nsems);
        curr = &sma->sems[semnum];
 
        switch (cmd) {
@@ -2081,7 +2090,8 @@ static long do_semtimedop(int semid, struct sembuf __user *tsops,
         */
        if (nsops == 1) {
                struct sem *curr;
-               curr = &sma->sems[sops->sem_num];
+               int idx = array_index_nospec(sops->sem_num, sma->sem_nsems);
+               curr = &sma->sems[idx];
 
                if (alter) {
                        if (sma->complex_count) {
index 29978ee76c2e95a8f10c73c8f5322337afe7ca2a..051a3e1fb8df9b2bcb2073e8299d31cdfc938724 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -408,7 +408,7 @@ void exit_shm(struct task_struct *task)
        up_write(&shm_ids(ns).rwsem);
 }
 
-static int shm_fault(struct vm_fault *vmf)
+static vm_fault_t shm_fault(struct vm_fault *vmf)
 {
        struct file *file = vmf->vma->vm_file;
        struct shm_file_data *sfd = shm_file_data(file);
index 52f368b6561e984e5b93b8e71bc56cb80f3683aa..fba78047fb37c525f6fa0a16e74418aa31b569cf 100644 (file)
@@ -109,7 +109,7 @@ struct audit_fsnotify_mark *audit_alloc_mark(struct audit_krule *krule, char *pa
        audit_update_mark(audit_mark, dentry->d_inode);
        audit_mark->rule = krule;
 
-       ret = fsnotify_add_mark(&audit_mark->mark, inode, NULL, true);
+       ret = fsnotify_add_inode_mark(&audit_mark->mark, inode, true);
        if (ret < 0) {
                fsnotify_put_mark(&audit_mark->mark);
                audit_mark = ERR_PTR(ret);
@@ -165,12 +165,11 @@ static void audit_autoremove_mark_rule(struct audit_fsnotify_mark *audit_mark)
 /* Update mark data in audit rules based on fsnotify events. */
 static int audit_mark_handle_event(struct fsnotify_group *group,
                                    struct inode *to_tell,
-                                   struct fsnotify_mark *inode_mark,
-                                   struct fsnotify_mark *vfsmount_mark,
                                    u32 mask, const void *data, int data_type,
                                    const unsigned char *dname, u32 cookie,
                                    struct fsnotify_iter_info *iter_info)
 {
+       struct fsnotify_mark *inode_mark = fsnotify_iter_inode_mark(iter_info);
        struct audit_fsnotify_mark *audit_mark;
        const struct inode *inode = NULL;
 
index 67e6956c0b61d0c2c08aa3f21546bd16696b4e75..c99ebaae5abce26ffad74f0bef100373069a7b37 100644 (file)
@@ -288,8 +288,8 @@ static void untag_chunk(struct node *p)
        if (!new)
                goto Fallback;
 
-       if (fsnotify_add_mark_locked(&new->mark, entry->connector->inode,
-                                    NULL, 1)) {
+       if (fsnotify_add_inode_mark_locked(&new->mark, entry->connector->inode,
+                                          1)) {
                fsnotify_put_mark(&new->mark);
                goto Fallback;
        }
@@ -354,7 +354,7 @@ static int create_chunk(struct inode *inode, struct audit_tree *tree)
                return -ENOMEM;
 
        entry = &chunk->mark;
-       if (fsnotify_add_mark(entry, inode, NULL, 0)) {
+       if (fsnotify_add_inode_mark(entry, inode, 0)) {
                fsnotify_put_mark(entry);
                return -ENOSPC;
        }
@@ -434,8 +434,8 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree)
                return -ENOENT;
        }
 
-       if (fsnotify_add_mark_locked(chunk_entry,
-                            old_entry->connector->inode, NULL, 1)) {
+       if (fsnotify_add_inode_mark_locked(chunk_entry,
+                            old_entry->connector->inode, 1)) {
                spin_unlock(&old_entry->lock);
                mutex_unlock(&old_entry->group->mark_mutex);
                fsnotify_put_mark(chunk_entry);
@@ -989,8 +989,6 @@ static void evict_chunk(struct audit_chunk *chunk)
 
 static int audit_tree_handle_event(struct fsnotify_group *group,
                                   struct inode *to_tell,
-                                  struct fsnotify_mark *inode_mark,
-                                  struct fsnotify_mark *vfsmount_mark,
                                   u32 mask, const void *data, int data_type,
                                   const unsigned char *file_name, u32 cookie,
                                   struct fsnotify_iter_info *iter_info)
index f1ba88994508baacf34fa8d8d04e57ec33e8cec5..c17c0c268436807211cc411f888c8bdffd9da8f4 100644 (file)
@@ -160,7 +160,7 @@ static struct audit_parent *audit_init_parent(struct path *path)
 
        fsnotify_init_mark(&parent->mark, audit_watch_group);
        parent->mark.mask = AUDIT_FS_WATCH;
-       ret = fsnotify_add_mark(&parent->mark, inode, NULL, 0);
+       ret = fsnotify_add_inode_mark(&parent->mark, inode, 0);
        if (ret < 0) {
                audit_free_parent(parent);
                return ERR_PTR(ret);
@@ -472,12 +472,11 @@ void audit_remove_watch_rule(struct audit_krule *krule)
 /* Update watch data in audit rules based on fsnotify events. */
 static int audit_watch_handle_event(struct fsnotify_group *group,
                                    struct inode *to_tell,
-                                   struct fsnotify_mark *inode_mark,
-                                   struct fsnotify_mark *vfsmount_mark,
                                    u32 mask, const void *data, int data_type,
                                    const unsigned char *dname, u32 cookie,
                                    struct fsnotify_iter_info *iter_info)
 {
+       struct fsnotify_mark *inode_mark = fsnotify_iter_inode_mark(iter_info);
        const struct inode *inode;
        struct audit_parent *parent;
 
index ed13645bd80c48ea3e16e999cbd598182e934e63..76efe9a183f5313de5cc0b43f2bc4fc446d9bf6a 100644 (file)
@@ -295,6 +295,15 @@ static const struct file_operations bpffs_map_fops = {
        .release        = bpffs_map_release,
 };
 
+static int bpffs_obj_open(struct inode *inode, struct file *file)
+{
+       return -EIO;
+}
+
+static const struct file_operations bpffs_obj_fops = {
+       .open           = bpffs_obj_open,
+};
+
 static int bpf_mkobj_ops(struct dentry *dentry, umode_t mode, void *raw,
                         const struct inode_operations *iops,
                         const struct file_operations *fops)
@@ -314,7 +323,8 @@ static int bpf_mkobj_ops(struct dentry *dentry, umode_t mode, void *raw,
 
 static int bpf_mkprog(struct dentry *dentry, umode_t mode, void *arg)
 {
-       return bpf_mkobj_ops(dentry, mode, arg, &bpf_prog_iops, NULL);
+       return bpf_mkobj_ops(dentry, mode, arg, &bpf_prog_iops,
+                            &bpffs_obj_fops);
 }
 
 static int bpf_mkmap(struct dentry *dentry, umode_t mode, void *arg)
@@ -322,7 +332,7 @@ static int bpf_mkmap(struct dentry *dentry, umode_t mode, void *arg)
        struct bpf_map *map = arg;
 
        return bpf_mkobj_ops(dentry, mode, arg, &bpf_map_iops,
-                            map->btf ? &bpffs_map_fops : NULL);
+                            map->btf ? &bpffs_map_fops : &bpffs_obj_fops);
 }
 
 static struct dentry *
index d8b12e0d39cd8e3b2f4733e1ce1dee2f2486ac12..266f10cb7222b558aca0a777206d7bc747912750 100644 (file)
@@ -605,7 +605,7 @@ static inline int nr_cpusets(void)
  * load balancing domains (sched domains) as specified by that partial
  * partition.
  *
- * See "What is sched_load_balance" in Documentation/cgroups/cpusets.txt
+ * See "What is sched_load_balance" in Documentation/cgroup-v1/cpusets.txt
  * for a background explanation of this.
  *
  * Does not return errors, on the theory that the callers of this
index 946fb92418f7915af8fd28a1f6db2574e1937e53..81e9af7dcec2bf4bec26e72a83109ffa958d1e43 100644 (file)
@@ -12,7 +12,7 @@ CONFIG_BLK_DEV_DM=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_CC_STACKPROTECTOR_STRONG=y
+CONFIG_STACKPROTECTOR_STRONG=y
 CONFIG_COMPACTION=y
 CONFIG_CPU_SW_DOMAIN_PAN=y
 CONFIG_DM_CRYPT=y
index 9bfdffc100da48338c71a76b1a74a4f176f8ecdc..7fa0c4ae6394f028fa09694b219314dd3d7d8731 100644 (file)
@@ -10,7 +10,3 @@ CONFIG_OPTIMIZE_INLINING=y
 # CONFIG_SLAB is not set
 # CONFIG_SLUB is not set
 CONFIG_SLOB=y
-CONFIG_CC_STACKPROTECTOR_NONE=y
-# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
-# CONFIG_CC_STACKPROTECTOR_STRONG is not set
-# CONFIG_CC_STACKPROTECTOR_AUTO is not set
index 08c6e5e217a0355f39431634746b7bff10621263..9440d61b925ca08faa3beb7d3a02fedfdd0a9b84 100644 (file)
@@ -440,6 +440,14 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm,
                        continue;
                }
                charge = 0;
+               /*
+                * Don't duplicate many vmas if we've been oom-killed (for
+                * example)
+                */
+               if (fatal_signal_pending(current)) {
+                       retval = -EINTR;
+                       goto out;
+               }
                if (mpnt->vm_flags & VM_ACCOUNT) {
                        unsigned long len = vma_pages(mpnt);
 
@@ -811,7 +819,7 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node)
        clear_tsk_need_resched(tsk);
        set_task_stack_end_magic(tsk);
 
-#ifdef CONFIG_CC_STACKPROTECTOR
+#ifdef CONFIG_STACKPROTECTOR
        tsk->stack_canary = get_random_canary();
 #endif
 
index 2c16f1ab5e107562a8f9ade9735d97d0277931fd..3ebd09efe72a67fcc1e88761e91e306880c5ae0a 100644 (file)
@@ -58,7 +58,7 @@ struct kcov {
 
 static bool check_kcov_mode(enum kcov_mode needed_mode, struct task_struct *t)
 {
-       enum kcov_mode mode;
+       unsigned int mode;
 
        /*
         * We are interested in code coverage as a function of a syscall inputs,
@@ -241,7 +241,8 @@ static void kcov_put(struct kcov *kcov)
 
 void kcov_task_init(struct task_struct *t)
 {
-       t->kcov_mode = KCOV_MODE_DISABLED;
+       WRITE_ONCE(t->kcov_mode, KCOV_MODE_DISABLED);
+       barrier();
        t->kcov_size = 0;
        t->kcov_area = NULL;
        t->kcov = NULL;
@@ -323,6 +324,21 @@ static int kcov_close(struct inode *inode, struct file *filep)
        return 0;
 }
 
+/*
+ * Fault in a lazily-faulted vmalloc area before it can be used by
+ * __santizer_cov_trace_pc(), to avoid recursion issues if any code on the
+ * vmalloc fault handling path is instrumented.
+ */
+static void kcov_fault_in_area(struct kcov *kcov)
+{
+       unsigned long stride = PAGE_SIZE / sizeof(unsigned long);
+       unsigned long *area = kcov->area;
+       unsigned long offset;
+
+       for (offset = 0; offset < kcov->size; offset += stride)
+               READ_ONCE(area[offset]);
+}
+
 static int kcov_ioctl_locked(struct kcov *kcov, unsigned int cmd,
                             unsigned long arg)
 {
@@ -371,6 +387,7 @@ static int kcov_ioctl_locked(struct kcov *kcov, unsigned int cmd,
 #endif
                else
                        return -EINVAL;
+               kcov_fault_in_area(kcov);
                /* Cache in task struct for performance. */
                t->kcov_size = kcov->size;
                t->kcov_area = kcov->area;
index 20fef1a38602d9d0ed6fdb5d359d5604fbafc3dd..23a83a4da38a1dffc5203c828a384531b6cce9b2 100644 (file)
@@ -829,6 +829,8 @@ static int kimage_load_normal_segment(struct kimage *image,
                else
                        buf += mchunk;
                mbytes -= mchunk;
+
+               cond_resched();
        }
 out:
        return result;
@@ -893,6 +895,8 @@ static int kimage_load_crash_segment(struct kimage *image,
                else
                        buf += mchunk;
                mbytes -= mchunk;
+
+               cond_resched();
        }
 out:
        return result;
index 68469b37d61a0c87e6a78a53006334cdcef8b7d5..f475f30eed8c031abc5e88241ee5088056dbb664 100644 (file)
@@ -274,9 +274,7 @@ static void module_assert_mutex_or_preempt(void)
 }
 
 static bool sig_enforce = IS_ENABLED(CONFIG_MODULE_SIG_FORCE);
-#ifndef CONFIG_MODULE_SIG_FORCE
 module_param(sig_enforce, bool_enable_only, 0644);
-#endif /* !CONFIG_MODULE_SIG_FORCE */
 
 /*
  * Export sig_enforce kernel cmdline parameter to allow other subsystems rely
@@ -2785,7 +2783,7 @@ static int module_sig_check(struct load_info *info, int flags)
        }
 
        /* Not having a signature is only an error if we're strict. */
-       if (err == -ENOKEY && !sig_enforce)
+       if (err == -ENOKEY && !is_module_sig_enforced())
                err = 0;
 
        return err;
index 42e48748855420af5fa2a0d45f04e54298546b9e..8b2e002d52eb0e6c927876077bddfcd0565d7929 100644 (file)
@@ -623,7 +623,7 @@ static __init int register_warn_debugfs(void)
 device_initcall(register_warn_debugfs);
 #endif
 
-#ifdef CONFIG_CC_STACKPROTECTOR
+#ifdef CONFIG_STACKPROTECTOR
 
 /*
  * Called when gcc's -fstack-protector feature is used, and
index 705c2366dafe19c13f011885df1e2ae93c2687e7..d9706da1093036dbdbce61e7cf74b2f410c8a99d 100644 (file)
@@ -455,8 +455,9 @@ struct kobject *power_kobj;
  * state - control system sleep states.
  *
  * show() returns available sleep state labels, which may be "mem", "standby",
- * "freeze" and "disk" (hibernation).  See Documentation/power/states.txt for a
- * description of what they mean.
+ * "freeze" and "disk" (hibernation).
+ * See Documentation/admin-guide/pm/sleep-states.rst for a description of
+ * what they mean.
  *
  * store() accepts one of those strings, translates it into the proper
  * enumerated value, and initiates a suspend transition.
index 9f5326e8a036fd261de4e290ca7364a2eaaa8c22..04f248644e065f601d78744be2bbe580a6aa1810 100644 (file)
@@ -39,7 +39,7 @@ static void relay_file_mmap_close(struct vm_area_struct *vma)
 /*
  * fault() vm_op implementation for relay file mapping.
  */
-static int relay_buf_fault(struct vm_fault *vmf)
+static vm_fault_t relay_buf_fault(struct vm_fault *vmf)
 {
        struct page *page;
        struct rchan_buf *buf = vmf->vma->vm_private_data;
index a98d54cd553502cb3f983416c0aae0fdac3d6a17..78d8facba456c2fc44c7024ae1a1c8d9db6f0692 100644 (file)
@@ -10,6 +10,8 @@
 #include <linux/kthread.h>
 #include <linux/nospec.h>
 
+#include <linux/kcov.h>
+
 #include <asm/switch_to.h>
 #include <asm/tlb.h>
 
@@ -2633,6 +2635,7 @@ static inline void
 prepare_task_switch(struct rq *rq, struct task_struct *prev,
                    struct task_struct *next)
 {
+       kcov_prepare_switch(prev);
        sched_info_switch(rq, prev, next);
        perf_event_task_sched_out(prev, next);
        rseq_preempt(prev);
@@ -2702,6 +2705,7 @@ static struct rq *finish_task_switch(struct task_struct *prev)
        finish_task(prev);
        finish_lock_switch(rq);
        finish_arch_post_lock_switch();
+       kcov_finish_switch(current);
 
        fire_sched_in_preempt_notifiers(current);
        /*
index dd6c0a2ad969fe3e3ff387833629bf6f611a1c50..dcc0166d1997a20e5d8c56c3facaca5315d8d1e4 100644 (file)
@@ -12,22 +12,22 @@ config NOP_TRACER
 config HAVE_FTRACE_NMI_ENTER
        bool
        help
-         See Documentation/trace/ftrace-design.txt
+         See Documentation/trace/ftrace-design.rst
 
 config HAVE_FUNCTION_TRACER
        bool
        help
-         See Documentation/trace/ftrace-design.txt
+         See Documentation/trace/ftrace-design.rst
 
 config HAVE_FUNCTION_GRAPH_TRACER
        bool
        help
-         See Documentation/trace/ftrace-design.txt
+         See Documentation/trace/ftrace-design.rst
 
 config HAVE_DYNAMIC_FTRACE
        bool
        help
-         See Documentation/trace/ftrace-design.txt
+         See Documentation/trace/ftrace-design.rst
 
 config HAVE_DYNAMIC_FTRACE_WITH_REGS
        bool
@@ -35,12 +35,12 @@ config HAVE_DYNAMIC_FTRACE_WITH_REGS
 config HAVE_FTRACE_MCOUNT_RECORD
        bool
        help
-         See Documentation/trace/ftrace-design.txt
+         See Documentation/trace/ftrace-design.rst
 
 config HAVE_SYSCALL_TRACEPOINTS
        bool
        help
-         See Documentation/trace/ftrace-design.txt
+         See Documentation/trace/ftrace-design.rst
 
 config HAVE_FENTRY
        bool
@@ -448,7 +448,7 @@ config KPROBE_EVENTS
        help
          This allows the user to add tracing events (similar to tracepoints)
          on the fly via the ftrace interface. See
-         Documentation/trace/kprobetrace.txt for more details.
+         Documentation/trace/kprobetrace.rst for more details.
 
          Those events can be inserted wherever kprobes can probe, and record
          various register and memory values.
@@ -575,7 +575,7 @@ config MMIOTRACE
          implementation and works via page faults. Tracing is disabled by
          default and can be enabled at run-time.
 
-         See Documentation/trace/mmiotrace.txt.
+         See Documentation/trace/mmiotrace.rst.
          If you are not helping to develop drivers, say N.
 
 config TRACING_MAP
index 803fcbced7293297ea52f2a91ddc9c91d8a99eda..706836ec314d2add83b84ebe59dec8fd7e13a7ad 100644 (file)
@@ -405,7 +405,7 @@ config ASSOCIATIVE_ARRAY
 
          See:
 
-               Documentation/assoc_array.txt
+               Documentation/core-api/assoc_array.rst
 
          for more information.
 
index d543c65ce0eb2a5181f2796ae119807e0c0f7e2d..8838d1158d192bfafe61fc234480ad9c9a05971f 100644 (file)
@@ -1506,6 +1506,10 @@ config NETDEV_NOTIFIER_ERROR_INJECT
 
          If unsure, say N.
 
+config FUNCTION_ERROR_INJECTION
+       def_bool y
+       depends on HAVE_FUNCTION_ERROR_INJECTION && KPROBES
+
 config FAULT_INJECTION
        bool "Fault-injection framework"
        depends on DEBUG_KERNEL
@@ -1513,10 +1517,6 @@ config FAULT_INJECTION
          Provide fault-injection framework.
          For more details, see Documentation/fault-injection/.
 
-config FUNCTION_ERROR_INJECTION
-       def_bool y
-       depends on HAVE_FUNCTION_ERROR_INJECTION && KPROBES
-
 config FAILSLAB
        bool "Fault-injection capability for kmalloc"
        depends on FAULT_INJECTION
@@ -1547,16 +1547,6 @@ config FAIL_IO_TIMEOUT
          Only works with drivers that use the generic timeout handling,
          for others it wont do anything.
 
-config FAIL_MMC_REQUEST
-       bool "Fault-injection capability for MMC IO"
-       depends on FAULT_INJECTION_DEBUG_FS && MMC
-       help
-         Provide fault-injection capability for MMC IO.
-         This will make the mmc core return data errors. This is
-         useful to test the error handling in the mmc block device
-         and to test how the mmc host driver handles retries from
-         the block device.
-
 config FAIL_FUTEX
        bool "Fault-injection capability for futexes"
        select DEBUG_FS
@@ -1564,6 +1554,12 @@ config FAIL_FUTEX
        help
          Provide fault-injection capability for futexes.
 
+config FAULT_INJECTION_DEBUG_FS
+       bool "Debugfs entries for fault-injection capabilities"
+       depends on FAULT_INJECTION && SYSFS && DEBUG_FS
+       help
+         Enable configuration of fault-injection capabilities via debugfs.
+
 config FAIL_FUNCTION
        bool "Fault-injection capability for functions"
        depends on FAULT_INJECTION_DEBUG_FS && FUNCTION_ERROR_INJECTION
@@ -1574,11 +1570,15 @@ config FAIL_FUNCTION
          an error value and have to handle it. This is useful to test the
          error handling in various subsystems.
 
-config FAULT_INJECTION_DEBUG_FS
-       bool "Debugfs entries for fault-injection capabilities"
-       depends on FAULT_INJECTION && SYSFS && DEBUG_FS
+config FAIL_MMC_REQUEST
+       bool "Fault-injection capability for MMC IO"
+       depends on FAULT_INJECTION_DEBUG_FS && MMC
        help
-         Enable configuration of fault-injection capabilities via debugfs.
+         Provide fault-injection capability for MMC IO.
+         This will make the mmc core return data errors. This is
+         useful to test the error handling in the mmc block device
+         and to test how the mmc host driver handles retries from
+         the block device.
 
 config FAULT_INJECTION_STACKTRACE_FILTER
        bool "stacktrace filter for fault-injection capabilities"
index cea592f402ed029d6d5dd63addd2d2bc8a8391f1..b2aa8f5148449de1557e3ee48feebb8f1cab3083 100644 (file)
@@ -260,6 +260,13 @@ plain(void)
 {
        int err;
 
+       /*
+        * Make sure crng is ready. Otherwise we get "(ptrval)" instead
+        * of a hashed address when printing '%p' in plain_hash() and
+        * plain_format().
+        */
+       wait_for_random_bytes();
+
        err = plain_hash();
        if (err) {
                pr_warn("plain 'p' does not appear to be hashed\n");
index 126548b5a292bce68708be3b725dfa04465e5078..2bf12da9baa0666e6c772ede6ff63f4900106fe4 100644 (file)
@@ -307,12 +307,10 @@ static int __init init_cleancache(void)
        struct dentry *root = debugfs_create_dir("cleancache", NULL);
        if (root == NULL)
                return -ENXIO;
-       debugfs_create_u64("succ_gets", S_IRUGO, root, &cleancache_succ_gets);
-       debugfs_create_u64("failed_gets", S_IRUGO,
-                               root, &cleancache_failed_gets);
-       debugfs_create_u64("puts", S_IRUGO, root, &cleancache_puts);
-       debugfs_create_u64("invalidates", S_IRUGO,
-                               root, &cleancache_invalidates);
+       debugfs_create_u64("succ_gets", 0444, root, &cleancache_succ_gets);
+       debugfs_create_u64("failed_gets", 0444, root, &cleancache_failed_gets);
+       debugfs_create_u64("puts", 0444, root, &cleancache_puts);
+       debugfs_create_u64("invalidates", 0444, root, &cleancache_invalidates);
 #endif
        return 0;
 }
index 275df8b5b22e7bdb722e95774a1948d6c69fa4f8..f23467291cfb0bcb06ad736ee7dd34b5705ac989 100644 (file)
@@ -172,23 +172,18 @@ static void cma_debugfs_add_one(struct cma *cma, int idx)
 
        tmp = debugfs_create_dir(name, cma_debugfs_root);
 
-       debugfs_create_file("alloc", S_IWUSR, tmp, cma,
-                               &cma_alloc_fops);
-
-       debugfs_create_file("free", S_IWUSR, tmp, cma,
-                               &cma_free_fops);
-
-       debugfs_create_file("base_pfn", S_IRUGO, tmp,
-                               &cma->base_pfn, &cma_debugfs_fops);
-       debugfs_create_file("count", S_IRUGO, tmp,
-                               &cma->count, &cma_debugfs_fops);
-       debugfs_create_file("order_per_bit", S_IRUGO, tmp,
-                               &cma->order_per_bit, &cma_debugfs_fops);
-       debugfs_create_file("used", S_IRUGO, tmp, cma, &cma_used_fops);
-       debugfs_create_file("maxchunk", S_IRUGO, tmp, cma, &cma_maxchunk_fops);
+       debugfs_create_file("alloc", 0200, tmp, cma, &cma_alloc_fops);
+       debugfs_create_file("free", 0200, tmp, cma, &cma_free_fops);
+       debugfs_create_file("base_pfn", 0444, tmp,
+                           &cma->base_pfn, &cma_debugfs_fops);
+       debugfs_create_file("count", 0444, tmp, &cma->count, &cma_debugfs_fops);
+       debugfs_create_file("order_per_bit", 0444, tmp,
+                           &cma->order_per_bit, &cma_debugfs_fops);
+       debugfs_create_file("used", 0444, tmp, cma, &cma_used_fops);
+       debugfs_create_file("maxchunk", 0444, tmp, cma, &cma_maxchunk_fops);
 
        u32s = DIV_ROUND_UP(cma_bitmap_maxno(cma), BITS_PER_BYTE * sizeof(u32));
-       debugfs_create_u32_array("bitmap", S_IRUGO, tmp, (u32*)cma->bitmap, u32s);
+       debugfs_create_u32_array("bitmap", 0444, tmp, (u32 *)cma->bitmap, u32s);
 }
 
 static int __init cma_debugfs_init(void)
index 29bd1df18b98aff1d4a2a59c9253d5734c32bb20..faca45ebe62dfbb58099661158334ab9ce0155f8 100644 (file)
@@ -1899,7 +1899,7 @@ static ssize_t sysfs_compact_node(struct device *dev,
 
        return count;
 }
-static DEVICE_ATTR(compact, S_IWUSR, NULL, sysfs_compact_node);
+static DEVICE_ATTR(compact, 0200, NULL, sysfs_compact_node);
 
 int compaction_register_node(struct node *node)
 {
index 4d90a64b2fdc8d50af4ef60278901a5b089b5735..6d4b97e7e9e97752413caef09df772ece3d6f45c 100644 (file)
@@ -105,7 +105,7 @@ show_pools(struct device *dev, struct device_attribute *attr, char *buf)
        return PAGE_SIZE - size;
 }
 
-static DEVICE_ATTR(pools, S_IRUGO, show_pools, NULL);
+static DEVICE_ATTR(pools, 0444, show_pools, NULL);
 
 /**
  * dma_pool_create - Creates a pool of consistent memory blocks, for dma.
index 1f2f248e36019121bad626a9a81403b5b5316b1d..b135ebb88b6f729e145430999591beb3db2371d2 100644 (file)
@@ -42,7 +42,7 @@ __setup("failslab=", setup_failslab);
 static int __init failslab_debugfs_init(void)
 {
        struct dentry *dir;
-       umode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
+       umode_t mode = S_IFREG | 0600;
 
        dir = fault_create_debugfs_attr("failslab", NULL, &failslab.attr);
        if (IS_ERR(dir))
index 4f5476a0f95535a1c687b898b96373b7fc1c040e..157e5bf63504258e3d1be341854627d47d4b96d0 100644 (file)
@@ -486,12 +486,11 @@ static int __init init_frontswap(void)
        struct dentry *root = debugfs_create_dir("frontswap", NULL);
        if (root == NULL)
                return -ENXIO;
-       debugfs_create_u64("loads", S_IRUGO, root, &frontswap_loads);
-       debugfs_create_u64("succ_stores", S_IRUGO, root, &frontswap_succ_stores);
-       debugfs_create_u64("failed_stores", S_IRUGO, root,
-                               &frontswap_failed_stores);
-       debugfs_create_u64("invalidates", S_IRUGO,
-                               root, &frontswap_invalidates);
+       debugfs_create_u64("loads", 0444, root, &frontswap_loads);
+       debugfs_create_u64("succ_stores", 0444, root, &frontswap_succ_stores);
+       debugfs_create_u64("failed_stores", 0444, root,
+                          &frontswap_failed_stores);
+       debugfs_create_u64("invalidates", 0444, root, &frontswap_invalidates);
 #endif
        return 0;
 }
index e2d2886fb1df33d973e69ab49790c2d0dba4ee51..a6d43cf9a98240d31b18198fc6ef2e55e5a8713c 100644 (file)
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -216,6 +216,8 @@ struct rmap_item {
 #define SEQNR_MASK     0x0ff   /* low bits of unstable tree seqnr */
 #define UNSTABLE_FLAG  0x100   /* is a node of the unstable tree */
 #define STABLE_FLAG    0x200   /* is listed from the stable tree */
+#define KSM_FLAG_MASK  (SEQNR_MASK|UNSTABLE_FLAG|STABLE_FLAG)
+                               /* to mask all the flags */
 
 /* The stable and unstable tree heads */
 static struct rb_root one_stable_tree[1] = { RB_ROOT };
@@ -2598,10 +2600,15 @@ again:
                anon_vma_lock_read(anon_vma);
                anon_vma_interval_tree_foreach(vmac, &anon_vma->rb_root,
                                               0, ULONG_MAX) {
+                       unsigned long addr;
+
                        cond_resched();
                        vma = vmac->vma;
-                       if (rmap_item->address < vma->vm_start ||
-                           rmap_item->address >= vma->vm_end)
+
+                       /* Ignore the stable/unstable/sqnr flags */
+                       addr = rmap_item->address & ~KSM_FLAG_MASK;
+
+                       if (addr < vma->vm_start || addr >= vma->vm_end)
                                continue;
                        /*
                         * Initially we examine only the vma which covers this
@@ -2615,8 +2622,7 @@ again:
                        if (rwc->invalid_vma && rwc->invalid_vma(vma, rwc->arg))
                                continue;
 
-                       if (!rwc->rmap_one(page, vma,
-                                       rmap_item->address, rwc->arg)) {
+                       if (!rwc->rmap_one(page, vma, addr, rwc->arg)) {
                                anon_vma_unlock_read(anon_vma);
                                return;
                        }
index 93ad42bc8a73c0e6cb1f1e42847d44963c2510ec..03d48d8835babeb507f78057c3f3068339dad77a 100644 (file)
@@ -1808,10 +1808,13 @@ static int __init memblock_init_debugfs(void)
        struct dentry *root = debugfs_create_dir("memblock", NULL);
        if (!root)
                return -ENXIO;
-       debugfs_create_file("memory", S_IRUGO, root, &memblock.memory, &memblock_debug_fops);
-       debugfs_create_file("reserved", S_IRUGO, root, &memblock.reserved, &memblock_debug_fops);
+       debugfs_create_file("memory", 0444, root,
+                           &memblock.memory, &memblock_debug_fops);
+       debugfs_create_file("reserved", 0444, root,
+                           &memblock.reserved, &memblock_debug_fops);
 #ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP
-       debugfs_create_file("physmem", S_IRUGO, root, &memblock.physmem, &memblock_debug_fops);
+       debugfs_create_file("physmem", 0444, root,
+                           &memblock.physmem, &memblock_debug_fops);
 #endif
 
        return 0;
index c1e64d60ed0285c3163235c7a5287c7d2f1edd2e..e6f0d5ef320aa65d2b65ceed4b202021a84fd49b 100644 (file)
@@ -3550,7 +3550,8 @@ static int mem_cgroup_oom_control_read(struct seq_file *sf, void *v)
 
        seq_printf(sf, "oom_kill_disable %d\n", memcg->oom_kill_disable);
        seq_printf(sf, "under_oom %d\n", (bool)memcg->under_oom);
-       seq_printf(sf, "oom_kill %lu\n", memcg_sum_events(memcg, OOM_KILL));
+       seq_printf(sf, "oom_kill %lu\n",
+                  atomic_long_read(&memcg->memory_events[MEMCG_OOM_KILL]));
        return 0;
 }
 
@@ -5239,7 +5240,8 @@ static int memory_events_show(struct seq_file *m, void *v)
                   atomic_long_read(&memcg->memory_events[MEMCG_MAX]));
        seq_printf(m, "oom %lu\n",
                   atomic_long_read(&memcg->memory_events[MEMCG_OOM]));
-       seq_printf(m, "oom_kill %lu\n", memcg_sum_events(memcg, OOM_KILL));
+       seq_printf(m, "oom_kill %lu\n",
+                  atomic_long_read(&memcg->memory_events[MEMCG_OOM_KILL]));
 
        return 0;
 }
@@ -5480,6 +5482,10 @@ enum mem_cgroup_protection mem_cgroup_protected(struct mem_cgroup *root,
        elow = memcg->memory.low;
 
        parent = parent_mem_cgroup(memcg);
+       /* No parent means a non-hierarchical mode on v1 memcg */
+       if (!parent)
+               return MEMCG_PROT_NONE;
+
        if (parent == root)
                goto exit;
 
index 049470aa1e3eefc88407e9a35f1ca252fd01912d..5c2e18505f75ba67da4b2c2df6a42b1785543b7a 100644 (file)
@@ -191,8 +191,6 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd,
                drop_rmap_locks(vma);
 }
 
-#define LATENCY_LIMIT  (64 * PAGE_SIZE)
-
 unsigned long move_page_tables(struct vm_area_struct *vma,
                unsigned long old_addr, struct vm_area_struct *new_vma,
                unsigned long new_addr, unsigned long len,
@@ -247,8 +245,6 @@ unsigned long move_page_tables(struct vm_area_struct *vma,
                next = (new_addr + PMD_SIZE) & PMD_MASK;
                if (extent > next - new_addr)
                        extent = next - new_addr;
-               if (extent > LATENCY_LIMIT)
-                       extent = LATENCY_LIMIT;
                move_ptes(vma, old_pmd, old_addr, old_addr + extent, new_vma,
                          new_pmd, new_addr, need_rmap_locks, &need_flush);
        }
index 6694348b27e98db274c1f99415061c71c1c1d7db..84081e77bc51cec7a9089937429046b7107aa027 100644 (file)
@@ -913,7 +913,7 @@ static void oom_kill_process(struct oom_control *oc, const char *message)
 
        /* Raise event before sending signal: task reaper must see this */
        count_vm_event(OOM_KILL);
-       count_memcg_event_mm(mm, OOM_KILL);
+       memcg_memory_event_mm(mm, MEMCG_OOM_KILL);
 
        /*
         * We should send SIGKILL before granting access to memory reserves
index 07b3c23762adbbc441ba7fb9e1f39c2c694d85c1..1521100f1e63b729bba37e21723a312950d688d8 100644 (file)
@@ -3061,7 +3061,7 @@ static bool should_fail_alloc_page(gfp_t gfp_mask, unsigned int order)
 
 static int __init fail_page_alloc_debugfs(void)
 {
-       umode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
+       umode_t mode = S_IFREG | 0600;
        struct dentry *dir;
 
        dir = fault_create_debugfs_attr("fail_page_alloc", NULL,
index e412a63b2b74f7820298751e1cf382fe90c48005..6302bc62c27d6b69939ab2791c57a5da8945e8aa 100644 (file)
@@ -201,7 +201,7 @@ static ssize_t page_idle_bitmap_write(struct file *file, struct kobject *kobj,
 }
 
 static struct bin_attribute page_idle_bitmap_attr =
-               __BIN_ATTR(bitmap, S_IRUSR | S_IWUSR,
+               __BIN_ATTR(bitmap, 0600,
                           page_idle_bitmap_read, page_idle_bitmap_write, 0);
 
 static struct bin_attribute *page_idle_bin_attrs[] = {
index 75d21a2259b3b1ff9d2ac624fc9fbab10100580d..d80adfe702d3b85f754589135f3695b4e3394c72 100644 (file)
@@ -631,8 +631,8 @@ static int __init pageowner_init(void)
                return 0;
        }
 
-       dentry = debugfs_create_file("page_owner", S_IRUSR, NULL,
-                       NULL, &proc_page_owner_operations);
+       dentry = debugfs_create_file("page_owner", 0400, NULL,
+                                    NULL, &proc_page_owner_operations);
 
        return PTR_ERR_OR_ZERO(dentry);
 }
index e9a7ac74823de13b912c2896f3254e762d17a172..2cab8440305531f8ab97f3a56c95b91516bcd2ea 100644 (file)
@@ -3013,7 +3013,8 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
        if (len > PAGE_SIZE)
                return -ENAMETOOLONG;
 
-       inode = shmem_get_inode(dir->i_sb, dir, S_IFLNK|S_IRWXUGO, 0, VM_NORESERVE);
+       inode = shmem_get_inode(dir->i_sb, dir, S_IFLNK | 0777, 0,
+                               VM_NORESERVE);
        if (!inode)
                return -ENOSPC;
 
@@ -3445,7 +3446,7 @@ static int shmem_show_options(struct seq_file *seq, struct dentry *root)
                        sbinfo->max_blocks << (PAGE_SHIFT - 10));
        if (sbinfo->max_inodes != shmem_default_max_inodes())
                seq_printf(seq, ",nr_inodes=%lu", sbinfo->max_inodes);
-       if (sbinfo->mode != (S_IRWXUGO | S_ISVTX))
+       if (sbinfo->mode != (0777 | S_ISVTX))
                seq_printf(seq, ",mode=%03ho", sbinfo->mode);
        if (!uid_eq(sbinfo->uid, GLOBAL_ROOT_UID))
                seq_printf(seq, ",uid=%u",
@@ -3486,7 +3487,7 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent)
        if (!sbinfo)
                return -ENOMEM;
 
-       sbinfo->mode = S_IRWXUGO | S_ISVTX;
+       sbinfo->mode = 0777 | S_ISVTX;
        sbinfo->uid = current_fsuid();
        sbinfo->gid = current_fsgid();
        sb->s_fs_info = sbinfo;
@@ -3929,7 +3930,7 @@ static struct file *__shmem_file_setup(struct vfsmount *mnt, const char *name, l
        d_set_d_op(path.dentry, &anon_ops);
 
        res = ERR_PTR(-ENOSPC);
-       inode = shmem_get_inode(sb, NULL, S_IFREG | S_IRWXUGO, 0, flags);
+       inode = shmem_get_inode(sb, NULL, S_IFREG | 0777, 0, flags);
        if (!inode)
                goto put_memory;
 
index 98dcdc3520623bf776164982224b7b258e9a2291..890b1f04a03a3d46f80fe1b2cfccae1f14b79836 100644 (file)
@@ -136,6 +136,7 @@ void slab_init_memcg_params(struct kmem_cache *s)
        s->memcg_params.root_cache = NULL;
        RCU_INIT_POINTER(s->memcg_params.memcg_caches, NULL);
        INIT_LIST_HEAD(&s->memcg_params.children);
+       s->memcg_params.dying = false;
 }
 
 static int init_memcg_params(struct kmem_cache *s,
@@ -608,7 +609,7 @@ void memcg_create_kmem_cache(struct mem_cgroup *memcg,
         * The memory cgroup could have been offlined while the cache
         * creation work was pending.
         */
-       if (memcg->kmem_state != KMEM_ONLINE)
+       if (memcg->kmem_state != KMEM_ONLINE || root_cache->memcg_params.dying)
                goto out_unlock;
 
        idx = memcg_cache_id(memcg);
@@ -712,6 +713,9 @@ void slab_deactivate_memcg_cache_rcu_sched(struct kmem_cache *s,
            WARN_ON_ONCE(s->memcg_params.deact_fn))
                return;
 
+       if (s->memcg_params.root_cache->memcg_params.dying)
+               return;
+
        /* pin memcg so that @s doesn't get destroyed in the middle */
        css_get(&s->memcg_params.memcg->css);
 
@@ -823,11 +827,36 @@ static int shutdown_memcg_caches(struct kmem_cache *s)
                return -EBUSY;
        return 0;
 }
+
+static void flush_memcg_workqueue(struct kmem_cache *s)
+{
+       mutex_lock(&slab_mutex);
+       s->memcg_params.dying = true;
+       mutex_unlock(&slab_mutex);
+
+       /*
+        * SLUB deactivates the kmem_caches through call_rcu_sched. Make
+        * sure all registered rcu callbacks have been invoked.
+        */
+       if (IS_ENABLED(CONFIG_SLUB))
+               rcu_barrier_sched();
+
+       /*
+        * SLAB and SLUB create memcg kmem_caches through workqueue and SLUB
+        * deactivates the memcg kmem_caches through workqueue. Make sure all
+        * previous workitems on workqueue are processed.
+        */
+       flush_workqueue(memcg_kmem_cache_wq);
+}
 #else
 static inline int shutdown_memcg_caches(struct kmem_cache *s)
 {
        return 0;
 }
+
+static inline void flush_memcg_workqueue(struct kmem_cache *s)
+{
+}
 #endif /* CONFIG_MEMCG && !CONFIG_SLOB */
 
 void slab_kmem_cache_release(struct kmem_cache *s)
@@ -845,6 +874,8 @@ void kmem_cache_destroy(struct kmem_cache *s)
        if (unlikely(!s))
                return;
 
+       flush_memcg_workqueue(s);
+
        get_online_cpus();
        get_online_mems();
 
@@ -1212,9 +1243,9 @@ void cache_random_seq_destroy(struct kmem_cache *cachep)
 
 #if defined(CONFIG_SLAB) || defined(CONFIG_SLUB_DEBUG)
 #ifdef CONFIG_SLAB
-#define SLABINFO_RIGHTS (S_IWUSR | S_IRUSR)
+#define SLABINFO_RIGHTS (0600)
 #else
-#define SLABINFO_RIGHTS S_IRUSR
+#define SLABINFO_RIGHTS (0400)
 #endif
 
 static void print_slabinfo_header(struct seq_file *m)
index 925cf795a652e59831c49600d425d2deb0494021..2cc2972eedaf1088e8a1ea0017f701b18c729494 100644 (file)
@@ -100,7 +100,7 @@ atomic_t nr_rotate_swap = ATOMIC_INIT(0);
 
 static inline unsigned char swap_count(unsigned char ent)
 {
-       return ent & ~SWAP_HAS_CACHE;   /* may include SWAP_HAS_CONT flag */
+       return ent & ~SWAP_HAS_CACHE;   /* may include COUNT_CONTINUED flag */
 }
 
 /* returns 1 if swap entry is freed */
index 89efac3a020e5bb47cc0fcbfb83c0fb114c0498f..cfea25be77548cfad6ffc5d4c4d3f60445804f52 100644 (file)
@@ -2741,11 +2741,11 @@ static const struct seq_operations vmalloc_op = {
 static int __init proc_vmalloc_init(void)
 {
        if (IS_ENABLED(CONFIG_NUMA))
-               proc_create_seq_private("vmallocinfo", S_IRUSR, NULL,
+               proc_create_seq_private("vmallocinfo", 0400, NULL,
                                &vmalloc_op,
                                nr_node_ids * sizeof(unsigned int), NULL);
        else
-               proc_create_seq("vmallocinfo", S_IRUSR, NULL, &vmalloc_op);
+               proc_create_seq("vmallocinfo", 0400, NULL, &vmalloc_op);
        return 0;
 }
 module_init(proc_vmalloc_init);
index 61cb05dc950caf394dbf375b5b7084a193cbaddb..8d87e973a4f509955e3c0974ed3a2e808cbd0688 100644 (file)
@@ -661,8 +661,9 @@ static void zs_pool_stat_create(struct zs_pool *pool, const char *name)
        }
        pool->stat_dentry = entry;
 
-       entry = debugfs_create_file("classes", S_IFREG | S_IRUGO,
-                       pool->stat_dentry, pool, &zs_stats_size_fops);
+       entry = debugfs_create_file("classes", S_IFREG | 0444,
+                                   pool->stat_dentry, pool,
+                                   &zs_stats_size_fops);
        if (!entry) {
                pr_warn("%s: debugfs file entry <%s> creation failed\n",
                                name, "classes");
index 61a5c41972dba22bc35179a13d40e900dea679b6..7d34e69507e305adec0a64b5e272626385f9d651 100644 (file)
@@ -1256,26 +1256,26 @@ static int __init zswap_debugfs_init(void)
        if (!zswap_debugfs_root)
                return -ENOMEM;
 
-       debugfs_create_u64("pool_limit_hit", S_IRUGO,
-                       zswap_debugfs_root, &zswap_pool_limit_hit);
-       debugfs_create_u64("reject_reclaim_fail", S_IRUGO,
-                       zswap_debugfs_root, &zswap_reject_reclaim_fail);
-       debugfs_create_u64("reject_alloc_fail", S_IRUGO,
-                       zswap_debugfs_root, &zswap_reject_alloc_fail);
-       debugfs_create_u64("reject_kmemcache_fail", S_IRUGO,
-                       zswap_debugfs_root, &zswap_reject_kmemcache_fail);
-       debugfs_create_u64("reject_compress_poor", S_IRUGO,
-                       zswap_debugfs_root, &zswap_reject_compress_poor);
-       debugfs_create_u64("written_back_pages", S_IRUGO,
-                       zswap_debugfs_root, &zswap_written_back_pages);
-       debugfs_create_u64("duplicate_entry", S_IRUGO,
-                       zswap_debugfs_root, &zswap_duplicate_entry);
-       debugfs_create_u64("pool_total_size", S_IRUGO,
-                       zswap_debugfs_root, &zswap_pool_total_size);
-       debugfs_create_atomic_t("stored_pages", S_IRUGO,
-                       zswap_debugfs_root, &zswap_stored_pages);
+       debugfs_create_u64("pool_limit_hit", 0444,
+                          zswap_debugfs_root, &zswap_pool_limit_hit);
+       debugfs_create_u64("reject_reclaim_fail", 0444,
+                          zswap_debugfs_root, &zswap_reject_reclaim_fail);
+       debugfs_create_u64("reject_alloc_fail", 0444,
+                          zswap_debugfs_root, &zswap_reject_alloc_fail);
+       debugfs_create_u64("reject_kmemcache_fail", 0444,
+                          zswap_debugfs_root, &zswap_reject_kmemcache_fail);
+       debugfs_create_u64("reject_compress_poor", 0444,
+                          zswap_debugfs_root, &zswap_reject_compress_poor);
+       debugfs_create_u64("written_back_pages", 0444,
+                          zswap_debugfs_root, &zswap_written_back_pages);
+       debugfs_create_u64("duplicate_entry", 0444,
+                          zswap_debugfs_root, &zswap_duplicate_entry);
+       debugfs_create_u64("pool_total_size", 0444,
+                          zswap_debugfs_root, &zswap_pool_total_size);
+       debugfs_create_atomic_t("stored_pages", 0444,
+                               zswap_debugfs_root, &zswap_stored_pages);
        debugfs_create_atomic_t("same_filled_pages", 0444,
-                       zswap_debugfs_root, &zswap_same_filled_pages);
+                               zswap_debugfs_root, &zswap_same_filled_pages);
 
        return 0;
 }
index 684b66bfa19919784672a85f6484e9da3b11253b..491828713e0bd738763beae0c48aff44dcc5c76f 100644 (file)
@@ -411,6 +411,12 @@ ebt_check_watcher(struct ebt_entry_watcher *w, struct xt_tgchk_param *par,
        watcher = xt_request_find_target(NFPROTO_BRIDGE, w->u.name, 0);
        if (IS_ERR(watcher))
                return PTR_ERR(watcher);
+
+       if (watcher->family != NFPROTO_BRIDGE) {
+               module_put(watcher->me);
+               return -ENOENT;
+       }
+
        w->u.watcher = watcher;
 
        par->target   = watcher;
@@ -709,6 +715,8 @@ ebt_check_entry(struct ebt_entry *e, struct net *net,
        }
        i = 0;
 
+       memset(&mtpar, 0, sizeof(mtpar));
+       memset(&tgpar, 0, sizeof(tgpar));
        mtpar.net       = tgpar.net       = net;
        mtpar.table     = tgpar.table     = name;
        mtpar.entryinfo = tgpar.entryinfo = e;
@@ -730,6 +738,13 @@ ebt_check_entry(struct ebt_entry *e, struct net *net,
                goto cleanup_watchers;
        }
 
+       /* Reject UNSPEC, xtables verdicts/return values are incompatible */
+       if (target->family != NFPROTO_BRIDGE) {
+               module_put(target->me);
+               ret = -ENOENT;
+               goto cleanup_watchers;
+       }
+
        t->u.target = target;
        if (t->u.target == &ebt_standard_target) {
                if (gap < sizeof(struct ebt_standard_target)) {
@@ -1606,16 +1621,16 @@ struct compat_ebt_entry_mwt {
                compat_uptr_t ptr;
        } u;
        compat_uint_t match_size;
-       compat_uint_t data[0];
+       compat_uint_t data[0] __attribute__ ((aligned (__alignof__(struct compat_ebt_replace))));
 };
 
 /* account for possible padding between match_size and ->data */
 static int ebt_compat_entry_padsize(void)
 {
-       BUILD_BUG_ON(XT_ALIGN(sizeof(struct ebt_entry_match)) <
-                       COMPAT_XT_ALIGN(sizeof(struct compat_ebt_entry_mwt)));
-       return (int) XT_ALIGN(sizeof(struct ebt_entry_match)) -
-                       COMPAT_XT_ALIGN(sizeof(struct compat_ebt_entry_mwt));
+       BUILD_BUG_ON(sizeof(struct ebt_entry_match) <
+                       sizeof(struct compat_ebt_entry_mwt));
+       return (int) sizeof(struct ebt_entry_match) -
+                       sizeof(struct compat_ebt_entry_mwt);
 }
 
 static int ebt_compat_match_offset(const struct xt_match *match,
index eaf05de37f75ca204ded7efdba35c5257e8717d1..6de981270566966eca1c0e0eaf6ed7400fa3e9d3 100644 (file)
@@ -261,7 +261,7 @@ static void nft_reject_br_send_v6_unreach(struct net *net,
        if (!reject6_br_csum_ok(oldskb, hook))
                return;
 
-       nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct icmp6hdr) +
+       nskb = alloc_skb(sizeof(struct ipv6hdr) + sizeof(struct icmp6hdr) +
                         LL_MAX_HEADER + len, GFP_ATOMIC);
        if (!nskb)
                return;
index 3b3d33ea9ed830373c08889f3e38d7bc695f313b..c6413c3607712de1d20e2b6010433434395020be 100644 (file)
@@ -168,12 +168,6 @@ static char tag_keepalive2 = CEPH_MSGR_TAG_KEEPALIVE2;
 static struct lock_class_key socket_class;
 #endif
 
-/*
- * When skipping (ignoring) a block of input we read it into a "skip
- * buffer," which is this many bytes in size.
- */
-#define SKIP_BUF_SIZE  1024
-
 static void queue_con(struct ceph_connection *con);
 static void cancel_con(struct ceph_connection *con);
 static void ceph_con_workfn(struct work_struct *);
@@ -520,12 +514,18 @@ static int ceph_tcp_connect(struct ceph_connection *con)
        return 0;
 }
 
+/*
+ * If @buf is NULL, discard up to @len bytes.
+ */
 static int ceph_tcp_recvmsg(struct socket *sock, void *buf, size_t len)
 {
        struct kvec iov = {buf, len};
        struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL };
        int r;
 
+       if (!buf)
+               msg.msg_flags |= MSG_TRUNC;
+
        iov_iter_kvec(&msg.msg_iter, READ | ITER_KVEC, &iov, 1, len);
        r = sock_recvmsg(sock, &msg, msg.msg_flags);
        if (r == -EAGAIN)
@@ -2575,9 +2575,6 @@ static int try_write(struct ceph_connection *con)
            con->state != CON_STATE_OPEN)
                return 0;
 
-more:
-       dout("try_write out_kvec_bytes %d\n", con->out_kvec_bytes);
-
        /* open the socket first? */
        if (con->state == CON_STATE_PREOPEN) {
                BUG_ON(con->sock);
@@ -2598,7 +2595,8 @@ more:
                }
        }
 
-more_kvec:
+more:
+       dout("try_write out_kvec_bytes %d\n", con->out_kvec_bytes);
        BUG_ON(!con->sock);
 
        /* kvec data queued? */
@@ -2623,7 +2621,7 @@ more_kvec:
 
                ret = write_partial_message_data(con);
                if (ret == 1)
-                       goto more_kvec;  /* we need to send the footer, too! */
+                       goto more;  /* we need to send the footer, too! */
                if (ret == 0)
                        goto out;
                if (ret < 0) {
@@ -2659,8 +2657,6 @@ out:
        return ret;
 }
 
-
-
 /*
  * Read what we can from the socket.
  */
@@ -2721,16 +2717,11 @@ more:
        if (con->in_base_pos < 0) {
                /*
                 * skipping + discarding content.
-                *
-                * FIXME: there must be a better way to do this!
                 */
-               static char buf[SKIP_BUF_SIZE];
-               int skip = min((int) sizeof (buf), -con->in_base_pos);
-
-               dout("skipping %d / %d bytes\n", skip, -con->in_base_pos);
-               ret = ceph_tcp_recvmsg(con->sock, buf, skip);
+               ret = ceph_tcp_recvmsg(con->sock, NULL, -con->in_base_pos);
                if (ret <= 0)
                        goto out;
+               dout("skipped %d / %d bytes\n", ret, -con->in_base_pos);
                con->in_base_pos += ret;
                if (con->in_base_pos)
                        goto more;
index 69a2581ddbba2ca2894a30bfe2204985244ad213..a00c74f1154e3a16902c3c788de921c601efe12b 100644 (file)
@@ -766,7 +766,7 @@ void osd_req_op_extent_dup_last(struct ceph_osd_request *osd_req,
 }
 EXPORT_SYMBOL(osd_req_op_extent_dup_last);
 
-void osd_req_op_cls_init(struct ceph_osd_request *osd_req, unsigned int which,
+int osd_req_op_cls_init(struct ceph_osd_request *osd_req, unsigned int which,
                        u16 opcode, const char *class, const char *method)
 {
        struct ceph_osd_req_op *op = _osd_req_op_init(osd_req, which,
@@ -778,7 +778,9 @@ void osd_req_op_cls_init(struct ceph_osd_request *osd_req, unsigned int which,
        BUG_ON(opcode != CEPH_OSD_OP_CALL);
 
        pagelist = kmalloc(sizeof (*pagelist), GFP_NOFS);
-       BUG_ON(!pagelist);
+       if (!pagelist)
+               return -ENOMEM;
+
        ceph_pagelist_init(pagelist);
 
        op->cls.class_name = class;
@@ -798,6 +800,7 @@ void osd_req_op_cls_init(struct ceph_osd_request *osd_req, unsigned int which,
        osd_req_op_cls_request_info_pagelist(osd_req, which, pagelist);
 
        op->indata_len = payload_len;
+       return 0;
 }
 EXPORT_SYMBOL(osd_req_op_cls_init);
 
@@ -1026,7 +1029,6 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc,
                                       truncate_size, truncate_seq);
        }
 
-       req->r_abort_on_full = true;
        req->r_flags = flags;
        req->r_base_oloc.pool = layout->pool_id;
        req->r_base_oloc.pool_ns = ceph_try_get_string(layout->pool_ns);
@@ -1054,6 +1056,38 @@ EXPORT_SYMBOL(ceph_osdc_new_request);
 DEFINE_RB_FUNCS(request, struct ceph_osd_request, r_tid, r_node)
 DEFINE_RB_FUNCS(request_mc, struct ceph_osd_request, r_tid, r_mc_node)
 
+/*
+ * Call @fn on each OSD request as long as @fn returns 0.
+ */
+static void for_each_request(struct ceph_osd_client *osdc,
+                       int (*fn)(struct ceph_osd_request *req, void *arg),
+                       void *arg)
+{
+       struct rb_node *n, *p;
+
+       for (n = rb_first(&osdc->osds); n; n = rb_next(n)) {
+               struct ceph_osd *osd = rb_entry(n, struct ceph_osd, o_node);
+
+               for (p = rb_first(&osd->o_requests); p; ) {
+                       struct ceph_osd_request *req =
+                           rb_entry(p, struct ceph_osd_request, r_node);
+
+                       p = rb_next(p);
+                       if (fn(req, arg))
+                               return;
+               }
+       }
+
+       for (p = rb_first(&osdc->homeless_osd.o_requests); p; ) {
+               struct ceph_osd_request *req =
+                   rb_entry(p, struct ceph_osd_request, r_node);
+
+               p = rb_next(p);
+               if (fn(req, arg))
+                       return;
+       }
+}
+
 static bool osd_homeless(struct ceph_osd *osd)
 {
        return osd->o_osd == CEPH_HOMELESS_OSD;
@@ -1395,7 +1429,6 @@ static enum calc_target_result calc_target(struct ceph_osd_client *osdc,
        bool recovery_deletes = ceph_osdmap_flag(osdc,
                                                 CEPH_OSDMAP_RECOVERY_DELETES);
        enum calc_target_result ct_res;
-       int ret;
 
        t->epoch = osdc->osdmap->epoch;
        pi = ceph_pg_pool_by_id(osdc->osdmap, t->base_oloc.pool);
@@ -1431,14 +1464,7 @@ static enum calc_target_result calc_target(struct ceph_osd_client *osdc,
                }
        }
 
-       ret = __ceph_object_locator_to_pg(pi, &t->target_oid, &t->target_oloc,
-                                         &pgid);
-       if (ret) {
-               WARN_ON(ret != -ENOENT);
-               t->osd = CEPH_HOMELESS_OSD;
-               ct_res = CALC_TARGET_POOL_DNE;
-               goto out;
-       }
+       __ceph_object_locator_to_pg(pi, &t->target_oid, &t->target_oloc, &pgid);
        last_pgid.pool = pgid.pool;
        last_pgid.seed = ceph_stable_mod(pgid.seed, t->pg_num, t->pg_num_mask);
 
@@ -2161,9 +2187,9 @@ static void __submit_request(struct ceph_osd_request *req, bool wrlocked)
        struct ceph_osd_client *osdc = req->r_osdc;
        struct ceph_osd *osd;
        enum calc_target_result ct_res;
+       int err = 0;
        bool need_send = false;
        bool promoted = false;
-       bool need_abort = false;
 
        WARN_ON(req->r_tid);
        dout("%s req %p wrlocked %d\n", __func__, req, wrlocked);
@@ -2179,7 +2205,10 @@ again:
                goto promote;
        }
 
-       if (osdc->osdmap->epoch < osdc->epoch_barrier) {
+       if (osdc->abort_err) {
+               dout("req %p abort_err %d\n", req, osdc->abort_err);
+               err = osdc->abort_err;
+       } else if (osdc->osdmap->epoch < osdc->epoch_barrier) {
                dout("req %p epoch %u barrier %u\n", req, osdc->osdmap->epoch,
                     osdc->epoch_barrier);
                req->r_t.paused = true;
@@ -2200,11 +2229,13 @@ again:
                   (ceph_osdmap_flag(osdc, CEPH_OSDMAP_FULL) ||
                    pool_full(osdc, req->r_t.base_oloc.pool))) {
                dout("req %p full/pool_full\n", req);
-               pr_warn_ratelimited("FULL or reached pool quota\n");
-               req->r_t.paused = true;
-               maybe_request_map(osdc);
-               if (req->r_abort_on_full)
-                       need_abort = true;
+               if (osdc->abort_on_full) {
+                       err = -ENOSPC;
+               } else {
+                       pr_warn_ratelimited("FULL or reached pool quota\n");
+                       req->r_t.paused = true;
+                       maybe_request_map(osdc);
+               }
        } else if (!osd_homeless(osd)) {
                need_send = true;
        } else {
@@ -2221,11 +2252,11 @@ again:
        link_request(osd, req);
        if (need_send)
                send_request(req);
-       else if (need_abort)
-               complete_request(req, -ENOSPC);
+       else if (err)
+               complete_request(req, err);
        mutex_unlock(&osd->lock);
 
-       if (ct_res == CALC_TARGET_POOL_DNE)
+       if (!err && ct_res == CALC_TARGET_POOL_DNE)
                send_map_check(req);
 
        if (promoted)
@@ -2281,11 +2312,21 @@ static void finish_request(struct ceph_osd_request *req)
 
 static void __complete_request(struct ceph_osd_request *req)
 {
-       if (req->r_callback) {
-               dout("%s req %p tid %llu cb %pf result %d\n", __func__, req,
-                    req->r_tid, req->r_callback, req->r_result);
+       dout("%s req %p tid %llu cb %pf result %d\n", __func__, req,
+            req->r_tid, req->r_callback, req->r_result);
+
+       if (req->r_callback)
                req->r_callback(req);
-       }
+       complete_all(&req->r_completion);
+       ceph_osdc_put_request(req);
+}
+
+static void complete_request_workfn(struct work_struct *work)
+{
+       struct ceph_osd_request *req =
+           container_of(work, struct ceph_osd_request, r_complete_work);
+
+       __complete_request(req);
 }
 
 /*
@@ -2297,9 +2338,9 @@ static void complete_request(struct ceph_osd_request *req, int err)
 
        req->r_result = err;
        finish_request(req);
-       __complete_request(req);
-       complete_all(&req->r_completion);
-       ceph_osdc_put_request(req);
+
+       INIT_WORK(&req->r_complete_work, complete_request_workfn);
+       queue_work(req->r_osdc->completion_wq, &req->r_complete_work);
 }
 
 static void cancel_map_check(struct ceph_osd_request *req)
@@ -2336,6 +2377,28 @@ static void abort_request(struct ceph_osd_request *req, int err)
        complete_request(req, err);
 }
 
+static int abort_fn(struct ceph_osd_request *req, void *arg)
+{
+       int err = *(int *)arg;
+
+       abort_request(req, err);
+       return 0; /* continue iteration */
+}
+
+/*
+ * Abort all in-flight requests with @err and arrange for all future
+ * requests to be failed immediately.
+ */
+void ceph_osdc_abort_requests(struct ceph_osd_client *osdc, int err)
+{
+       dout("%s osdc %p err %d\n", __func__, osdc, err);
+       down_write(&osdc->lock);
+       for_each_request(osdc, abort_fn, &err);
+       osdc->abort_err = err;
+       up_write(&osdc->lock);
+}
+EXPORT_SYMBOL(ceph_osdc_abort_requests);
+
 static void update_epoch_barrier(struct ceph_osd_client *osdc, u32 eb)
 {
        if (likely(eb > osdc->epoch_barrier)) {
@@ -2362,6 +2425,30 @@ void ceph_osdc_update_epoch_barrier(struct ceph_osd_client *osdc, u32 eb)
 }
 EXPORT_SYMBOL(ceph_osdc_update_epoch_barrier);
 
+/*
+ * We can end up releasing caps as a result of abort_request().
+ * In that case, we probably want to ensure that the cap release message
+ * has an updated epoch barrier in it, so set the epoch barrier prior to
+ * aborting the first request.
+ */
+static int abort_on_full_fn(struct ceph_osd_request *req, void *arg)
+{
+       struct ceph_osd_client *osdc = req->r_osdc;
+       bool *victims = arg;
+
+       if ((req->r_flags & CEPH_OSD_FLAG_WRITE) &&
+           (ceph_osdmap_flag(osdc, CEPH_OSDMAP_FULL) ||
+            pool_full(osdc, req->r_t.base_oloc.pool))) {
+               if (!*victims) {
+                       update_epoch_barrier(osdc, osdc->osdmap->epoch);
+                       *victims = true;
+               }
+               abort_request(req, -ENOSPC);
+       }
+
+       return 0; /* continue iteration */
+}
+
 /*
  * Drop all pending requests that are stalled waiting on a full condition to
  * clear, and complete them with ENOSPC as the return code. Set the
@@ -2370,61 +2457,11 @@ EXPORT_SYMBOL(ceph_osdc_update_epoch_barrier);
  */
 static void ceph_osdc_abort_on_full(struct ceph_osd_client *osdc)
 {
-       struct rb_node *n;
        bool victims = false;
 
-       dout("enter abort_on_full\n");
-
-       if (!ceph_osdmap_flag(osdc, CEPH_OSDMAP_FULL) && !have_pool_full(osdc))
-               goto out;
-
-       /* Scan list and see if there is anything to abort */
-       for (n = rb_first(&osdc->osds); n; n = rb_next(n)) {
-               struct ceph_osd *osd = rb_entry(n, struct ceph_osd, o_node);
-               struct rb_node *m;
-
-               m = rb_first(&osd->o_requests);
-               while (m) {
-                       struct ceph_osd_request *req = rb_entry(m,
-                                       struct ceph_osd_request, r_node);
-                       m = rb_next(m);
-
-                       if (req->r_abort_on_full) {
-                               victims = true;
-                               break;
-                       }
-               }
-               if (victims)
-                       break;
-       }
-
-       if (!victims)
-               goto out;
-
-       /*
-        * Update the barrier to current epoch if it's behind that point,
-        * since we know we have some calls to be aborted in the tree.
-        */
-       update_epoch_barrier(osdc, osdc->osdmap->epoch);
-
-       for (n = rb_first(&osdc->osds); n; n = rb_next(n)) {
-               struct ceph_osd *osd = rb_entry(n, struct ceph_osd, o_node);
-               struct rb_node *m;
-
-               m = rb_first(&osd->o_requests);
-               while (m) {
-                       struct ceph_osd_request *req = rb_entry(m,
-                                       struct ceph_osd_request, r_node);
-                       m = rb_next(m);
-
-                       if (req->r_abort_on_full &&
-                           (ceph_osdmap_flag(osdc, CEPH_OSDMAP_FULL) ||
-                            pool_full(osdc, req->r_t.target_oloc.pool)))
-                               abort_request(req, -ENOSPC);
-               }
-       }
-out:
-       dout("return abort_on_full barrier=%u\n", osdc->epoch_barrier);
+       if (osdc->abort_on_full &&
+           (ceph_osdmap_flag(osdc, CEPH_OSDMAP_FULL) || have_pool_full(osdc)))
+               for_each_request(osdc, abort_on_full_fn, &victims);
 }
 
 static void check_pool_dne(struct ceph_osd_request *req)
@@ -3541,8 +3578,6 @@ static void handle_reply(struct ceph_osd *osd, struct ceph_msg *msg)
        up_read(&osdc->lock);
 
        __complete_request(req);
-       complete_all(&req->r_completion);
-       ceph_osdc_put_request(req);
        return;
 
 fail_request:
@@ -4927,7 +4962,10 @@ int ceph_osdc_call(struct ceph_osd_client *osdc,
        if (ret)
                goto out_put_req;
 
-       osd_req_op_cls_init(req, 0, CEPH_OSD_OP_CALL, class, method);
+       ret = osd_req_op_cls_init(req, 0, CEPH_OSD_OP_CALL, class, method);
+       if (ret)
+               goto out_put_req;
+
        if (req_page)
                osd_req_op_cls_request_data_pages(req, 0, &req_page, req_len,
                                                  0, false, false);
@@ -4996,6 +5034,10 @@ int ceph_osdc_init(struct ceph_osd_client *osdc, struct ceph_client *client)
        if (!osdc->notify_wq)
                goto out_msgpool_reply;
 
+       osdc->completion_wq = create_singlethread_workqueue("ceph-completion");
+       if (!osdc->completion_wq)
+               goto out_notify_wq;
+
        schedule_delayed_work(&osdc->timeout_work,
                              osdc->client->options->osd_keepalive_timeout);
        schedule_delayed_work(&osdc->osds_timeout_work,
@@ -5003,6 +5045,8 @@ int ceph_osdc_init(struct ceph_osd_client *osdc, struct ceph_client *client)
 
        return 0;
 
+out_notify_wq:
+       destroy_workqueue(osdc->notify_wq);
 out_msgpool_reply:
        ceph_msgpool_destroy(&osdc->msgpool_op_reply);
 out_msgpool:
@@ -5017,7 +5061,7 @@ out:
 
 void ceph_osdc_stop(struct ceph_osd_client *osdc)
 {
-       flush_workqueue(osdc->notify_wq);
+       destroy_workqueue(osdc->completion_wq);
        destroy_workqueue(osdc->notify_wq);
        cancel_delayed_work_sync(&osdc->timeout_work);
        cancel_delayed_work_sync(&osdc->osds_timeout_work);
index e22820e24f501224c2ebdc8f0dcc0cc0b59ae66d..98c0ff3d644174fe9f5ce30fedfd617c5236539b 100644 (file)
@@ -2146,10 +2146,10 @@ bool ceph_osds_changed(const struct ceph_osds *old_acting,
  * Should only be called with target_oid and target_oloc (as opposed to
  * base_oid and base_oloc), since tiering isn't taken into account.
  */
-int __ceph_object_locator_to_pg(struct ceph_pg_pool_info *pi,
-                               const struct ceph_object_id *oid,
-                               const struct ceph_object_locator *oloc,
-                               struct ceph_pg *raw_pgid)
+void __ceph_object_locator_to_pg(struct ceph_pg_pool_info *pi,
+                                const struct ceph_object_id *oid,
+                                const struct ceph_object_locator *oloc,
+                                struct ceph_pg *raw_pgid)
 {
        WARN_ON(pi->id != oloc->pool);
 
@@ -2165,11 +2165,8 @@ int __ceph_object_locator_to_pg(struct ceph_pg_pool_info *pi,
                int nsl = oloc->pool_ns->len;
                size_t total = nsl + 1 + oid->name_len;
 
-               if (total > sizeof(stack_buf)) {
-                       buf = kmalloc(total, GFP_NOIO);
-                       if (!buf)
-                               return -ENOMEM;
-               }
+               if (total > sizeof(stack_buf))
+                       buf = kmalloc(total, GFP_NOIO | __GFP_NOFAIL);
                memcpy(buf, oloc->pool_ns->str, nsl);
                buf[nsl] = '\037';
                memcpy(buf + nsl + 1, oid->name, oid->name_len);
@@ -2181,7 +2178,6 @@ int __ceph_object_locator_to_pg(struct ceph_pg_pool_info *pi,
                     oid->name, nsl, oloc->pool_ns->str,
                     raw_pgid->pool, raw_pgid->seed);
        }
-       return 0;
 }
 
 int ceph_object_locator_to_pg(struct ceph_osdmap *osdmap,
@@ -2195,7 +2191,8 @@ int ceph_object_locator_to_pg(struct ceph_osdmap *osdmap,
        if (!pi)
                return -ENOENT;
 
-       return __ceph_object_locator_to_pg(pi, oid, oloc, raw_pgid);
+       __ceph_object_locator_to_pg(pi, oid, oloc, raw_pgid);
+       return 0;
 }
 EXPORT_SYMBOL(ceph_object_locator_to_pg);
 
index a7a9c3d738ba8c3309fa17cfb85dae81d0d9a095..8e3fda9e725cba97973ed2ce85ebe6f2e926e7cf 100644 (file)
@@ -119,13 +119,14 @@ unsigned long neigh_rand_reach_time(unsigned long base)
 EXPORT_SYMBOL(neigh_rand_reach_time);
 
 
-static bool neigh_del(struct neighbour *n, __u8 state,
+static bool neigh_del(struct neighbour *n, __u8 state, __u8 flags,
                      struct neighbour __rcu **np, struct neigh_table *tbl)
 {
        bool retval = false;
 
        write_lock(&n->lock);
-       if (refcount_read(&n->refcnt) == 1 && !(n->nud_state & state)) {
+       if (refcount_read(&n->refcnt) == 1 && !(n->nud_state & state) &&
+           !(n->flags & flags)) {
                struct neighbour *neigh;
 
                neigh = rcu_dereference_protected(n->next,
@@ -157,7 +158,7 @@ bool neigh_remove_one(struct neighbour *ndel, struct neigh_table *tbl)
        while ((n = rcu_dereference_protected(*np,
                                              lockdep_is_held(&tbl->lock)))) {
                if (n == ndel)
-                       return neigh_del(n, 0, np, tbl);
+                       return neigh_del(n, 0, 0, np, tbl);
                np = &n->next;
        }
        return false;
@@ -185,7 +186,8 @@ static int neigh_forced_gc(struct neigh_table *tbl)
                         * - nobody refers to it.
                         * - it is not permanent
                         */
-                       if (neigh_del(n, NUD_PERMANENT, np, tbl)) {
+                       if (neigh_del(n, NUD_PERMANENT, NTF_EXT_LEARNED, np,
+                                     tbl)) {
                                shrunk = 1;
                                continue;
                        }
index f333d75ef1a9cd011a70eca7f84b20b80f5765ee..bcc41829a16d50714bdd3c25c976c0b7296fab84 100644 (file)
@@ -728,22 +728,9 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
                        sock_valbool_flag(sk, SOCK_DBG, valbool);
                break;
        case SO_REUSEADDR:
-               val = (valbool ? SK_CAN_REUSE : SK_NO_REUSE);
-               if ((sk->sk_family == PF_INET || sk->sk_family == PF_INET6) &&
-                   inet_sk(sk)->inet_num &&
-                   (sk->sk_reuse != val)) {
-                       ret = (sk->sk_state == TCP_ESTABLISHED) ? -EISCONN : -EUCLEAN;
-                       break;
-               }
-               sk->sk_reuse = val;
+               sk->sk_reuse = (valbool ? SK_CAN_REUSE : SK_NO_REUSE);
                break;
        case SO_REUSEPORT:
-               if ((sk->sk_family == PF_INET || sk->sk_family == PF_INET6) &&
-                   inet_sk(sk)->inet_num &&
-                   (sk->sk_reuseport != valbool)) {
-                       ret = (sk->sk_state == TCP_ESTABLISHED) ? -EISCONN : -EUCLEAN;
-                       break;
-               }
                sk->sk_reuseport = valbool;
                break;
        case SO_TYPE:
index 7d20e1f3de28a4826a9e39667a2a7a1a931cbb2b..56197f0d9608de25b857ad2f902c554002a2929b 100644 (file)
@@ -75,7 +75,8 @@ static struct sk_buff *trailer_rcv(struct sk_buff *skb, struct net_device *dev,
        if (!skb->dev)
                return NULL;
 
-       pskb_trim_rcsum(skb, skb->len - 4);
+       if (pskb_trim_rcsum(skb, skb->len - 4))
+               return NULL;
 
        return skb;
 }
index 38ab97b0a2ece3b6d712269312e6e310da8918f6..ca0dad90803a92bdcbb1e199554985ad4626fada 100644 (file)
@@ -531,6 +531,7 @@ find_check_entry(struct ipt_entry *e, struct net *net, const char *name,
                return -ENOMEM;
 
        j = 0;
+       memset(&mtpar, 0, sizeof(mtpar));
        mtpar.net       = net;
        mtpar.table     = name;
        mtpar.entryinfo = &e->ip;
index fed3f1c6616708997f621535efe9412e4afa0a50..bea17f1e8302585d70c1e0108ae1c33d149230d8 100644 (file)
@@ -1730,6 +1730,10 @@ process:
                        reqsk_put(req);
                        goto discard_it;
                }
+               if (tcp_checksum_complete(skb)) {
+                       reqsk_put(req);
+                       goto csum_error;
+               }
                if (unlikely(sk->sk_state != TCP_LISTEN)) {
                        inet_csk_reqsk_queue_drop_and_put(sk, req);
                        goto lookup;
index 4d58e2ce0b5b181b39aeb12f8761ba016606dd43..8cc7c348733052a8ef4bc06d09149171d8277006 100644 (file)
@@ -268,8 +268,6 @@ found:
                goto out_check_final;
        }
 
-       p = *head;
-       th2 = tcp_hdr(p);
        tcp_flag_word(th2) |= flags & (TCP_FLAG_FIN | TCP_FLAG_PSH);
 
 out_check_final:
index 89019bf59f4651d45bcc69503ebf7028371d60c3..c134286d6a4179516709570ad534d1ae26fd0bce 100644 (file)
@@ -1324,6 +1324,7 @@ retry:
                }
        }
 
+       memset(&cfg, 0, sizeof(cfg));
        cfg.valid_lft = min_t(__u32, ifp->valid_lft,
                              idev->cnf.temp_valid_lft + age);
        cfg.preferred_lft = cnf_temp_preferred_lft + age - idev->desync_factor;
@@ -1357,7 +1358,6 @@ retry:
 
        cfg.pfx = &addr;
        cfg.scope = ipv6_addr_scope(cfg.pfx);
-       cfg.rt_priority = 0;
 
        ift = ipv6_add_addr(idev, &cfg, block, NULL);
        if (IS_ERR(ift)) {
index 7aa4c41a3bd912e99490b46544b2fa6512e8a1fc..39d1d487eca25faceacbc3619fc6c4c38088d62a 100644 (file)
@@ -934,6 +934,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
 {
        struct fib6_info *leaf = rcu_dereference_protected(fn->leaf,
                                    lockdep_is_held(&rt->fib6_table->tb6_lock));
+       enum fib_event_type event = FIB_EVENT_ENTRY_ADD;
        struct fib6_info *iter = NULL, *match = NULL;
        struct fib6_info __rcu **ins;
        int replace = (info->nlh &&
@@ -1013,6 +1014,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
                                       "Can not append to a REJECT route");
                        return -EINVAL;
                }
+               event = FIB_EVENT_ENTRY_APPEND;
                rt->fib6_nsiblings = match->fib6_nsiblings;
                list_add_tail(&rt->fib6_siblings, &match->fib6_siblings);
                match->fib6_nsiblings++;
@@ -1034,15 +1036,12 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
         *      insert node
         */
        if (!replace) {
-               enum fib_event_type event;
-
                if (!add)
                        pr_warn("NLM_F_CREATE should be set when creating new route\n");
 
 add:
                nlflags |= NLM_F_CREATE;
 
-               event = append ? FIB_EVENT_ENTRY_APPEND : FIB_EVENT_ENTRY_ADD;
                err = call_fib6_entry_notifiers(info->nl_net, event, rt,
                                                extack);
                if (err)
index 0758b5bcfb2905e0bc342fc6e7ded6a3eb9bee28..7eab959734bc736cc103551fb50bce84f9aeaec7 100644 (file)
@@ -550,6 +550,7 @@ find_check_entry(struct ip6t_entry *e, struct net *net, const char *name,
                return -ENOMEM;
 
        j = 0;
+       memset(&mtpar, 0, sizeof(mtpar));
        mtpar.net       = net;
        mtpar.table     = name;
        mtpar.entryinfo = &e->ipv6;
index fb956989adaf4735f3c4ac94def46ff45782a9bf..86a0e4333d42212d03f53e0d54fcf4e03a328607 100644 (file)
@@ -2307,9 +2307,6 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
        const struct in6_addr *daddr, *saddr;
        struct rt6_info *rt6 = (struct rt6_info *)dst;
 
-       if (rt6->rt6i_flags & RTF_LOCAL)
-               return;
-
        if (dst_metric_locked(dst, RTAX_MTU))
                return;
 
index b620d9b72e595ba4390b3e02ff8a0bbafa49eebe..7efa9fd7e1094dc43ca464e5c6f06ea36031d476 100644 (file)
@@ -1479,6 +1479,10 @@ process:
                        reqsk_put(req);
                        goto discard_it;
                }
+               if (tcp_checksum_complete(skb)) {
+                       reqsk_put(req);
+                       goto csum_error;
+               }
                if (unlikely(sk->sk_state != TCP_LISTEN)) {
                        inet_csk_reqsk_queue_drop_and_put(sk, req);
                        goto lookup;
index 6616c9fd292f1ddae6b974bb2d70de7d7dc1bd28..5b9900889e311f964c4d7640f152a60edfb02740 100644 (file)
@@ -553,6 +553,12 @@ static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *inf
                goto out_tunnel;
        }
 
+       /* L2TPv2 only accepts PPP pseudo-wires */
+       if (tunnel->version == 2 && cfg.pw_type != L2TP_PWTYPE_PPP) {
+               ret = -EPROTONOSUPPORT;
+               goto out_tunnel;
+       }
+
        if (tunnel->version > 2) {
                if (info->attrs[L2TP_ATTR_DATA_SEQ])
                        cfg.data_seq = nla_get_u8(info->attrs[L2TP_ATTR_DATA_SEQ]);
index b56cb1df4fc076ecfa1c76031f621c2c79b06126..55188382845c310c98eb86cdfc3b78e1d03e8e0f 100644 (file)
@@ -612,6 +612,8 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
        u32 session_id, peer_session_id;
        bool drop_refcnt = false;
        bool drop_tunnel = false;
+       bool new_session = false;
+       bool new_tunnel = false;
        int ver = 2;
        int fd;
 
@@ -701,6 +703,15 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
                                .encap = L2TP_ENCAPTYPE_UDP,
                                .debug = 0,
                        };
+
+                       /* Prevent l2tp_tunnel_register() from trying to set up
+                        * a kernel socket.
+                        */
+                       if (fd < 0) {
+                               error = -EBADF;
+                               goto end;
+                       }
+
                        error = l2tp_tunnel_create(sock_net(sk), fd, ver, tunnel_id, peer_tunnel_id, &tcfg, &tunnel);
                        if (error < 0)
                                goto end;
@@ -713,6 +724,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
                                goto end;
                        }
                        drop_tunnel = true;
+                       new_tunnel = true;
                }
        } else {
                /* Error if we can't find the tunnel */
@@ -734,6 +746,12 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
        session = l2tp_session_get(sock_net(sk), tunnel, session_id);
        if (session) {
                drop_refcnt = true;
+
+               if (session->pwtype != L2TP_PWTYPE_PPP) {
+                       error = -EPROTOTYPE;
+                       goto end;
+               }
+
                ps = l2tp_session_priv(session);
 
                /* Using a pre-existing session is fine as long as it hasn't
@@ -751,6 +769,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
                /* Default MTU must allow space for UDP/L2TP/PPP headers */
                cfg.mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD;
                cfg.mru = cfg.mtu;
+               cfg.pw_type = L2TP_PWTYPE_PPP;
 
                session = l2tp_session_create(sizeof(struct pppol2tp_session),
                                              tunnel, session_id,
@@ -772,6 +791,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
                        goto end;
                }
                drop_refcnt = true;
+               new_session = true;
        }
 
        /* Special case: if source & dest session_id == 0x0000, this
@@ -818,6 +838,12 @@ out_no_ppp:
                  session->name);
 
 end:
+       if (error) {
+               if (new_session)
+                       l2tp_session_delete(session);
+               if (new_tunnel)
+                       l2tp_tunnel_delete(tunnel);
+       }
        if (drop_refcnt)
                l2tp_session_dec_refcount(session);
        if (drop_tunnel)
@@ -1175,7 +1201,7 @@ static int pppol2tp_tunnel_ioctl(struct l2tp_tunnel *tunnel,
                                l2tp_session_get(sock_net(sk), tunnel,
                                                 stats.session_id);
 
-                       if (session) {
+                       if (session && session->pwtype == L2TP_PWTYPE_PPP) {
                                err = pppol2tp_session_ioctl(session, cmd,
                                                             arg);
                                l2tp_session_dec_refcount(session);
index fb1b1f9e7e5e03281fabe79175c62f3817354d0d..fb73451ed85ec65cd0b4b5cc3808d51d40a8dd39 100644 (file)
@@ -1098,6 +1098,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 
        ieee80211_led_init(local);
 
+       result = ieee80211_txq_setup_flows(local);
+       if (result)
+               goto fail_flows;
+
        rtnl_lock();
 
        result = ieee80211_init_rate_ctrl_alg(local,
@@ -1120,10 +1124,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 
        rtnl_unlock();
 
-       result = ieee80211_txq_setup_flows(local);
-       if (result)
-               goto fail_flows;
-
 #ifdef CONFIG_INET
        local->ifa_notifier.notifier_call = ieee80211_ifa_changed;
        result = register_inetaddr_notifier(&local->ifa_notifier);
@@ -1149,8 +1149,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 #if defined(CONFIG_INET) || defined(CONFIG_IPV6)
  fail_ifa:
 #endif
-       ieee80211_txq_teardown_flows(local);
- fail_flows:
        rtnl_lock();
        rate_control_deinitialize(local);
        ieee80211_remove_interfaces(local);
@@ -1158,6 +1156,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        rtnl_unlock();
        ieee80211_led_exit(local);
        ieee80211_wep_free(local);
+       ieee80211_txq_teardown_flows(local);
+ fail_flows:
        destroy_workqueue(local->workqueue);
  fail_workqueue:
        wiphy_unregister(local->hw.wiphy);
index bbad940c01373f7929feae44d5729e1a55fb58b7..8a33dac4e8058b0ec07281814f5c90507421eb4e 100644 (file)
@@ -1234,7 +1234,10 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
        pr_debug("Create set %s with family %s\n",
                 set->name, set->family == NFPROTO_IPV4 ? "inet" : "inet6");
 
-#ifndef IP_SET_PROTO_UNDEF
+#ifdef IP_SET_PROTO_UNDEF
+       if (set->family != NFPROTO_UNSPEC)
+               return -IPSET_ERR_INVALID_FAMILY;
+#else
        if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
                return -IPSET_ERR_INVALID_FAMILY;
 #endif
index 0c03c0e16a964ccea12ffa54ea2e4f697d6ea244..dd21782e2f12fc30d5bd227f3c33bc9362c72942 100644 (file)
@@ -839,6 +839,9 @@ __ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest,
                 *    For now only for NAT!
                 */
                ip_vs_rs_hash(ipvs, dest);
+               /* FTP-NAT requires conntrack for mangling */
+               if (svc->port == FTPPORT)
+                       ip_vs_register_conntrack(svc);
        }
        atomic_set(&dest->conn_flags, conn_flags);
 
@@ -1462,6 +1465,7 @@ static void __ip_vs_del_service(struct ip_vs_service *svc, bool cleanup)
  */
 static void ip_vs_unlink_service(struct ip_vs_service *svc, bool cleanup)
 {
+       ip_vs_unregister_conntrack(svc);
        /* Hold svc to avoid double release from dest_trash */
        atomic_inc(&svc->refcnt);
        /*
index ba0a0fd045c857b97e112d2e6a40634b690e1d83..473cce2a5231c8f3757e82c8f94eaf81326d9f4b 100644 (file)
@@ -168,7 +168,7 @@ static inline bool crosses_local_route_boundary(int skb_af, struct sk_buff *skb,
                                                bool new_rt_is_local)
 {
        bool rt_mode_allow_local = !!(rt_mode & IP_VS_RT_MODE_LOCAL);
-       bool rt_mode_allow_non_local = !!(rt_mode & IP_VS_RT_MODE_LOCAL);
+       bool rt_mode_allow_non_local = !!(rt_mode & IP_VS_RT_MODE_NON_LOCAL);
        bool rt_mode_allow_redirect = !!(rt_mode & IP_VS_RT_MODE_RDR);
        bool source_is_loopback;
        bool old_rt_is_local;
index 3b5059a8dcdd19d1aadaf10e5600cb65491c812c..d8383609fe2825b707cfb8ebc54381761ccc1108 100644 (file)
@@ -46,6 +46,7 @@
 struct nf_conncount_tuple {
        struct hlist_node               node;
        struct nf_conntrack_tuple       tuple;
+       struct nf_conntrack_zone        zone;
 };
 
 struct nf_conncount_rb {
@@ -80,7 +81,8 @@ static int key_diff(const u32 *a, const u32 *b, unsigned int klen)
 }
 
 bool nf_conncount_add(struct hlist_head *head,
-                     const struct nf_conntrack_tuple *tuple)
+                     const struct nf_conntrack_tuple *tuple,
+                     const struct nf_conntrack_zone *zone)
 {
        struct nf_conncount_tuple *conn;
 
@@ -88,6 +90,7 @@ bool nf_conncount_add(struct hlist_head *head,
        if (conn == NULL)
                return false;
        conn->tuple = *tuple;
+       conn->zone = *zone;
        hlist_add_head(&conn->node, head);
        return true;
 }
@@ -108,7 +111,7 @@ unsigned int nf_conncount_lookup(struct net *net, struct hlist_head *head,
 
        /* check the saved connections */
        hlist_for_each_entry_safe(conn, n, head, node) {
-               found = nf_conntrack_find_get(net, zone, &conn->tuple);
+               found = nf_conntrack_find_get(net, &conn->zone, &conn->tuple);
                if (found == NULL) {
                        hlist_del(&conn->node);
                        kmem_cache_free(conncount_conn_cachep, conn);
@@ -117,7 +120,8 @@ unsigned int nf_conncount_lookup(struct net *net, struct hlist_head *head,
 
                found_ct = nf_ct_tuplehash_to_ctrack(found);
 
-               if (tuple && nf_ct_tuple_equal(&conn->tuple, tuple)) {
+               if (tuple && nf_ct_tuple_equal(&conn->tuple, tuple) &&
+                   nf_ct_zone_equal(found_ct, zone, zone->dir)) {
                        /*
                         * Just to be sure we have it only once in the list.
                         * We should not see tuples twice unless someone hooks
@@ -196,7 +200,7 @@ count_tree(struct net *net, struct rb_root *root,
                        if (!addit)
                                return count;
 
-                       if (!nf_conncount_add(&rbconn->hhead, tuple))
+                       if (!nf_conncount_add(&rbconn->hhead, tuple, zone))
                                return 0; /* hotdrop */
 
                        return count + 1;
@@ -238,6 +242,7 @@ count_tree(struct net *net, struct rb_root *root,
        }
 
        conn->tuple = *tuple;
+       conn->zone = *zone;
        memcpy(rbconn->key, key, sizeof(u32) * keylen);
 
        INIT_HLIST_HEAD(&rbconn->hhead);
index 39327a42879f7f614fa46f6577c3f883aa3714ce..20a2e37c76d124e31771c9bf96bd13216501202a 100644 (file)
@@ -1446,7 +1446,8 @@ ctnetlink_parse_nat_setup(struct nf_conn *ct,
                }
                nfnl_lock(NFNL_SUBSYS_CTNETLINK);
                rcu_read_lock();
-               if (nat_hook->parse_nat_setup)
+               nat_hook = rcu_dereference(nf_nat_hook);
+               if (nat_hook)
                        return -EAGAIN;
 #endif
                return -EOPNOTSUPP;
index f0411fbffe77a96655f66c618d22e4a9d53fcb06..896d4a36081d4bb527b10c5db27df1a4dab32df8 100644 (file)
@@ -2890,12 +2890,13 @@ static struct nft_set *nft_set_lookup_byid(const struct net *net,
        u32 id = ntohl(nla_get_be32(nla));
 
        list_for_each_entry(trans, &net->nft.commit_list, list) {
-               struct nft_set *set = nft_trans_set(trans);
+               if (trans->msg_type == NFT_MSG_NEWSET) {
+                       struct nft_set *set = nft_trans_set(trans);
 
-               if (trans->msg_type == NFT_MSG_NEWSET &&
-                   id == nft_trans_set_id(trans) &&
-                   nft_active_genmask(set, genmask))
-                       return set;
+                       if (id == nft_trans_set_id(trans) &&
+                           nft_active_genmask(set, genmask))
+                               return set;
+               }
        }
        return ERR_PTR(-ENOENT);
 }
@@ -5836,18 +5837,23 @@ static int nf_tables_flowtable_event(struct notifier_block *this,
        struct net_device *dev = netdev_notifier_info_to_dev(ptr);
        struct nft_flowtable *flowtable;
        struct nft_table *table;
+       struct net *net;
 
        if (event != NETDEV_UNREGISTER)
                return 0;
 
+       net = maybe_get_net(dev_net(dev));
+       if (!net)
+               return 0;
+
        nfnl_lock(NFNL_SUBSYS_NFTABLES);
-       list_for_each_entry(table, &dev_net(dev)->nft.tables, list) {
+       list_for_each_entry(table, &net->nft.tables, list) {
                list_for_each_entry(flowtable, &table->flowtables, list) {
                        nft_flowtable_event(event, dev, flowtable);
                }
        }
        nfnl_unlock(NFNL_SUBSYS_NFTABLES);
-
+       put_net(net);
        return NOTIFY_DONE;
 }
 
@@ -6438,7 +6444,7 @@ static void nf_tables_abort_release(struct nft_trans *trans)
        kfree(trans);
 }
 
-static int nf_tables_abort(struct net *net, struct sk_buff *skb)
+static int __nf_tables_abort(struct net *net)
 {
        struct nft_trans *trans, *next;
        struct nft_trans_elem *te;
@@ -6554,6 +6560,11 @@ static void nf_tables_cleanup(struct net *net)
        nft_validate_state_update(net, NFT_VALIDATE_SKIP);
 }
 
+static int nf_tables_abort(struct net *net, struct sk_buff *skb)
+{
+       return __nf_tables_abort(net);
+}
+
 static bool nf_tables_valid_genid(struct net *net, u32 genid)
 {
        return net->nft.base_seq == genid;
@@ -7148,9 +7159,12 @@ static int __net_init nf_tables_init_net(struct net *net)
 
 static void __net_exit nf_tables_exit_net(struct net *net)
 {
+       nfnl_lock(NFNL_SUBSYS_NFTABLES);
+       if (!list_empty(&net->nft.commit_list))
+               __nf_tables_abort(net);
        __nft_release_tables(net);
+       nfnl_unlock(NFNL_SUBSYS_NFTABLES);
        WARN_ON_ONCE(!list_empty(&net->nft.tables));
-       WARN_ON_ONCE(!list_empty(&net->nft.commit_list));
 }
 
 static struct pernet_operations nf_tables_net_ops = {
@@ -7192,13 +7206,13 @@ err1:
 
 static void __exit nf_tables_module_exit(void)
 {
-       unregister_pernet_subsys(&nf_tables_net_ops);
        nfnetlink_subsys_unregister(&nf_tables_subsys);
        unregister_netdevice_notifier(&nf_tables_flowtable_notifier);
+       nft_chain_filter_fini();
+       unregister_pernet_subsys(&nf_tables_net_ops);
        rcu_barrier();
        nf_tables_core_module_exit();
        kfree(info);
-       nft_chain_filter_fini();
 }
 
 module_init(nf_tables_module_init);
index deff10adef9c4b97bf60f0f5d18d46e33fcfd348..8de912ca53d3bfb1b2a924cbeb655d8e4d4ebd3a 100644 (file)
@@ -183,7 +183,8 @@ next_rule:
 
        switch (regs.verdict.code) {
        case NFT_JUMP:
-               BUG_ON(stackptr >= NFT_JUMP_STACK_SIZE);
+               if (WARN_ON_ONCE(stackptr >= NFT_JUMP_STACK_SIZE))
+                       return NF_DROP;
                jumpstack[stackptr].chain = chain;
                jumpstack[stackptr].rules = rules + 1;
                stackptr++;
index 4d0da7042affbcc4a2d129c852cf1b6fd2bf04a3..e1b6be29848d2c00590ce98458f84b4243a5b45b 100644 (file)
@@ -429,7 +429,7 @@ replay:
                         */
                        if (err == -EAGAIN) {
                                status |= NFNL_BATCH_REPLAY;
-                               goto next;
+                               goto done;
                        }
                }
 ack:
@@ -456,7 +456,7 @@ ack:
                        if (err)
                                status |= NFNL_BATCH_FAILURE;
                }
-next:
+
                msglen = NLMSG_ALIGN(nlh->nlmsg_len);
                if (msglen > skb->len)
                        msglen = skb->len;
@@ -464,7 +464,11 @@ next:
        }
 done:
        if (status & NFNL_BATCH_REPLAY) {
-               ss->abort(net, oskb);
+               const struct nfnetlink_subsystem *ss2;
+
+               ss2 = nfnl_dereference_protected(subsys_id);
+               if (ss2 == ss)
+                       ss->abort(net, oskb);
                nfnl_err_reset(&err_list);
                nfnl_unlock(subsys_id);
                kfree_skb(skb);
index 84c902477a91efa963b7613743c0e07ff3afc867..d21834bed805b789c72d79640d8e98b2a6cf247c 100644 (file)
@@ -318,6 +318,10 @@ static int nf_tables_netdev_event(struct notifier_block *this,
            event != NETDEV_CHANGENAME)
                return NOTIFY_DONE;
 
+       ctx.net = maybe_get_net(ctx.net);
+       if (!ctx.net)
+               return NOTIFY_DONE;
+
        nfnl_lock(NFNL_SUBSYS_NFTABLES);
        list_for_each_entry(table, &ctx.net->nft.tables, list) {
                if (table->family != NFPROTO_NETDEV)
@@ -334,6 +338,7 @@ static int nf_tables_netdev_event(struct notifier_block *this,
                }
        }
        nfnl_unlock(NFNL_SUBSYS_NFTABLES);
+       put_net(ctx.net);
 
        return NOTIFY_DONE;
 }
index 50c068d660e54647c0068c087a9f6b90f9e14686..a832c59f0a9cbeb30cd1d261c2be81fc8b5d7027 100644 (file)
@@ -52,7 +52,7 @@ static inline void nft_connlimit_do_eval(struct nft_connlimit *priv,
        if (!addit)
                goto out;
 
-       if (!nf_conncount_add(&priv->hhead, tuple_ptr)) {
+       if (!nf_conncount_add(&priv->hhead, tuple_ptr, zone)) {
                regs->verdict.code = NF_DROP;
                spin_unlock_bh(&priv->lock);
                return;
index 4d49529cff615285bd3d1c8d5914e2624ece7da4..27d7e4598ab63c982b034136a3115f710b545679 100644 (file)
@@ -203,9 +203,7 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
                                goto err1;
                        set->ops->gc_init(set);
                }
-
-       } else if (set->flags & NFT_SET_EVAL)
-               return -EINVAL;
+       }
 
        nft_set_ext_prepare(&priv->tmpl);
        nft_set_ext_add_length(&priv->tmpl, NFT_SET_EXT_KEY, set->klen);
index d260ce2d6671e8d18bed0eb8bcf673fdd132342d..7f3a9a211034b2dee751dd776e1b5f59db6c6b61 100644 (file)
@@ -66,7 +66,7 @@ static bool __nft_rbtree_lookup(const struct net *net, const struct nft_set *set
                        parent = rcu_dereference_raw(parent->rb_left);
                        if (interval &&
                            nft_rbtree_equal(set, this, interval) &&
-                           nft_rbtree_interval_end(this) &&
+                           nft_rbtree_interval_end(rbe) &&
                            !nft_rbtree_interval_end(interval))
                                continue;
                        interval = rbe;
index f28a0b944087960d3eb6157c4a174fc8a8391c10..74e1b3bd695417daf3afb725d3183658a3a81342 100644 (file)
@@ -142,3 +142,4 @@ module_exit(nft_socket_module_exit);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Máté Eckl");
 MODULE_DESCRIPTION("nf_tables socket match module");
+MODULE_ALIAS_NFT_EXPR("socket");
index 8790190c6feb3cf1bce5577319fc043a5c55dc2c..03b9a50ec93bd958d1ef46d59a981f8be1d89aa4 100644 (file)
@@ -245,12 +245,22 @@ static int xt_ct_tg_check(const struct xt_tgchk_param *par,
        }
 
        if (info->helper[0]) {
+               if (strnlen(info->helper, sizeof(info->helper)) == sizeof(info->helper)) {
+                       ret = -ENAMETOOLONG;
+                       goto err3;
+               }
+
                ret = xt_ct_set_helper(ct, info->helper, par);
                if (ret < 0)
                        goto err3;
        }
 
        if (info->timeout[0]) {
+               if (strnlen(info->timeout, sizeof(info->timeout)) == sizeof(info->timeout)) {
+                       ret = -ENAMETOOLONG;
+                       goto err4;
+               }
+
                ret = xt_ct_set_timeout(ct, par, info->timeout);
                if (ret < 0)
                        goto err4;
index 94df000abb92d657addb2cad35028a2d3f08e024..29c38aa7f72620dc095406955bcda94e686df82d 100644 (file)
@@ -211,7 +211,7 @@ static int __init connmark_mt_init(void)
 static void __exit connmark_mt_exit(void)
 {
        xt_unregister_match(&connmark_mt_reg);
-       xt_unregister_target(connmark_tg_reg);
+       xt_unregister_targets(connmark_tg_reg, ARRAY_SIZE(connmark_tg_reg));
 }
 
 module_init(connmark_mt_init);
index 6f4c5217d8358cadb1537b0f4c3a3b4c1ab43175..bf2890b1321280bbf0b2791647158854b85f29e1 100644 (file)
@@ -372,8 +372,8 @@ set_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
 
        /* Normalize to fit into jiffies */
        if (add_opt.ext.timeout != IPSET_NO_TIMEOUT &&
-           add_opt.ext.timeout > UINT_MAX / MSEC_PER_SEC)
-               add_opt.ext.timeout = UINT_MAX / MSEC_PER_SEC;
+           add_opt.ext.timeout > IPSET_MAX_TIMEOUT)
+               add_opt.ext.timeout = IPSET_MAX_TIMEOUT;
        if (info->add_set.index != IPSET_INVALID_ID)
                ip_set_add(info->add_set.index, skb, par, &add_opt);
        if (info->del_set.index != IPSET_INVALID_ID)
@@ -407,8 +407,8 @@ set_target_v3(struct sk_buff *skb, const struct xt_action_param *par)
 
        /* Normalize to fit into jiffies */
        if (add_opt.ext.timeout != IPSET_NO_TIMEOUT &&
-           add_opt.ext.timeout > UINT_MAX / MSEC_PER_SEC)
-               add_opt.ext.timeout = UINT_MAX / MSEC_PER_SEC;
+           add_opt.ext.timeout > IPSET_MAX_TIMEOUT)
+               add_opt.ext.timeout = IPSET_MAX_TIMEOUT;
        if (info->add_set.index != IPSET_INVALID_ID)
                ip_set_add(info->add_set.index, skb, par, &add_opt);
        if (info->del_set.index != IPSET_INVALID_ID)
@@ -470,7 +470,7 @@ set_target_v3_checkentry(const struct xt_tgchk_param *par)
                }
                if (((info->flags & IPSET_FLAG_MAP_SKBPRIO) |
                     (info->flags & IPSET_FLAG_MAP_SKBQUEUE)) &&
-                    !(par->hook_mask & (1 << NF_INET_FORWARD |
+                    (par->hook_mask & ~(1 << NF_INET_FORWARD |
                                         1 << NF_INET_LOCAL_OUT |
                                         1 << NF_INET_POST_ROUTING))) {
                        pr_info_ratelimited("mapping of prio or/and queue is allowed only from OUTPUT/FORWARD/POSTROUTING chains\n");
index f2bf78de5688a3ee44862fe158bffee4ca94d91a..dac6218a460ed4d4a5b7b03ad4f6056a68784a16 100644 (file)
@@ -193,4 +193,5 @@ struct rds_transport rds_loop_transport = {
        .inc_copy_to_user       = rds_message_inc_copy_to_user,
        .inc_free               = rds_loop_inc_free,
        .t_name                 = "loopback",
+       .t_type                 = RDS_TRANS_LOOP,
 };
index b04c333d9d1c201ba4aa4617c750941cf4cdfec7..f2272fb8cd456e7b5bb2495d5d02691803c3769f 100644 (file)
@@ -479,6 +479,11 @@ struct rds_notifier {
        int                     n_status;
 };
 
+/* Available as part of RDS core, so doesn't need to participate
+ * in get_preferred transport etc
+ */
+#define        RDS_TRANS_LOOP  3
+
 /**
  * struct rds_transport -  transport specific behavioural hooks
  *
index dc67458b52f0043c2328d4a77a43536e7c62b0ed..192ac6f78ded7b0288ac01d641cd5f7772b03fd8 100644 (file)
@@ -103,6 +103,11 @@ static void rds_recv_rcvbuf_delta(struct rds_sock *rs, struct sock *sk,
                rds_stats_add(s_recv_bytes_added_to_socket, delta);
        else
                rds_stats_add(s_recv_bytes_removed_from_socket, -delta);
+
+       /* loop transport doesn't send/recv congestion updates */
+       if (rs->rs_transport->t_type == RDS_TRANS_LOOP)
+               return;
+
        now_congested = rs->rs_rcv_bytes > rds_sk_rcvbuf(rs);
 
        rdsdebug("rs %p (%pI4:%u) recv bytes %d buf %d "
index e672dee302c7092433a64ed3ed8bfcd183e1f9c8..7f849b01ec8e6767b851145bbf3d7086cc1cef23 100644 (file)
@@ -409,6 +409,21 @@ static void sctp_packet_set_owner_w(struct sk_buff *skb, struct sock *sk)
        refcount_inc(&sk->sk_wmem_alloc);
 }
 
+static void sctp_packet_gso_append(struct sk_buff *head, struct sk_buff *skb)
+{
+       if (SCTP_OUTPUT_CB(head)->last == head)
+               skb_shinfo(head)->frag_list = skb;
+       else
+               SCTP_OUTPUT_CB(head)->last->next = skb;
+       SCTP_OUTPUT_CB(head)->last = skb;
+
+       head->truesize += skb->truesize;
+       head->data_len += skb->len;
+       head->len += skb->len;
+
+       __skb_header_release(skb);
+}
+
 static int sctp_packet_pack(struct sctp_packet *packet,
                            struct sk_buff *head, int gso, gfp_t gfp)
 {
@@ -422,7 +437,7 @@ static int sctp_packet_pack(struct sctp_packet *packet,
 
        if (gso) {
                skb_shinfo(head)->gso_type = sk->sk_gso_type;
-               NAPI_GRO_CB(head)->last = head;
+               SCTP_OUTPUT_CB(head)->last = head;
        } else {
                nskb = head;
                pkt_size = packet->size;
@@ -503,15 +518,8 @@ merge:
                                         &packet->chunk_list);
                }
 
-               if (gso) {
-                       if (skb_gro_receive(&head, nskb)) {
-                               kfree_skb(nskb);
-                               return 0;
-                       }
-                       if (WARN_ON_ONCE(skb_shinfo(head)->gso_segs >=
-                                        sk->sk_gso_max_segs))
-                               return 0;
-               }
+               if (gso)
+                       sctp_packet_gso_append(head, nskb);
 
                pkt_count++;
        } while (!list_empty(&packet->chunk_list));
index 973b4471b532b0e64525e94bb2cb181a88b17bbc..da7f02edcd374c44437e34a2705f410317ea536d 100644 (file)
@@ -1273,8 +1273,7 @@ static __poll_t smc_accept_poll(struct sock *parent)
        return mask;
 }
 
-static __poll_t smc_poll(struct file *file, struct socket *sock,
-                            poll_table *wait)
+static __poll_t smc_poll_mask(struct socket *sock, __poll_t events)
 {
        struct sock *sk = sock->sk;
        __poll_t mask = 0;
@@ -1290,7 +1289,7 @@ static __poll_t smc_poll(struct file *file, struct socket *sock,
        if ((sk->sk_state == SMC_INIT) || smc->use_fallback) {
                /* delegate to CLC child sock */
                release_sock(sk);
-               mask = smc->clcsock->ops->poll(file, smc->clcsock, wait);
+               mask = smc->clcsock->ops->poll_mask(smc->clcsock, events);
                lock_sock(sk);
                sk->sk_err = smc->clcsock->sk->sk_err;
                if (sk->sk_err) {
@@ -1308,11 +1307,6 @@ static __poll_t smc_poll(struct file *file, struct socket *sock,
                        }
                }
        } else {
-               if (sk->sk_state != SMC_CLOSED) {
-                       release_sock(sk);
-                       sock_poll_wait(file, sk_sleep(sk), wait);
-                       lock_sock(sk);
-               }
                if (sk->sk_err)
                        mask |= EPOLLERR;
                if ((sk->sk_shutdown == SHUTDOWN_MASK) ||
@@ -1625,7 +1619,7 @@ static const struct proto_ops smc_sock_ops = {
        .socketpair     = sock_no_socketpair,
        .accept         = smc_accept,
        .getname        = smc_getname,
-       .poll           = smc_poll,
+       .poll_mask      = smc_poll_mask,
        .ioctl          = smc_ioctl,
        .listen         = smc_listen,
        .shutdown       = smc_shutdown,
index 301f224304698950544088c16518ea2e14ff41a6..a127d61e8af984d3aaefde49c94f48a9a9187d53 100644 (file)
@@ -712,7 +712,7 @@ static int __init tls_register(void)
        build_protos(tls_prots[TLSV4], &tcp_prot);
 
        tls_sw_proto_ops = inet_stream_ops;
-       tls_sw_proto_ops.poll = tls_sw_poll;
+       tls_sw_proto_ops.poll_mask = tls_sw_poll_mask;
        tls_sw_proto_ops.splice_read = tls_sw_splice_read;
 
 #ifdef CONFIG_TLS_DEVICE
index 8ca57d01b18f6bfc55a06bcc0c21d6220c7a01d5..f127fac88acfe0046b0a7dd55bab4d6d486de105 100644 (file)
@@ -191,18 +191,12 @@ static void tls_free_both_sg(struct sock *sk)
 }
 
 static int tls_do_encryption(struct tls_context *tls_ctx,
-                            struct tls_sw_context_tx *ctx, size_t data_len,
-                            gfp_t flags)
+                            struct tls_sw_context_tx *ctx,
+                            struct aead_request *aead_req,
+                            size_t data_len)
 {
-       unsigned int req_size = sizeof(struct aead_request) +
-               crypto_aead_reqsize(ctx->aead_send);
-       struct aead_request *aead_req;
        int rc;
 
-       aead_req = kzalloc(req_size, flags);
-       if (!aead_req)
-               return -ENOMEM;
-
        ctx->sg_encrypted_data[0].offset += tls_ctx->tx.prepend_size;
        ctx->sg_encrypted_data[0].length -= tls_ctx->tx.prepend_size;
 
@@ -219,7 +213,6 @@ static int tls_do_encryption(struct tls_context *tls_ctx,
        ctx->sg_encrypted_data[0].offset -= tls_ctx->tx.prepend_size;
        ctx->sg_encrypted_data[0].length += tls_ctx->tx.prepend_size;
 
-       kfree(aead_req);
        return rc;
 }
 
@@ -228,8 +221,14 @@ static int tls_push_record(struct sock *sk, int flags,
 {
        struct tls_context *tls_ctx = tls_get_ctx(sk);
        struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx);
+       struct aead_request *req;
        int rc;
 
+       req = kzalloc(sizeof(struct aead_request) +
+                     crypto_aead_reqsize(ctx->aead_send), sk->sk_allocation);
+       if (!req)
+               return -ENOMEM;
+
        sg_mark_end(ctx->sg_plaintext_data + ctx->sg_plaintext_num_elem - 1);
        sg_mark_end(ctx->sg_encrypted_data + ctx->sg_encrypted_num_elem - 1);
 
@@ -245,15 +244,14 @@ static int tls_push_record(struct sock *sk, int flags,
        tls_ctx->pending_open_record_frags = 0;
        set_bit(TLS_PENDING_CLOSED_RECORD, &tls_ctx->flags);
 
-       rc = tls_do_encryption(tls_ctx, ctx, ctx->sg_plaintext_size,
-                              sk->sk_allocation);
+       rc = tls_do_encryption(tls_ctx, ctx, req, ctx->sg_plaintext_size);
        if (rc < 0) {
                /* If we are called from write_space and
                 * we fail, we need to set this SOCK_NOSPACE
                 * to trigger another write_space in the future.
                 */
                set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
-               return rc;
+               goto out_req;
        }
 
        free_sg(sk, ctx->sg_plaintext_data, &ctx->sg_plaintext_num_elem,
@@ -268,6 +266,8 @@ static int tls_push_record(struct sock *sk, int flags,
                tls_err_abort(sk, EBADMSG);
 
        tls_advance_record_sn(sk, &tls_ctx->tx);
+out_req:
+       kfree(req);
        return rc;
 }
 
@@ -754,7 +754,7 @@ int tls_sw_recvmsg(struct sock *sk,
        struct sk_buff *skb;
        ssize_t copied = 0;
        bool cmsg = false;
-       int err = 0;
+       int target, err = 0;
        long timeo;
 
        flags |= nonblock;
@@ -764,6 +764,7 @@ int tls_sw_recvmsg(struct sock *sk,
 
        lock_sock(sk);
 
+       target = sock_rcvlowat(sk, flags & MSG_WAITALL, len);
        timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
        do {
                bool zc = false;
@@ -856,6 +857,9 @@ fallback_to_reg_recv:
                                        goto recv_end;
                        }
                }
+               /* If we have a new message from strparser, continue now. */
+               if (copied >= target && !ctx->recv_pkt)
+                       break;
        } while (len);
 
 recv_end:
@@ -915,23 +919,22 @@ splice_read_end:
        return copied ? : err;
 }
 
-unsigned int tls_sw_poll(struct file *file, struct socket *sock,
-                        struct poll_table_struct *wait)
+__poll_t tls_sw_poll_mask(struct socket *sock, __poll_t events)
 {
-       unsigned int ret;
        struct sock *sk = sock->sk;
        struct tls_context *tls_ctx = tls_get_ctx(sk);
        struct tls_sw_context_rx *ctx = tls_sw_ctx_rx(tls_ctx);
+       __poll_t mask;
 
-       /* Grab POLLOUT and POLLHUP from the underlying socket */
-       ret = ctx->sk_poll(file, sock, wait);
+       /* Grab EPOLLOUT and EPOLLHUP from the underlying socket */
+       mask = ctx->sk_poll_mask(sock, events);
 
-       /* Clear POLLIN bits, and set based on recv_pkt */
-       ret &= ~(POLLIN | POLLRDNORM);
+       /* Clear EPOLLIN bits, and set based on recv_pkt */
+       mask &= ~(EPOLLIN | EPOLLRDNORM);
        if (ctx->recv_pkt)
-               ret |= POLLIN | POLLRDNORM;
+               mask |= EPOLLIN | EPOLLRDNORM;
 
-       return ret;
+       return mask;
 }
 
 static int tls_read_size(struct strparser *strp, struct sk_buff *skb)
@@ -1188,7 +1191,7 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx)
                sk->sk_data_ready = tls_data_ready;
                write_unlock_bh(&sk->sk_callback_lock);
 
-               sw_ctx_rx->sk_poll = sk->sk_socket->ops->poll;
+               sw_ctx_rx->sk_poll_mask = sk->sk_socket->ops->poll_mask;
 
                strp_check_rcv(&sw_ctx_rx->strp);
        }
index 5fe35aafdd9cf849d78d46f0f7d960356c804987..48e8097339ab44cca29bc9bbc938b58ea3a43333 100644 (file)
@@ -1012,6 +1012,7 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev)
        nl80211_notify_iface(rdev, wdev, NL80211_CMD_DEL_INTERFACE);
 
        list_del_rcu(&wdev->list);
+       synchronize_rcu();
        rdev->devlist_generation++;
 
        switch (wdev->iftype) {
index b5bb1c30991461d980cd57e3e582e3ca69ac4516..3c654cd7ba562ad874c7176960c688b53fb80f61 100644 (file)
@@ -1746,6 +1746,8 @@ int cfg80211_get_station(struct net_device *dev, const u8 *mac_addr,
        if (!rdev->ops->get_station)
                return -EOPNOTSUPP;
 
+       memset(sinfo, 0, sizeof(*sinfo));
+
        return rdev_get_station(rdev, dev, mac_addr, sinfo);
 }
 EXPORT_SYMBOL(cfg80211_get_station);
index b9ef487c4618b56160ac73ed89271a6f03ebf371..f47abb46c5874c8b949b8d3cb3d278c479775e06 100644 (file)
@@ -204,7 +204,8 @@ static int xdp_umem_pin_pages(struct xdp_umem *umem)
        long npgs;
        int err;
 
-       umem->pgs = kcalloc(umem->npgs, sizeof(*umem->pgs), GFP_KERNEL);
+       umem->pgs = kcalloc(umem->npgs, sizeof(*umem->pgs),
+                           GFP_KERNEL | __GFP_NOWARN);
        if (!umem->pgs)
                return -ENOMEM;
 
index 2520bc14ffacf71f29e4db4d6682162deb6f6fe4..078999a3fdff7542ff52db288b96d9f0848e1c49 100755 (executable)
@@ -21,7 +21,7 @@ GetOptions(
 );
 
 if ($help != 0) {
-    print "$scriptname [--help] [--fix-rst]\n";
+    print "$scriptname [--help] [--fix]\n";
     exit -1;
 }
 
@@ -38,16 +38,31 @@ while (<IN>) {
        my $f = $1;
        my $ln = $2;
 
-       # Makefiles contain nasty expressions to parse docs
-       next if ($f =~ m/Makefile/);
+       # Makefiles and scripts contain nasty expressions to parse docs
+       next if ($f =~ m/Makefile/ || $f =~ m/\.sh$/);
+
        # Skip this script
        next if ($f eq $scriptname);
 
-       if ($ln =~ m,\b(\S*)(Documentation/[A-Za-z0-9\_\.\,\~/\*+-]*),) {
+       if ($ln =~ m,\b(\S*)(Documentation/[A-Za-z0-9\_\.\,\~/\*\[\]\?+-]*)(.*),) {
                my $prefix = $1;
                my $ref = $2;
                my $base = $2;
+               my $extra = $3;
+
+               # some file references are like:
+               # /usr/src/linux/Documentation/DMA-{API,mapping}.txt
+               # For now, ignore them
+               next if ($extra =~ m/^{/);
+
+               # Remove footnotes at the end like:
+               # Documentation/devicetree/dt-object-internal.txt[1]
+               $ref =~ s/(txt|rst)\[\d+]$/$1/;
+
+               # Remove ending ']' without any '['
+               $ref =~ s/\].*// if (!($ref =~ m/\[/));
 
+               # Remove puntuation marks at the end
                $ref =~ s/[\,\.]+$//;
 
                my $fulref = "$prefix$ref";
@@ -63,8 +78,15 @@ while (<IN>) {
                # Check if exists, evaluating wildcards
                next if (grep -e, glob("$ref $fulref"));
 
+               # Accept relative Documentation patches for tools/
+               if ($f =~ m/tools/) {
+                       my $path = $f;
+                       $path =~ s,(.*)/.*,$1,;
+                       next if (grep -e, glob("$path/$ref $path/$fulref"));
+               }
+
                if ($fix) {
-                       if (!($ref =~ m/(devicetree|scripts|Kconfig|Kbuild)/)) {
+                       if (!($ref =~ m/(scripts|Kconfig|Kbuild)/)) {
                                $broken_ref{$ref}++;
                        }
                } else {
@@ -84,10 +106,19 @@ foreach my $ref (keys %broken_ref) {
        # get just the basename
        $new =~ s,.*/,,;
 
-       # Seek for the same name on another place, as it may have been moved
        my $f="";
 
-       $f = qx(find . -iname $new) if ($new);
+       # usual reason for breakage: DT file moved around
+       if ($ref =~ /devicetree/) {
+               my $search = $new;
+               $search =~ s,^.*/,,;
+               $f = qx(find Documentation/devicetree/ -iname "*$search*") if ($search);
+               if (!$f) {
+                       # Manufacturer name may have changed
+                       $search =~ s/^.*,//;
+                       $f = qx(find Documentation/devicetree/ -iname "*$search*") if ($search);
+               }
+       }
 
        # usual reason for breakage: file renamed to .rst
        if (!$f) {
@@ -95,6 +126,17 @@ foreach my $ref (keys %broken_ref) {
                $f=qx(find . -iname $new) if ($new);
        }
 
+       # usual reason for breakage: use dash or underline
+       if (!$f) {
+               $new =~ s/[-_]/[-_]/g;
+               $f=qx(find . -iname $new) if ($new);
+       }
+
+       # Wild guess: seek for the same name on another place
+       if (!$f) {
+               $f = qx(find . -iname $new) if ($new);
+       }
+
        my @find = split /\s+/, $f;
 
        if (!$f) {
index 8f9ecac7f8dea26f2621ba63bcb05dd781af3584..eeaddfe0c0fb9c3999453451de1899db81a9ad84 100644 (file)
@@ -19,7 +19,7 @@
 #include "include/audit.h"
 #include "include/policy.h"
 #include "include/policy_ns.h"
-
+#include "include/secid.h"
 
 const char *const audit_mode_names[] = {
        "normal",
@@ -163,3 +163,91 @@ int aa_audit(int type, struct aa_profile *profile, struct common_audit_data *sa,
 
        return aad(sa)->error;
 }
+
+struct aa_audit_rule {
+       struct aa_label *label;
+};
+
+void aa_audit_rule_free(void *vrule)
+{
+       struct aa_audit_rule *rule = vrule;
+
+       if (rule) {
+               if (!IS_ERR(rule->label))
+                       aa_put_label(rule->label);
+               kfree(rule);
+       }
+}
+
+int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
+{
+       struct aa_audit_rule *rule;
+
+       switch (field) {
+       case AUDIT_SUBJ_ROLE:
+               if (op != Audit_equal && op != Audit_not_equal)
+                       return -EINVAL;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       rule = kzalloc(sizeof(struct aa_audit_rule), GFP_KERNEL);
+
+       if (!rule)
+               return -ENOMEM;
+
+       /* Currently rules are treated as coming from the root ns */
+       rule->label = aa_label_parse(&root_ns->unconfined->label, rulestr,
+                                    GFP_KERNEL, true, false);
+       if (IS_ERR(rule->label)) {
+               aa_audit_rule_free(rule);
+               return PTR_ERR(rule->label);
+       }
+
+       *vrule = rule;
+       return 0;
+}
+
+int aa_audit_rule_known(struct audit_krule *rule)
+{
+       int i;
+
+       for (i = 0; i < rule->field_count; i++) {
+               struct audit_field *f = &rule->fields[i];
+
+               switch (f->type) {
+               case AUDIT_SUBJ_ROLE:
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
+                       struct audit_context *actx)
+{
+       struct aa_audit_rule *rule = vrule;
+       struct aa_label *label;
+       int found = 0;
+
+       label = aa_secid_to_label(sid);
+
+       if (!label)
+               return -ENOENT;
+
+       if (aa_label_is_subset(label, rule->label))
+               found = 1;
+
+       switch (field) {
+       case AUDIT_SUBJ_ROLE:
+               switch (op) {
+               case Audit_equal:
+                       return found;
+               case Audit_not_equal:
+                       return !found;
+               }
+       }
+       return 0;
+}
index 590b7e8cd21c5450b24dfc84ea6b82c39b3c7959..098d546d8253d920737d368fab9966b4d60dcc30 100644 (file)
@@ -839,7 +839,7 @@ static struct aa_label *handle_onexec(struct aa_label *label,
                                                   cond, unsafe));
 
        } else {
-               /* TODO: determine how much we want to losen this */
+               /* TODO: determine how much we want to loosen this */
                error = fn_for_each_in_ns(label, profile,
                                profile_onexec(profile, onexec, stack, bprm,
                                               buffer, cond, unsafe));
index 9c9be9c98c153e52c763dcbf2f4773e5ccfa7eba..b8c8b1066b0a126ad4ac50f343a721cbabcd8748 100644 (file)
@@ -189,4 +189,10 @@ static inline int complain_error(int error)
        return error;
 }
 
+void aa_audit_rule_free(void *vrule);
+int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule);
+int aa_audit_rule_known(struct audit_krule *rule);
+int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
+                       struct audit_context *actx);
+
 #endif /* __AA_AUDIT_H */
index d871e7ff095275e8a23685449945036d016682eb..7ce5fe73ae7f5f641c279d03ad79c3b9f4ab8d0d 100644 (file)
@@ -281,7 +281,7 @@ void __aa_labelset_update_subtree(struct aa_ns *ns);
 
 void aa_label_free(struct aa_label *label);
 void aa_label_kref(struct kref *kref);
-bool aa_label_init(struct aa_label *label, int size);
+bool aa_label_init(struct aa_label *label, int size, gfp_t gfp);
 struct aa_label *aa_label_alloc(int size, struct aa_proxy *proxy, gfp_t gfp);
 
 bool aa_label_is_subset(struct aa_label *set, struct aa_label *sub);
index e042b994f2b8bae575abe142dcdc7c3e2b5828f2..b6380c5f00972702807407cbc1f853192a308333 100644 (file)
@@ -43,10 +43,11 @@ struct aa_buffers {
 
 DECLARE_PER_CPU(struct aa_buffers, aa_buffers);
 
-#define ASSIGN(FN, X, N) ((X) = FN(N))
-#define EVAL1(FN, X) ASSIGN(FN, X, 0) /*X = FN(0)*/
-#define EVAL2(FN, X, Y...) do { ASSIGN(FN, X, 1);  EVAL1(FN, Y); } while (0)
-#define EVAL(FN, X...) CONCATENATE(EVAL, COUNT_ARGS(X))(FN, X)
+#define ASSIGN(FN, A, X, N) ((X) = FN(A, N))
+#define EVAL1(FN, A, X) ASSIGN(FN, A, X, 0) /*X = FN(0)*/
+#define EVAL2(FN, A, X, Y...)  \
+       do { ASSIGN(FN, A, X, 1);  EVAL1(FN, A, Y); } while (0)
+#define EVAL(FN, A, X...) CONCATENATE(EVAL, COUNT_ARGS(X))(FN, A, X)
 
 #define for_each_cpu_buffer(I) for ((I) = 0; (I) < MAX_PATH_BUFFERS; (I)++)
 
@@ -56,26 +57,24 @@ DECLARE_PER_CPU(struct aa_buffers, aa_buffers);
 #define AA_BUG_PREEMPT_ENABLED(X) /* nop */
 #endif
 
-#define __get_buffer(N) ({                                     \
-       struct aa_buffers *__cpu_var; \
+#define __get_buffer(C, N) ({                                          \
        AA_BUG_PREEMPT_ENABLED("__get_buffer without preempt disabled");  \
-       __cpu_var = this_cpu_ptr(&aa_buffers);                  \
-       __cpu_var->buf[(N)]; })
+       (C)->buf[(N)]; })
 
-#define __get_buffers(X...)    EVAL(__get_buffer, X)
+#define __get_buffers(C, X...)    EVAL(__get_buffer, C, X)
 
 #define __put_buffers(X, Y...) ((void)&(X))
 
-#define get_buffers(X...)      \
-do {                           \
-       preempt_disable();      \
-       __get_buffers(X);       \
+#define get_buffers(X...)                                              \
+do {                                                                   \
+       struct aa_buffers *__cpu_var = get_cpu_ptr(&aa_buffers);        \
+       __get_buffers(__cpu_var, X);                                    \
 } while (0)
 
-#define put_buffers(X, Y...)   \
-do {                           \
-       __put_buffers(X, Y);    \
-       preempt_enable();       \
+#define put_buffers(X, Y...)           \
+do {                                   \
+       __put_buffers(X, Y);            \
+       put_cpu_ptr(&aa_buffers);       \
 } while (0)
 
 #endif /* __AA_PATH_H */
index 95ed86a0f1e28c75e7c5394f320ec0ad482f78dd..dee6fa3b6081e1342bfa3e0c4077ea960ca7bfff 100644 (file)
@@ -3,7 +3,7 @@
  *
  * This file contains AppArmor security identifier (secid) definitions
  *
- * Copyright 2009-2010 Canonical Ltd.
+ * Copyright 2009-2018 Canonical Ltd.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
 #ifndef __AA_SECID_H
 #define __AA_SECID_H
 
+#include <linux/slab.h>
 #include <linux/types.h>
 
+struct aa_label;
+
 /* secid value that will not be allocated */
 #define AA_SECID_INVALID 0
-#define AA_SECID_ALLOC AA_SECID_INVALID
 
-u32 aa_alloc_secid(void);
+struct aa_label *aa_secid_to_label(u32 secid);
+int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
+int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
+void apparmor_release_secctx(char *secdata, u32 seclen);
+
+
+int aa_alloc_secid(struct aa_label *label, gfp_t gfp);
 void aa_free_secid(u32 secid);
+void aa_secid_update(u32 secid, struct aa_label *label);
+
+void aa_secids_init(void);
 
 #endif /* __AA_SECID_H */
index 523250e348378d1ef7ddcd80f7e6e64285ef787b..ba11bdf9043aacd26acf7119873c212240e3cb3f 100644 (file)
@@ -128,7 +128,7 @@ static int ns_cmp(struct aa_ns *a, struct aa_ns *b)
 }
 
 /**
- * profile_cmp - profile comparision for set ordering
+ * profile_cmp - profile comparison for set ordering
  * @a: profile to compare (NOT NULL)
  * @b: profile to compare (NOT NULL)
  *
@@ -157,7 +157,7 @@ static int profile_cmp(struct aa_profile *a, struct aa_profile *b)
 }
 
 /**
- * vec_cmp - label comparision for set ordering
+ * vec_cmp - label comparison for set ordering
  * @a: label to compare (NOT NULL)
  * @vec: vector of profiles to compare (NOT NULL)
  * @n: length of @vec
@@ -402,13 +402,12 @@ static void label_free_or_put_new(struct aa_label *label, struct aa_label *new)
                aa_put_label(new);
 }
 
-bool aa_label_init(struct aa_label *label, int size)
+bool aa_label_init(struct aa_label *label, int size, gfp_t gfp)
 {
        AA_BUG(!label);
        AA_BUG(size < 1);
 
-       label->secid = aa_alloc_secid();
-       if (label->secid == AA_SECID_INVALID)
+       if (aa_alloc_secid(label, gfp) < 0)
                return false;
 
        label->size = size;                     /* doesn't include null */
@@ -441,7 +440,7 @@ struct aa_label *aa_label_alloc(int size, struct aa_proxy *proxy, gfp_t gfp)
        if (!new)
                goto fail;
 
-       if (!aa_label_init(new, size))
+       if (!aa_label_init(new, size, gfp))
                goto fail;
 
        if (!proxy) {
@@ -463,7 +462,7 @@ fail:
 
 
 /**
- * label_cmp - label comparision for set ordering
+ * label_cmp - label comparison for set ordering
  * @a: label to compare (NOT NULL)
  * @b: label to compare (NOT NULL)
  *
@@ -2011,7 +2010,7 @@ out:
 
 /**
  * __label_update - insert updated version of @label into labelset
- * @label - the label to update/repace
+ * @label - the label to update/replace
  *
  * Returns: new label that is up to date
  *     else NULL on failure
index 068a9f471f774d57543c6a93d978056070ac9cfb..a7b3f681b80e19aed6b0733ad0edf863b20c0c9b 100644 (file)
@@ -408,7 +408,7 @@ int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target,
  * @request: requested perms
  * @deny: Returns: explicit deny set
  * @sa: initialized audit structure (MAY BE NULL if not auditing)
- * @cb: callback fn for tpye specific fields (MAY BE NULL)
+ * @cb: callback fn for type specific fields (MAY BE NULL)
  *
  * Returns: 0 if permission else error code
  *
index ce2b89e9ad94eb9b5b657a8ccce703894c021e19..74f17376202bd1cf36cafcf849abd06fe36ec35a 100644 (file)
@@ -39,6 +39,7 @@
 #include "include/policy_ns.h"
 #include "include/procattr.h"
 #include "include/mount.h"
+#include "include/secid.h"
 
 /* Flag indicating whether initialization completed */
 int apparmor_initialized;
@@ -116,7 +117,8 @@ static int apparmor_ptrace_access_check(struct task_struct *child,
        tracer = begin_current_label_crit_section();
        tracee = aa_get_task_label(child);
        error = aa_may_ptrace(tracer, tracee,
-                 mode == PTRACE_MODE_READ ? AA_PTRACE_READ : AA_PTRACE_TRACE);
+                       (mode & PTRACE_MODE_READ) ? AA_PTRACE_READ
+                                                 : AA_PTRACE_TRACE);
        aa_put_label(tracee);
        end_current_label_crit_section(tracer);
 
@@ -710,6 +712,13 @@ static void apparmor_bprm_committed_creds(struct linux_binprm *bprm)
        return;
 }
 
+static void apparmor_task_getsecid(struct task_struct *p, u32 *secid)
+{
+       struct aa_label *label = aa_get_task_label(p);
+       *secid = label->secid;
+       aa_put_label(label);
+}
+
 static int apparmor_task_setrlimit(struct task_struct *task,
                unsigned int resource, struct rlimit *new_rlim)
 {
@@ -1186,8 +1195,20 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
 
        LSM_HOOK_INIT(task_free, apparmor_task_free),
        LSM_HOOK_INIT(task_alloc, apparmor_task_alloc),
+       LSM_HOOK_INIT(task_getsecid, apparmor_task_getsecid),
        LSM_HOOK_INIT(task_setrlimit, apparmor_task_setrlimit),
        LSM_HOOK_INIT(task_kill, apparmor_task_kill),
+
+#ifdef CONFIG_AUDIT
+       LSM_HOOK_INIT(audit_rule_init, aa_audit_rule_init),
+       LSM_HOOK_INIT(audit_rule_known, aa_audit_rule_known),
+       LSM_HOOK_INIT(audit_rule_match, aa_audit_rule_match),
+       LSM_HOOK_INIT(audit_rule_free, aa_audit_rule_free),
+#endif
+
+       LSM_HOOK_INIT(secid_to_secctx, apparmor_secid_to_secctx),
+       LSM_HOOK_INIT(secctx_to_secid, apparmor_secctx_to_secid),
+       LSM_HOOK_INIT(release_secctx, apparmor_release_secctx),
 };
 
 /*
@@ -1378,14 +1399,12 @@ static int param_set_audit(const char *val, const struct kernel_param *kp)
        if (apparmor_initialized && !policy_admin_capable(NULL))
                return -EPERM;
 
-       for (i = 0; i < AUDIT_MAX_INDEX; i++) {
-               if (strcmp(val, audit_mode_names[i]) == 0) {
-                       aa_g_audit = i;
-                       return 0;
-               }
-       }
+       i = match_string(audit_mode_names, AUDIT_MAX_INDEX, val);
+       if (i < 0)
+               return -EINVAL;
 
-       return -EINVAL;
+       aa_g_audit = i;
+       return 0;
 }
 
 static int param_get_mode(char *buffer, const struct kernel_param *kp)
@@ -1409,14 +1428,13 @@ static int param_set_mode(const char *val, const struct kernel_param *kp)
        if (apparmor_initialized && !policy_admin_capable(NULL))
                return -EPERM;
 
-       for (i = 0; i < APPARMOR_MODE_NAMES_MAX_INDEX; i++) {
-               if (strcmp(val, aa_profile_mode_names[i]) == 0) {
-                       aa_g_profile_mode = i;
-                       return 0;
-               }
-       }
+       i = match_string(aa_profile_mode_names, APPARMOR_MODE_NAMES_MAX_INDEX,
+                        val);
+       if (i < 0)
+               return -EINVAL;
 
-       return -EINVAL;
+       aa_g_profile_mode = i;
+       return 0;
 }
 
 /*
@@ -1530,6 +1548,8 @@ static int __init apparmor_init(void)
                return 0;
        }
 
+       aa_secids_init();
+
        error = aa_setup_dfa_engine();
        if (error) {
                AA_ERROR("Unable to setup dfa engine\n");
index 280eba082c7bfbb05b0c96d8d4bd7aa3e604a7a8..55f2ee505a019411de885560a5e80f79a23d0e5b 100644 (file)
@@ -472,7 +472,7 @@ unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start,
 
 /**
  * aa_dfa_next - step one character to the next state in the dfa
- * @dfa: the dfa to tranverse (NOT NULL)
+ * @dfa: the dfa to traverse (NOT NULL)
  * @state: the state to start in
  * @c: the input character to transition on
  *
index 6e8c7ac0b33d1e7b678db852dcce3eb183a51ca8..c1da22482bfbb3162f81203062daaae6186d45d2 100644 (file)
@@ -121,7 +121,7 @@ static void audit_cb(struct audit_buffer *ab, void *va)
  * @src_name: src_name of object being mediated (MAYBE_NULL)
  * @type: type of filesystem (MAYBE_NULL)
  * @trans: name of trans (MAYBE NULL)
- * @flags: filesystem idependent mount flags
+ * @flags: filesystem independent mount flags
  * @data: filesystem mount flags
  * @request: permissions requested
  * @perms: the permissions computed for the request (NOT NULL)
index c07493ce237680c7183d93282a310cf4eacbfbde..1590e2de4e841c131ac472fa5e9c312d448b0866 100644 (file)
@@ -268,7 +268,7 @@ struct aa_profile *aa_alloc_profile(const char *hname, struct aa_proxy *proxy,
 
        if (!aa_policy_init(&profile->base, NULL, hname, gfp))
                goto fail;
-       if (!aa_label_init(&profile->label, 1))
+       if (!aa_label_init(&profile->label, 1, gfp))
                goto fail;
 
        /* update being set needed by fs interface */
@@ -1008,6 +1008,9 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label,
                        audit_policy(label, op, ns_name, ent->new->base.hname,
                                     "same as current profile, skipping",
                                     error);
+                       /* break refcount cycle with proxy. */
+                       aa_put_proxy(ent->new->label.proxy);
+                       ent->new->label.proxy = NULL;
                        goto skip;
                }
 
@@ -1085,7 +1088,7 @@ fail:
  * Remove a profile or sub namespace from the current namespace, so that
  * they can not be found anymore and mark them as replaced by unconfined
  *
- * NOTE: removing confinement does not restore rlimits to preconfinemnet values
+ * NOTE: removing confinement does not restore rlimits to preconfinement values
  *
  * Returns: size of data consume else error code if fails
  */
index d022137143b9eb2eb0a846ed00bfbc860e388a3b..95fd26d09757f2c7fb7b39d541e1aa6fdc923a5d 100644 (file)
@@ -124,7 +124,7 @@ int aa_task_setrlimit(struct aa_label *label, struct task_struct *task,
         */
 
        if (label != peer &&
-           !aa_capable(label, CAP_SYS_RESOURCE, SECURITY_CAP_NOAUDIT))
+           aa_capable(label, CAP_SYS_RESOURCE, SECURITY_CAP_NOAUDIT) != 0)
                error = fn_for_each(label, profile,
                                audit_resource(profile, resource,
                                               new_rlim->rlim_max, peer,
index 3a3edbad0b214c8d77560a25e7917f1fef1fe96e..f2f22d00db18893a917006794c5a09e341aae2b0 100644 (file)
@@ -3,7 +3,7 @@
  *
  * This file contains AppArmor security identifier (secid) manipulation fns
  *
- * Copyright 2009-2010 Canonical Ltd.
+ * Copyright 2009-2017 Canonical Ltd.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
  * License.
  *
  *
- * AppArmor allocates a unique secid for every profile loaded.  If a profile
- * is replaced it receives the secid of the profile it is replacing.
- *
- * The secid value of 0 is invalid.
+ * AppArmor allocates a unique secid for every label used. If a label
+ * is replaced it receives the secid of the label it is replacing.
  */
 
-#include <linux/spinlock.h>
 #include <linux/errno.h>
 #include <linux/err.h>
+#include <linux/gfp.h>
+#include <linux/idr.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
 
+#include "include/cred.h"
+#include "include/lib.h"
 #include "include/secid.h"
+#include "include/label.h"
+#include "include/policy_ns.h"
+
+/*
+ * secids - do not pin labels with a refcount. They rely on the label
+ * properly updating/freeing them
+ */
 
-/* global counter from which secids are allocated */
-static u32 global_secid;
+#define AA_FIRST_SECID 1
+
+static DEFINE_IDR(aa_secids);
 static DEFINE_SPINLOCK(secid_lock);
 
-/* TODO FIXME: add secid to profile mapping, and secid recycling */
+/*
+ * TODO: allow policy to reserve a secid range?
+ * TODO: add secid pinning
+ * TODO: use secid_update in label replace
+ */
+
+/**
+ * aa_secid_update - update a secid mapping to a new label
+ * @secid: secid to update
+ * @label: label the secid will now map to
+ */
+void aa_secid_update(u32 secid, struct aa_label *label)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&secid_lock, flags);
+       idr_replace(&aa_secids, label, secid);
+       spin_unlock_irqrestore(&secid_lock, flags);
+}
+
+/**
+ *
+ * see label for inverse aa_label_to_secid
+ */
+struct aa_label *aa_secid_to_label(u32 secid)
+{
+       struct aa_label *label;
+
+       rcu_read_lock();
+       label = idr_find(&aa_secids, secid);
+       rcu_read_unlock();
+
+       return label;
+}
+
+int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
+{
+       /* TODO: cache secctx and ref count so we don't have to recreate */
+       struct aa_label *label = aa_secid_to_label(secid);
+       int len;
+
+       AA_BUG(!secdata);
+       AA_BUG(!seclen);
+
+       if (!label)
+               return -EINVAL;
+
+       if (secdata)
+               len = aa_label_asxprint(secdata, root_ns, label,
+                                       FLAG_SHOW_MODE | FLAG_VIEW_SUBNS |
+                                       FLAG_HIDDEN_UNCONFINED | FLAG_ABS_ROOT,
+                                       GFP_ATOMIC);
+       else
+               len = aa_label_snxprint(NULL, 0, root_ns, label,
+                                       FLAG_SHOW_MODE | FLAG_VIEW_SUBNS |
+                                       FLAG_HIDDEN_UNCONFINED | FLAG_ABS_ROOT);
+       if (len < 0)
+               return -ENOMEM;
+
+       *seclen = len;
+
+       return 0;
+}
+
+int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
+{
+       struct aa_label *label;
+
+       label = aa_label_strn_parse(&root_ns->unconfined->label, secdata,
+                                   seclen, GFP_KERNEL, false, false);
+       if (IS_ERR(label))
+               return PTR_ERR(label);
+       *secid = label->secid;
+
+       return 0;
+}
+
+void apparmor_release_secctx(char *secdata, u32 seclen)
+{
+       kfree(secdata);
+}
 
 /**
  * aa_alloc_secid - allocate a new secid for a profile
+ * @label: the label to allocate a secid for
+ * @gfp: memory allocation flags
+ *
+ * Returns: 0 with @label->secid initialized
+ *          <0 returns error with @label->secid set to AA_SECID_INVALID
  */
-u32 aa_alloc_secid(void)
+int aa_alloc_secid(struct aa_label *label, gfp_t gfp)
 {
-       u32 secid;
+       unsigned long flags;
+       int ret;
+
+       idr_preload(gfp);
+       spin_lock_irqsave(&secid_lock, flags);
+       ret = idr_alloc(&aa_secids, label, AA_FIRST_SECID, 0, GFP_ATOMIC);
+       spin_unlock_irqrestore(&secid_lock, flags);
+       idr_preload_end();
 
-       /*
-        * TODO FIXME: secid recycling - part of profile mapping table
-        */
-       spin_lock(&secid_lock);
-       secid = (++global_secid);
-       spin_unlock(&secid_lock);
-       return secid;
+       if (ret < 0) {
+               label->secid = AA_SECID_INVALID;
+               return ret;
+       }
+
+       AA_BUG(ret == AA_SECID_INVALID);
+       label->secid = ret;
+       return 0;
 }
 
 /**
@@ -51,5 +155,14 @@ u32 aa_alloc_secid(void)
  */
 void aa_free_secid(u32 secid)
 {
-       ;                       /* NOP ATM */
+       unsigned long flags;
+
+       spin_lock_irqsave(&secid_lock, flags);
+       idr_remove(&aa_secids, secid);
+       spin_unlock_irqrestore(&secid_lock, flags);
+}
+
+void aa_secids_init(void)
+{
+       idr_init_base(&aa_secids, AA_FIRST_SECID);
 }
index c65b39bafdfee2e259a5695dee791fa7ae661c0e..cd97929fac663f61250edeae3397e3ab75b5ff49 100644 (file)
@@ -509,7 +509,7 @@ static inline int may_allow_all(struct dev_cgroup *parent)
  * This is one of the three key functions for hierarchy implementation.
  * This function is responsible for re-evaluating all the cgroup's active
  * exceptions due to a parent's exception change.
- * Refer to Documentation/cgroups/devices.txt for more details.
+ * Refer to Documentation/cgroup-v1/devices.txt for more details.
  */
 static void revalidate_active_exceptions(struct dev_cgroup *devcg)
 {
index 9a46dc24ac1040279bedcdab897a7ab40b0eaa1d..2b5ee5fbd652de22a951d7618e6daad3d7cb82f5 100644 (file)
@@ -4728,7 +4728,7 @@ err_af:
 }
 
 /* This supports connect(2) and SCTP connect services such as sctp_connectx(3)
- * and sctp_sendmsg(3) as described in Documentation/security/LSM-sctp.txt
+ * and sctp_sendmsg(3) as described in Documentation/security/LSM-sctp.rst
  */
 static int selinux_socket_connect_helper(struct socket *sock,
                                         struct sockaddr *address, int addrlen)
index 6e937a8146a184a4b8ee6211db0b0f235f5f5425..63b3ef9c83f59f7599207f8b639c68bb6e16fc3b 100644 (file)
@@ -48,7 +48,7 @@ config SND_MIXER_OSS
        depends on SND_OSSEMUL
        help
          To enable OSS mixer API emulation (/dev/mixer*), say Y here
-         and read <file:Documentation/sound/alsa/OSS-Emulation.txt>.
+         and read <file:Documentation/sound/designs/oss-emulation.rst>.
 
          Many programs still use the OSS API, so say Y.
 
@@ -61,7 +61,7 @@ config SND_PCM_OSS
        select SND_PCM
        help
          To enable OSS digital audio (PCM) emulation (/dev/dsp*), say Y
-         here and read <file:Documentation/sound/alsa/OSS-Emulation.txt>.
+         here and read <file:Documentation/sound/designs/oss-emulation.rst>.
 
          Many programs still use the OSS API, so say Y.
 
index 7144cc36e8ae16e4c4b190a75be56cd9a6a39aa6..648a12da44f99be375c365bb0f0d8ba59384d3ea 100644 (file)
@@ -153,7 +153,7 @@ config SND_SERIAL_U16550
        select SND_RAWMIDI
        help
          To include support for MIDI serial port interfaces, say Y here
-         and read <file:Documentation/sound/alsa/serial-u16550.txt>.
+         and read <file:Documentation/sound/cards/serial-u16550.rst>.
          This driver works with serial UARTs 16550 and better.
 
          This driver accesses the serial port hardware directly, so
@@ -223,7 +223,7 @@ config SND_AC97_POWER_SAVE
          the device frequently.  A value of 10 seconds would be a
          good choice for normal operations.
 
-         See Documentation/sound/alsa/powersave.txt for more details.
+         See Documentation/sound/designs/powersave.rst for more details.
 
 config SND_AC97_POWER_SAVE_DEFAULT
        int "Default time-out for AC97 power-save mode"
index d9f3fdb777e42bf2b7b89f5e7948fc1335597a5f..4105d9f653d9042a159ab8ba67f3d5cc6817e57e 100644 (file)
@@ -175,7 +175,7 @@ config SND_BT87X
        help
          If you want to record audio from TV cards based on
          Brooktree Bt878/Bt879 chips, say Y here and read
-         <file:Documentation/sound/alsa/Bt87x.txt>.
+         <file:Documentation/sound/cards/bt87x.rst>.
 
          To compile this driver as a module, choose M here: the module
          will be called snd-bt87x.
@@ -210,7 +210,7 @@ config SND_CMIPCI
        help
          If you want to use soundcards based on C-Media CMI8338, CMI8738,
          CMI8768 or CMI8770 chips, say Y here and read
-         <file:Documentation/sound/alsa/CMIPCI.txt>.
+         <file:Documentation/sound/cards/cmipci.rst>.
 
          To compile this driver as a module, choose M here: the module
          will be called snd-cmipci.
@@ -472,8 +472,8 @@ config SND_EMU10K1
          Audigy and E-mu APS (partially supported) soundcards.
 
          The confusing multitude of mixer controls is documented in
-         <file:Documentation/sound/alsa/SB-Live-mixer.txt> and
-         <file:Documentation/sound/alsa/Audigy-mixer.txt>.
+         <file:Documentation/sound/cards/sb-live-mixer.rst> and
+         <file:Documentation/sound/cards/audigy-mixer.rst>.
 
          To compile this driver as a module, choose M here: the module
          will be called snd-emu10k1.
@@ -735,7 +735,7 @@ config SND_MIXART
        select SND_PCM
        help
          If you want to use Digigram miXart soundcards, say Y here and
-         read <file:Documentation/sound/alsa/MIXART.txt>.
+         read <file:Documentation/sound/cards/mixart.rst>.
 
          To compile this driver as a module, choose M here: the module
          will be called snd-mixart.
index d39458ab251fb0685e28993f2c89b2505dc6174c..69f9b100bd24c12e834378006e5649f6b668aedb 100644 (file)
@@ -1858,7 +1858,9 @@ int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device)
        if (!kctl)
                return -ENOMEM;
        kctl->id.device = device;
-       snd_ctl_add(emu->card, kctl);
+       err = snd_ctl_add(emu->card, kctl);
+       if (err < 0)
+               return err;
 
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024);
 
index 73a67bc3586bcd55e6e0387093fcda8917e6c2e7..e3fb9c61017c6535e3d8fb4cb4f9694bce2e2bb1 100644 (file)
@@ -1068,11 +1068,19 @@ static int snd_fm801_mixer(struct fm801 *chip)
                if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97_sec)) < 0)
                        return err;
        }
-       for (i = 0; i < FM801_CONTROLS; i++)
-               snd_ctl_add(chip->card, snd_ctl_new1(&snd_fm801_controls[i], chip));
+       for (i = 0; i < FM801_CONTROLS; i++) {
+               err = snd_ctl_add(chip->card,
+                       snd_ctl_new1(&snd_fm801_controls[i], chip));
+               if (err < 0)
+                       return err;
+       }
        if (chip->multichannel) {
-               for (i = 0; i < FM801_CONTROLS_MULTI; i++)
-                       snd_ctl_add(chip->card, snd_ctl_new1(&snd_fm801_controls_multi[i], chip));
+               for (i = 0; i < FM801_CONTROLS_MULTI; i++) {
+                       err = snd_ctl_add(chip->card,
+                               snd_ctl_new1(&snd_fm801_controls_multi[i], chip));
+                       if (err < 0)
+                               return err;
+               }
        }
        return 0;
 }
index dbf9910c52693bfaaf0017bb31aeab240d2152d4..e7fcfc3b8885fb7470dc1b10a49f305f7bca323d 100644 (file)
@@ -958,6 +958,8 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
        SND_PCI_QUIRK(0x103c, 0x8079, "HP EliteBook 840 G3", CXT_FIXUP_HP_DOCK),
        SND_PCI_QUIRK(0x103c, 0x807C, "HP EliteBook 820 G3", CXT_FIXUP_HP_DOCK),
        SND_PCI_QUIRK(0x103c, 0x80FD, "HP ProBook 640 G2", CXT_FIXUP_HP_DOCK),
+       SND_PCI_QUIRK(0x103c, 0x83b3, "HP EliteBook 830 G5", CXT_FIXUP_HP_DOCK),
+       SND_PCI_QUIRK(0x103c, 0x83d3, "HP ProBook 640 G4", CXT_FIXUP_HP_DOCK),
        SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE),
        SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC),
        SND_PCI_QUIRK(0x103c, 0x814f, "HP ZBook 15u G3", CXT_FIXUP_MUTE_LED_GPIO),
index d64dcb9a4c9957ed8d473eb1cb92e9af93a5e4f4..e9bd33ea538f239891c031a1a81e075a35c75043 100644 (file)
@@ -793,6 +793,9 @@ static inline void alc_shutup(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
 
+       if (!snd_hda_get_bool_hint(codec, "shutup"))
+               return; /* disabled explicitly by hints */
+
        if (spec && spec->shutup)
                spec->shutup(codec);
        else
index 9655b08a1c52f194c7b627ba32732dab604f5929..6c85f13ab23f17f7ef4031f5f73797fb383584a7 100644 (file)
@@ -1016,6 +1016,10 @@ static int snd_lx6464es_create(struct snd_card *card,
 
        /* dsp port */
        chip->port_dsp_bar = pci_ioremap_bar(pci, 2);
+       if (!chip->port_dsp_bar) {
+               dev_err(card->dev, "cannot remap PCI memory region\n");
+               goto remap_pci_failed;
+       }
 
        err = request_threaded_irq(pci->irq, lx_interrupt, lx_threaded_irq,
                                   IRQF_SHARED, KBUILD_MODNAME, chip);
@@ -1055,6 +1059,9 @@ device_new_failed:
        free_irq(pci->irq, chip);
 
 request_irq_failed:
+       iounmap(chip->port_dsp_bar);
+
+remap_pci_failed:
        pci_release_regions(pci);
 
 request_regions_failed:
index a8abb15e3c3ab0d3bce8b7c984d15d826b8699bd..7fbdb703bfcd58ef5df9401a3c6c6ab4a0d8d454 100644 (file)
@@ -1188,6 +1188,7 @@ SONICVIBES_SINGLE("Joystick Speed", 0, SV_IREG_GAME_PORT, 1, 15, 0);
 static int snd_sonicvibes_create_gameport(struct sonicvibes *sonic)
 {
        struct gameport *gp;
+       int err;
 
        sonic->gameport = gp = gameport_allocate_port();
        if (!gp) {
@@ -1203,7 +1204,10 @@ static int snd_sonicvibes_create_gameport(struct sonicvibes *sonic)
 
        gameport_register_port(gp);
 
-       snd_ctl_add(sonic->card, snd_ctl_new1(&snd_sonicvibes_game_control, sonic));
+       err = snd_ctl_add(sonic->card,
+               snd_ctl_new1(&snd_sonicvibes_game_control, sonic));
+       if (err < 0)
+               return err;
 
        return 0;
 }
@@ -1515,7 +1519,11 @@ static int snd_sonic_probe(struct pci_dev *pci,
                return err;
        }
 
-       snd_sonicvibes_create_gameport(sonic);
+       err = snd_sonicvibes_create_gameport(sonic);
+       if (err < 0) {
+               snd_card_free(card);
+               return err;
+       }
 
        if ((err = snd_card_register(card)) < 0) {
                snd_card_free(card);
index 1406292d50ece6d9b0da7dba51e7252176ac61d1..9b41b7dda84fafff418d357590efadd5c2763ca7 100644 (file)
@@ -32,6 +32,7 @@ struct audioformat {
        struct snd_pcm_chmap_elem *chmap; /* (optional) channel map */
        bool dsd_dop;                   /* add DOP headers in case of DSD samples */
        bool dsd_bitrev;                /* reverse the bits of each DSD sample */
+       bool dsd_raw;                   /* altsetting is raw DSD */
 };
 
 struct snd_usb_substream;
index 1f7a74a77ea34f6c7f86dc5259e716d5bd09e8f7..fd13ac11b13674e1c06500f7ab3eef151b1226e2 100644 (file)
@@ -64,8 +64,11 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
                sample_width = fmt->bBitResolution;
                sample_bytes = fmt->bSubslotSize;
 
-               if (format & UAC2_FORMAT_TYPE_I_RAW_DATA)
+               if (format & UAC2_FORMAT_TYPE_I_RAW_DATA) {
                        pcm_formats |= SNDRV_PCM_FMTBIT_SPECIAL;
+                       /* flag potentially raw DSD capable altsettings */
+                       fp->dsd_raw = true;
+               }
 
                format <<= 1;
                break;
index 8c3568d8d03bab132e5399fccd7cba184c81ed2a..ca963e94ec03ca261fe271577c0568b7832c84fb 100644 (file)
@@ -1653,11 +1653,11 @@ static void build_feature_ctl_badd(struct usb_mixer_interface *mixer,
                        NULL, NULL, unitid, 0, 0);
 }
 
-static void get_connector_control_name(struct mixer_build *state,
+static void get_connector_control_name(struct usb_mixer_interface *mixer,
                                       struct usb_audio_term *term,
                                       bool is_input, char *name, int name_size)
 {
-       int name_len = get_term_name(state->chip, term, name, name_size, 0);
+       int name_len = get_term_name(mixer->chip, term, name, name_size, 0);
 
        if (name_len == 0)
                strlcpy(name, "Unknown", name_size);
@@ -1674,7 +1674,7 @@ static void get_connector_control_name(struct mixer_build *state,
 }
 
 /* Build a mixer control for a UAC connector control (jack-detect) */
-static void build_connector_control(struct mixer_build *state,
+static void build_connector_control(struct usb_mixer_interface *mixer,
                                    struct usb_audio_term *term, bool is_input)
 {
        struct snd_kcontrol *kctl;
@@ -1683,7 +1683,7 @@ static void build_connector_control(struct mixer_build *state,
        cval = kzalloc(sizeof(*cval), GFP_KERNEL);
        if (!cval)
                return;
-       snd_usb_mixer_elem_init_std(&cval->head, state->mixer, term->id);
+       snd_usb_mixer_elem_init_std(&cval->head, mixer, term->id);
        /*
         * UAC2: The first byte from reading the UAC2_TE_CONNECTOR control returns the
         * number of channels connected.
@@ -1694,7 +1694,7 @@ static void build_connector_control(struct mixer_build *state,
         * This boolean ctl will simply report if any channels are connected
         * or not.
         */
-       if (state->mixer->protocol == UAC_VERSION_2)
+       if (mixer->protocol == UAC_VERSION_2)
                cval->control = UAC2_TE_CONNECTOR;
        else /* UAC_VERSION_3 */
                cval->control = UAC3_TE_INSERTION;
@@ -1705,11 +1705,11 @@ static void build_connector_control(struct mixer_build *state,
        cval->max = 1;
        kctl = snd_ctl_new1(&usb_connector_ctl_ro, cval);
        if (!kctl) {
-               usb_audio_err(state->chip, "cannot malloc kcontrol\n");
+               usb_audio_err(mixer->chip, "cannot malloc kcontrol\n");
                kfree(cval);
                return;
        }
-       get_connector_control_name(state, term, is_input, kctl->id.name,
+       get_connector_control_name(mixer, term, is_input, kctl->id.name,
                                   sizeof(kctl->id.name));
        kctl->private_free = snd_usb_mixer_elem_free;
        snd_usb_mixer_add_control(&cval->head, kctl);
@@ -2042,7 +2042,7 @@ static int parse_audio_input_terminal(struct mixer_build *state, int unitid,
 
        /* Check for jack detection. */
        if (uac_v2v3_control_is_readable(bmctls, control))
-               build_connector_control(state, &iterm, true);
+               build_connector_control(state->mixer, &iterm, true);
 
        return 0;
 }
@@ -2918,6 +2918,23 @@ static int snd_usb_mixer_controls_badd(struct usb_mixer_interface *mixer,
                                       UAC3_BADD_FU_ID7, map->map);
        }
 
+       /* Insertion Control */
+       if (f->subclass == UAC3_FUNCTION_SUBCLASS_HEADSET_ADAPTER) {
+               struct usb_audio_term iterm, oterm;
+
+               /* Input Term - Insertion control */
+               memset(&iterm, 0, sizeof(iterm));
+               iterm.id = UAC3_BADD_IT_ID4;
+               iterm.type = UAC_BIDIR_TERMINAL_HEADSET;
+               build_connector_control(mixer, &iterm, true);
+
+               /* Output Term - Insertion control */
+               memset(&oterm, 0, sizeof(oterm));
+               oterm.id = UAC3_BADD_OT_ID3;
+               oterm.type = UAC_BIDIR_TERMINAL_HEADSET;
+               build_connector_control(mixer, &oterm, false);
+       }
+
        return 0;
 }
 
@@ -2990,7 +3007,7 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
 
                        if (uac_v2v3_control_is_readable(le16_to_cpu(desc->bmControls),
                                                         UAC2_TE_CONNECTOR)) {
-                               build_connector_control(&state, &state.oterm,
+                               build_connector_control(state.mixer, &state.oterm,
                                                        false);
                        }
                } else {  /* UAC_VERSION_3 */
@@ -3017,7 +3034,7 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
 
                        if (uac_v2v3_control_is_readable(le32_to_cpu(desc->bmControls),
                                                         UAC3_TE_INSERTION)) {
-                               build_connector_control(&state, &state.oterm,
+                               build_connector_control(state.mixer, &state.oterm,
                                                        false);
                        }
                }
@@ -3321,10 +3338,12 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
                err = snd_usb_mixer_controls(mixer);
                if (err < 0)
                        goto _error;
-               err = snd_usb_mixer_status_create(mixer);
-               if (err < 0)
-                       goto _error;
        }
+
+       err = snd_usb_mixer_status_create(mixer);
+       if (err < 0)
+               goto _error;
+
        err = create_keep_iface_ctl(mixer);
        if (err < 0)
                goto _error;
index 0e37e358ca97e30196477c9ec60b13515c2d92a2..8aac48f9c32272b194e5bdebee7f23272c9ce828 100644 (file)
@@ -3277,6 +3277,10 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
        }
 },
 
+/* disabled due to regression for other devices;
+ * see https://bugzilla.kernel.org/show_bug.cgi?id=199905
+ */
+#if 0
 {
        /*
         * Nura's first gen headphones use Cambridge Silicon Radio's vendor
@@ -3324,6 +3328,7 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
                }
        }
 },
+#endif /* disabled */
 
 {
        /*
index f4b69173682ccddc8c5f3cfb4d5931c52bc11116..02b6cc02767f88d11af8c5cff60cbd48cf1d8726 100644 (file)
@@ -1362,16 +1362,12 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
        case USB_ID(0x1511, 0x0037): /* AURALiC VEGA */
        case USB_ID(0x20b1, 0x0002): /* Wyred 4 Sound DAC-2 DSD */
        case USB_ID(0x20b1, 0x2004): /* Matrix Audio X-SPDIF 2 */
-       case USB_ID(0x20b1, 0x3008): /* iFi Audio micro/nano iDSD */
        case USB_ID(0x20b1, 0x2008): /* Matrix Audio X-Sabre */
        case USB_ID(0x20b1, 0x300a): /* Matrix Audio Mini-i Pro */
        case USB_ID(0x22d9, 0x0416): /* OPPO HA-1 */
        case USB_ID(0x22d9, 0x0436): /* OPPO Sonica */
        case USB_ID(0x22d9, 0x0461): /* OPPO UDP-205 */
        case USB_ID(0x2522, 0x0012): /* LH Labs VI DAC Infinity */
-       case USB_ID(0x25ce, 0x001f): /* Mytek Brooklyn DAC */
-       case USB_ID(0x25ce, 0x0021): /* Mytek Manhattan DAC */
-       case USB_ID(0x25ce, 0x8025): /* Mytek Brooklyn DAC+ */
        case USB_ID(0x2772, 0x0230): /* Pro-Ject Pre Box S2 Digital */
                if (fp->altsetting == 2)
                        return SNDRV_PCM_FMTBIT_DSD_U32_BE;
@@ -1389,7 +1385,6 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
        case USB_ID(0x20b1, 0x3021): /* Eastern El. MiniMax Tube DAC Supreme */
        case USB_ID(0x20b1, 0x3023): /* Aune X1S 32BIT/384 DSD DAC */
        case USB_ID(0x20b1, 0x302d): /* Unison Research Unico CD Due */
-       case USB_ID(0x20b1, 0x3036): /* Holo Springs Level 3 R2R DAC */
        case USB_ID(0x20b1, 0x307b): /* CH Precision C1 DAC */
        case USB_ID(0x20b1, 0x3086): /* Singxer F-1 converter board */
        case USB_ID(0x22d9, 0x0426): /* OPPO HA-2 */
@@ -1443,6 +1438,20 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
                        return SNDRV_PCM_FMTBIT_DSD_U32_BE;
        }
 
+       /* Mostly generic method to detect many DSD-capable implementations -
+        * from XMOS/Thesycon
+        */
+       switch (USB_ID_VENDOR(chip->usb_id)) {
+       case 0x20b1:  /* XMOS based devices */
+       case 0x25ce:  /* Mytek devices */
+               if (fp->dsd_raw)
+                       return SNDRV_PCM_FMTBIT_DSD_U32_BE;
+               break;
+       default:
+               break;
+
+       }
+
        return 0;
 }
 
index db9f15f5db047e643780ce23a0d33f9cc599ddf4..c0d7ea0bf5b62438ca8184551b64d5d29ad7951b 100644 (file)
@@ -170,7 +170,7 @@ struct prctl_mm_map {
  * asking selinux for a specific new context (e.g. with runcon) will result
  * in execve returning -EPERM.
  *
- * See Documentation/prctl/no_new_privs.txt for more details.
+ * See Documentation/userspace-api/no_new_privs.rst for more details.
  */
 #define PR_SET_NO_NEW_PRIVS    38
 #define PR_GET_NO_NEW_PRIVS    39
index 6a12bbf39f7ba189325374f940893af82ba62cee..7aba8243a0e7cbd3fa4726910db27bcaa3be6d1a 100644 (file)
@@ -201,7 +201,7 @@ static void mem_toupper(char *f, size_t len)
 
 /*
  * Check for "NAME_PATH" environment variable to override fs location (for
- * testing). This matches the recommendation in Documentation/sysfs-rules.txt
+ * testing). This matches the recommendation in Documentation/admin-guide/sysfs-rules.rst
  * for SYSFS_PATH.
  */
 static bool fs__env_override(struct fs *fs)
index 29347756b0afbe9767fca0ac3ab3c5c897acbeed..77e4891e17b0aa9ef2492d70fe77209a7d28439a 100644 (file)
@@ -61,7 +61,7 @@ check_pos(struct bpf_insn_pos *pos)
 
 /*
  * Convert type string (u8/u16/u32/u64/s8/s16/s32/s64 ..., see
- * Documentation/trace/kprobetrace.txt) to size field of BPF_LDX_MEM
+ * Documentation/trace/kprobetrace.rst) to size field of BPF_LDX_MEM
  * instruction (BPF_{B,H,W,DW}).
  */
 static int
index 4f80ad7d72755b308bdc4d963f620a9548dcdbb3..f8fcb06fd68b3b45cce94694fc4b8c1982d03f6a 100644 (file)
@@ -105,7 +105,7 @@ override-dev-timeline-functions: true
 #       example: [color=#CC00CC]
 #
 #   arglist: A list of arguments from registers/stack addresses. See URL:
-#            https://www.kernel.org/doc/Documentation/trace/kprobetrace.txt
+#            https://www.kernel.org/doc/Documentation/trace/kprobetrace.rst
 #
 #       example: cpu=%di:s32
 #
@@ -170,7 +170,7 @@ pm_restore_console:
 #       example: [color=#CC00CC]
 #
 #   arglist: A list of arguments from registers/stack addresses. See URL:
-#            https://www.kernel.org/doc/Documentation/trace/kprobetrace.txt
+#            https://www.kernel.org/doc/Documentation/trace/kprobetrace.rst
 #
 #       example: port=+36(%di):s32
 #
index 607ed8729c06d107fa1fa7454c3efa00abfcff10..7a6214e9ae58d4432668394bf4762a0e2cb5c669 100644 (file)
@@ -16,9 +16,7 @@ LDLIBS += -lcap -lelf -lrt -lpthread
 TEST_CUSTOM_PROGS = $(OUTPUT)/urandom_read
 all: $(TEST_CUSTOM_PROGS)
 
-$(TEST_CUSTOM_PROGS): urandom_read
-
-urandom_read: urandom_read.c
+$(TEST_CUSTOM_PROGS): $(OUTPUT)/%: %.c
        $(CC) -o $(TEST_CUSTOM_PROGS) -static $< -Wl,--build-id
 
 # Order correspond to 'make run_tests' order
index b69bdeb4b9febdb9b6446e56138cbebcfa791914..1e9e3c4705611792f2423cad1682c494b9332bc5 100644 (file)
@@ -35,7 +35,7 @@ out:
        return len;
 }
 
-static ssize_t write_text(const char *path, char *buf, size_t len)
+static ssize_t write_text(const char *path, char *buf, ssize_t len)
 {
        int fd;
 
@@ -140,7 +140,7 @@ long cg_read_key_long(const char *cgroup, const char *control, const char *key)
 int cg_write(const char *cgroup, const char *control, char *buf)
 {
        char path[PATH_MAX];
-       size_t len = strlen(buf);
+       ssize_t len = strlen(buf);
 
        snprintf(path, sizeof(path), "%s/%s", cgroup, control);
 
index 5ba73035e1d95ad45788610668950084844d1861..a0002563e9eeecc8f6b97d0a95ed90309cbd9a8c 100644 (file)
@@ -24,6 +24,14 @@ arm*)
   ARG2=%r1
   OFFS=4
 ;;
+ppc64*)
+  ARG2=%r4
+  OFFS=8
+;;
+ppc*)
+  ARG2=%r4
+  OFFS=4
+;;
 *)
   echo "Please implement other architecture here"
   exit_untested
index 231bcd2c4eb59e9d3528be1e181650424fe13130..d026ff4e562f3a49f0f5cca7fa39a6dcfa112af1 100644 (file)
@@ -34,6 +34,13 @@ arm*)
   GOODREG=%r0
   BADREG=%ax
 ;;
+ppc*)
+  GOODREG=%r3
+  BADREG=%msr
+;;
+*)
+  echo "Please implement other architecture here"
+  exit_untested
 esac
 
 test_goodarg() # Good-args
index de97e4ff705cd1212840f01e975003b6bb99de84..637ea0219617f3beb9a69016e5b613bf173f5ada 100644 (file)
         "matchPattern": "action order [0-9]*: ife encode action pass.*type 0xED3E.*use tcindex 65535.*index 1",
         "matchCount": "1",
         "teardown": [
-            "$TC actions flush action skbedit"
+            "$TC actions flush action ife"
         ]
     },
     {