Merge tags 'ib-mfd-clk-gpio-regulator-rtc-v5.13', 'ib-mfd-extcon-v5.13', 'ib-mfd...
authorLee Jones <lee.jones@linaro.org>
Wed, 14 Apr 2021 14:59:22 +0000 (15:59 +0100)
committerLee Jones <lee.jones@linaro.org>
Wed, 14 Apr 2021 14:59:22 +0000 (15:59 +0100)
Immutable branch between MFD, Clock, GPIO, Regulator and RTC due for the v5.13 merge window

Immutable branch between MFD and Extcon due for the v5.13 merge window

Immutable branch between MFD and Input due for the v5.13 merge window

Immutable branch between MFD and Platform/x86 due for the v5.13 merge window

Immutable branch between MFD and Power due for the v5.13 merge window

Immutable branch between MFD, PWM and RTC due for the v5.13 merge window

1108 files changed:
Documentation/ABI/testing/sysfs-fs-xfs
Documentation/devicetree/bindings/input/input.yaml
Documentation/devicetree/bindings/interrupt-controller/ingenic,intc.yaml
Documentation/devicetree/bindings/mfd/actions,atc260x.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/rohm,bd71828-pmic.yaml
Documentation/devicetree/bindings/regulator/rohm,bd71815-regulator.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/fsl,spdif.yaml
Documentation/gpu/todo.rst
Documentation/networking/bonding.rst
Documentation/networking/netdev-FAQ.rst
Documentation/process/stable-kernel-rules.rst
Documentation/process/submitting-patches.rst
Documentation/virt/kvm/api.rst
MAINTAINERS
Makefile
arch/Kconfig
arch/arm/Kconfig
arch/arm/xen/p2m.c
arch/arm64/Kconfig
arch/arm64/include/asm/kvm_asm.h
arch/arm64/include/asm/kvm_hyp.h
arch/arm64/include/asm/memory.h
arch/arm64/include/asm/mmu_context.h
arch/arm64/include/asm/pgtable-prot.h
arch/arm64/include/asm/pgtable.h
arch/arm64/include/asm/sysreg.h
arch/arm64/kernel/head.S
arch/arm64/kernel/idreg-override.c
arch/arm64/kernel/image-vars.h
arch/arm64/kernel/perf_event.c
arch/arm64/kvm/arm.c
arch/arm64/kvm/hyp/entry.S
arch/arm64/kvm/hyp/include/hyp/switch.h
arch/arm64/kvm/hyp/nvhe/debug-sr.c
arch/arm64/kvm/hyp/nvhe/host.S
arch/arm64/kvm/hyp/nvhe/hyp-main.c
arch/arm64/kvm/hyp/nvhe/switch.c
arch/arm64/kvm/hyp/nvhe/tlb.c
arch/arm64/kvm/hyp/pgtable.c
arch/arm64/kvm/hyp/vgic-v3-sr.c
arch/arm64/kvm/hyp/vhe/tlb.c
arch/arm64/kvm/mmu.c
arch/arm64/kvm/perf.c
arch/arm64/kvm/pmu-emul.c
arch/arm64/kvm/reset.c
arch/arm64/kvm/vgic/vgic-v3.c
arch/arm64/mm/init.c
arch/arm64/mm/mmu.c
arch/csky/kernel/probes/ftrace.c
arch/ia64/include/asm/syscall.h
arch/ia64/kernel/ptrace.c
arch/m68k/include/asm/page_mm.h
arch/m68k/include/asm/page_no.h
arch/mips/boot/compressed/decompress.c
arch/mips/crypto/Makefile
arch/mips/include/asm/traps.h
arch/mips/kernel/cpu-probe.c
arch/mips/kernel/cpu-r3k-probe.c
arch/mips/kernel/traps.c
arch/mips/kernel/vmlinux.lds.S
arch/parisc/Kconfig
arch/parisc/kernel/ptrace.c
arch/powerpc/include/asm/code-patching.h
arch/powerpc/include/asm/cpu_has_feature.h
arch/powerpc/include/asm/dcr-native.h
arch/powerpc/include/asm/interrupt.h
arch/powerpc/include/asm/mmu.h
arch/powerpc/include/asm/ptrace.h
arch/powerpc/include/asm/switch_to.h
arch/powerpc/include/asm/vio.h
arch/powerpc/kernel/exceptions-64s.S
arch/powerpc/kernel/head_book3s_32.S
arch/powerpc/kernel/interrupt.c
arch/powerpc/kernel/traps.c
arch/powerpc/kernel/vdso32/gettimeofday.S
arch/powerpc/lib/sstep.c
arch/powerpc/perf/core-book3s.c
arch/powerpc/platforms/pseries/msi.c
arch/powerpc/platforms/pseries/vio.c
arch/riscv/Kconfig
arch/riscv/Kconfig.socs
arch/riscv/include/asm/asm-prototypes.h
arch/riscv/include/asm/irq.h
arch/riscv/include/asm/processor.h
arch/riscv/include/asm/ptrace.h
arch/riscv/include/asm/sbi.h
arch/riscv/include/asm/timex.h
arch/riscv/kernel/Makefile
arch/riscv/kernel/probes/ftrace.c
arch/riscv/kernel/probes/kprobes.c
arch/riscv/kernel/process.c
arch/riscv/kernel/sbi.c
arch/riscv/kernel/setup.c
arch/riscv/kernel/time.c
arch/riscv/kernel/traps.c
arch/riscv/mm/kasan_init.c
arch/s390/configs/debug_defconfig
arch/s390/configs/defconfig
arch/s390/configs/zfcpdump_defconfig
arch/s390/include/asm/idle.h
arch/s390/include/asm/pci.h
arch/s390/include/asm/timex.h
arch/s390/include/uapi/asm/hwctrset.h [new file with mode: 0644]
arch/s390/include/uapi/asm/perf_cpum_cf_diag.h [deleted file]
arch/s390/kernel/idle.c
arch/s390/kernel/perf_cpum_cf.c
arch/s390/kernel/perf_cpum_cf_diag.c
arch/s390/kernel/time.c
arch/s390/kernel/topology.c
arch/s390/kernel/vtime.c
arch/s390/kvm/interrupt.c
arch/s390/pci/pci.c
arch/s390/pci/pci_event.c
arch/sparc/configs/sparc64_defconfig
arch/sparc/include/asm/elf_64.h
arch/sparc/include/asm/extable.h [new file with mode: 0644]
arch/sparc/include/asm/extable_64.h [deleted file]
arch/sparc/include/asm/processor_32.h
arch/sparc/include/asm/thread_info_64.h
arch/sparc/include/asm/uaccess.h
arch/sparc/include/asm/uaccess_32.h
arch/sparc/include/asm/uaccess_64.h
arch/sparc/kernel/head_32.S
arch/sparc/kernel/head_64.S
arch/sparc/kernel/process_32.c
arch/sparc/kernel/setup_32.c
arch/sparc/kernel/setup_64.c
arch/sparc/kernel/traps_64.c
arch/sparc/kernel/unaligned_32.c
arch/sparc/lib/checksum_32.S
arch/sparc/lib/copy_user.S
arch/sparc/lib/memset.S
arch/sparc/mm/Makefile
arch/sparc/mm/extable.c [deleted file]
arch/sparc/mm/fault_32.c
arch/sparc/mm/mm_32.h
arch/x86/entry/common.c
arch/x86/entry/entry_64_compat.S
arch/x86/events/core.c
arch/x86/events/intel/core.c
arch/x86/events/intel/ds.c
arch/x86/include/asm/insn-eval.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/proto.h
arch/x86/include/asm/ptrace.h
arch/x86/include/asm/smap.h
arch/x86/include/asm/thread_info.h
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/kprobes/ftrace.c
arch/x86/kernel/kvm.c
arch/x86/kernel/kvmclock.c
arch/x86/kernel/sev-es.c
arch/x86/kernel/signal.c
arch/x86/kernel/traps.c
arch/x86/kernel/unwind_orc.c
arch/x86/kvm/hyperv.c
arch/x86/kvm/hyperv.h
arch/x86/kvm/lapic.c
arch/x86/kvm/mmu/mmu_internal.h
arch/x86/kvm/mmu/tdp_iter.c
arch/x86/kvm/mmu/tdp_iter.h
arch/x86/kvm/mmu/tdp_mmu.c
arch/x86/kvm/svm/svm.c
arch/x86/kvm/vmx/vmx.c
arch/x86/kvm/x86.c
arch/x86/lib/insn-eval.c
arch/x86/net/bpf_jit_comp.c
arch/x86/platform/iris/iris.c
arch/x86/xen/p2m.c
block/bio.c
block/blk-cgroup-rwstat.c
block/blk-crypto-fallback.c
block/blk-lib.c
block/blk-map.c
block/blk-zoned.c
block/bounce.c
block/genhd.c
crypto/Kconfig
drivers/atm/eni.c
drivers/atm/fore200e.c
drivers/atm/idt77105.c
drivers/atm/lanai.c
drivers/atm/uPD98402.c
drivers/base/power/runtime.c
drivers/base/swnode.c
drivers/block/drbd/drbd_int.h
drivers/block/floppy.c
drivers/block/rsxx/core.c
drivers/block/umem.c
drivers/block/zram/zram_drv.c
drivers/bluetooth/btrsi.c
drivers/char/applicom.c
drivers/char/hw_random/pseries-rng.c
drivers/char/toshiba.c
drivers/char/tpm/tpm_ibmvtpm.c
drivers/clk/clk-bd718x7.c
drivers/counter/stm32-timer-cnt.c
drivers/cpufreq/cpufreq-dt-platdev.c
drivers/cpufreq/qcom-cpufreq-hw.c
drivers/crypto/nx/nx-842-pseries.c
drivers/crypto/nx/nx.c
drivers/extcon/Kconfig
drivers/extcon/Makefile
drivers/extcon/extcon-arizona.c [deleted file]
drivers/firmware/efi/efi.c
drivers/firmware/efi/libstub/arm64-stub.c
drivers/firmware/efi/libstub/efi-stub.c
drivers/firmware/efi/vars.c
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-bd71815.c [new file with mode: 0644]
drivers/gpio/gpio-pca953x.c
drivers/gpio/gpiolib-acpi.c
drivers/gpio/gpiolib.c
drivers/gpu/drm/Kconfig
drivers/gpu/drm/amd/amdgpu/amdgpu.h
drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/dc/core/dc_link.c
drivers/gpu/drm/amd/display/dc/dc.h
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_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hubp.c
drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c
drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hubp.c
drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c
drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c
drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h
drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c
drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c
drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c
drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/drm_gem_shmem_helper.c
drivers/gpu/drm/drm_ioc32.c
drivers/gpu/drm/i915/gt/intel_engine_cs.c
drivers/gpu/drm/i915/i915_cmd_parser.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_perf.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/meson/meson_drv.c
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/omapdrm/dss/dsi.c
drivers/gpu/drm/qxl/qxl_display.c
drivers/gpu/drm/qxl/qxl_release.c
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_gem.c
drivers/gpu/drm/radeon/radeon_prime.c
drivers/gpu/drm/tiny/gm12u320.c
drivers/gpu/drm/ttm/ttm_bo.c
drivers/gpu/drm/ttm/ttm_pool.c
drivers/gpu/drm/udl/udl_drv.c
drivers/gpu/drm/udl/udl_drv.h
drivers/gpu/drm/udl/udl_main.c
drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c
drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c
drivers/iio/adc/Kconfig
drivers/iio/adc/ab8500-gpadc.c
drivers/iio/adc/ad7949.c
drivers/iio/adc/qcom-spmi-vadc.c
drivers/iio/gyro/mpu3050-core.c
drivers/iio/humidity/hid-sensor-humidity.c
drivers/iio/imu/adis16400.c
drivers/iio/light/hid-sensor-prox.c
drivers/iio/temperature/hid-sensor-temperature.c
drivers/input/joydev.c
drivers/input/misc/Kconfig
drivers/input/misc/Makefile
drivers/input/misc/atc260x-onkey.c [new file with mode: 0644]
drivers/iommu/amd/init.c
drivers/iommu/tegra-smmu.c
drivers/irqchip/Kconfig
drivers/irqchip/irq-ingenic-tcu.c
drivers/irqchip/irq-ingenic.c
drivers/leds/trigger/ledtrig-tty.c
drivers/md/bcache/super.c
drivers/md/dm-crypt.c
drivers/md/dm-writecache.c
drivers/md/raid5-cache.c
drivers/md/raid5-ppl.c
drivers/media/firewire/firedtv-fw.c
drivers/media/pci/cx18/cx18-alsa-main.c
drivers/media/pci/cx18/cx18-driver.c
drivers/media/pci/cx25821/cx25821-alsa.c
drivers/media/pci/cx88/cx88-alsa.c
drivers/media/pci/ivtv/ivtv-alsa-main.c
drivers/media/pci/ivtv/ivtv-driver.c
drivers/media/pci/sta2x11/sta2x11_vip.c
drivers/media/platform/atmel/atmel-isi.c
drivers/media/platform/atmel/atmel-sama5d2-isc.c
drivers/media/platform/marvell-ccic/cafe-driver.c
drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
drivers/media/platform/stm32/stm32-dcmi.c
drivers/media/platform/vsp1/vsp1_drm.c
drivers/media/rc/Makefile
drivers/media/rc/keymaps/Makefile
drivers/media/rc/keymaps/rc-cec.c
drivers/media/rc/rc-main.c
drivers/media/usb/cpia2/cpia2_v4l.c
drivers/media/usb/tm6000/tm6000-alsa.c
drivers/media/usb/tm6000/tm6000-dvb.c
drivers/media/usb/usbtv/usbtv-audio.c
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/ab8500-core.c
drivers/mfd/arizona-core.c
drivers/mfd/atc260x-core.c [new file with mode: 0644]
drivers/mfd/atc260x-i2c.c [new file with mode: 0644]
drivers/mfd/intel_pmt.c
drivers/mfd/rohm-bd71828.c
drivers/mfd/rohm-bd718x7.c
drivers/misc/fastrpc.c
drivers/misc/habanalabs/common/debugfs.c
drivers/misc/habanalabs/common/device.c
drivers/misc/habanalabs/common/habanalabs.h
drivers/misc/habanalabs/common/habanalabs_ioctl.c
drivers/misc/habanalabs/common/irq.c
drivers/misc/habanalabs/common/mmu/mmu.c
drivers/misc/ibmvmc.c
drivers/misc/pvpanic.c
drivers/mmc/core/bus.c
drivers/mmc/core/mmc.c
drivers/mmc/host/mmci.c
drivers/mtd/maps/sun_uflash.c
drivers/net/Kconfig
drivers/net/bonding/bond_main.c
drivers/net/can/flexcan.c
drivers/net/can/m_can/tcan4x5x-core.c
drivers/net/can/peak_canfd/peak_pciefd_main.c
drivers/net/can/sja1000/ems_pci.c
drivers/net/can/sja1000/ems_pcmcia.c
drivers/net/can/sja1000/kvaser_pci.c
drivers/net/can/sja1000/peak_pci.c
drivers/net/can/sja1000/peak_pcmcia.c
drivers/net/can/sja1000/plx_pci.c
drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
drivers/net/can/usb/peak_usb/pcan_usb.c
drivers/net/can/usb/peak_usb/pcan_usb_fd.c
drivers/net/can/usb/peak_usb/pcan_usb_pro.c
drivers/net/dsa/bcm_sf2.c
drivers/net/dsa/mt7530.c
drivers/net/dsa/sja1105/sja1105_main.c
drivers/net/dsa/xrs700x/xrs700x.c
drivers/net/ethernet/atheros/alx/main.c
drivers/net/ethernet/broadcom/bcm4908_enet.c
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/cadence/macb_main.c
drivers/net/ethernet/chelsio/inline_crypto/ch_ktls/chcr_ktls.c
drivers/net/ethernet/davicom/dm9000.c
drivers/net/ethernet/freescale/enetc/enetc.c
drivers/net/ethernet/freescale/enetc/enetc.h
drivers/net/ethernet/freescale/enetc/enetc_hw.h
drivers/net/ethernet/freescale/enetc/enetc_pf.c
drivers/net/ethernet/freescale/enetc/enetc_vf.c
drivers/net/ethernet/freescale/fec_ptp.c
drivers/net/ethernet/freescale/gianfar.c
drivers/net/ethernet/hisilicon/hns/hns_enet.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
drivers/net/ethernet/ibm/ibmveth.c
drivers/net/ethernet/ibm/ibmvnic.c
drivers/net/ethernet/intel/iavf/iavf_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbevf/ipsec.c
drivers/net/ethernet/marvell/octeontx2/af/cgx.c
drivers/net/ethernet/mediatek/mtk_star_emac.c
drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
drivers/net/ethernet/mellanox/mlx4/en_netdev.c
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
drivers/net/ethernet/mellanox/mlxsw/reg.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
drivers/net/ethernet/mellanox/mlxsw/switchx2.c
drivers/net/ethernet/microchip/lan743x_main.c
drivers/net/ethernet/mscc/Kconfig
drivers/net/ethernet/mscc/ocelot_flower.c
drivers/net/ethernet/realtek/r8169_main.c
drivers/net/ethernet/renesas/sh_eth.c
drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c
drivers/net/ethernet/stmicro/stmmac/enh_desc.c
drivers/net/ethernet/stmicro/stmmac/hwif.h
drivers/net/ethernet/stmicro/stmmac/norm_desc.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/sun/niu.c
drivers/net/ethernet/tehuti/tehuti.c
drivers/net/hamradio/6pack.c
drivers/net/hamradio/scc.c
drivers/net/hyperv/hyperv_net.h
drivers/net/hyperv/netvsc_drv.c
drivers/net/hyperv/rndis_filter.c
drivers/net/netdevsim/netdev.c
drivers/net/phy/dp83822.c
drivers/net/phy/dp83tc811.c
drivers/net/phy/phy.c
drivers/net/phy/phy_device.c
drivers/net/usb/cdc_ncm.c
drivers/net/usb/qmi_wwan.c
drivers/net/usb/r8152.c
drivers/net/usb/usbnet.c
drivers/net/wan/fsl_ucc_hdlc.c
drivers/net/wan/lapbether.c
drivers/net/wireless/admtek/adm8211.c
drivers/net/wireless/ath/ath11k/mac.c
drivers/net/wireless/ath/ath11k/qmi.c
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/atmel/atmel.c
drivers/net/wireless/atmel/atmel_cs.c
drivers/net/wireless/atmel/atmel_pci.c
drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c
drivers/net/wireless/broadcom/brcm80211/brcmutil/utils.c
drivers/net/wireless/cisco/airo.c
drivers/net/wireless/cisco/airo_cs.c
drivers/net/wireless/intel/iwlwifi/fw/pnvm.c
drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h
drivers/net/wireless/intel/iwlwifi/mvm/fw.c
drivers/net/wireless/intel/iwlwifi/pcie/drv.c
drivers/net/wireless/intel/iwlwifi/pcie/rx.c
drivers/net/wireless/intersil/hostap/hostap_cs.c
drivers/net/wireless/intersil/hostap/hostap_pci.c
drivers/net/wireless/intersil/hostap/hostap_plx.c
drivers/net/wireless/mediatek/mt76/dma.c
drivers/net/wireless/mediatek/mt76/mt7915/mac.c
drivers/net/wireless/mediatek/mt76/mt7915/testmode.c
drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
drivers/net/wireless/ralink/rt2x00/rt2400pci.c
drivers/net/wireless/ralink/rt2x00/rt2500pci.c
drivers/net/wireless/ralink/rt2x00/rt2500usb.c
drivers/net/wireless/ralink/rt2x00/rt2800pci.c
drivers/net/wireless/ralink/rt2x00/rt2800usb.c
drivers/net/wireless/ralink/rt2x00/rt61pci.c
drivers/net/wireless/ralink/rt2x00/rt73usb.c
drivers/net/wireless/rsi/rsi_91x_main.c
drivers/net/wireless/rsi/rsi_91x_sdio.c
drivers/net/wireless/rsi/rsi_91x_usb.c
drivers/net/xen-netback/netback.c
drivers/nvme/host/core.c
drivers/nvme/host/fabrics.h
drivers/nvme/host/fc.c
drivers/nvme/host/pci.c
drivers/nvme/host/rdma.c
drivers/nvme/host/tcp.c
drivers/nvme/host/zns.c
drivers/nvme/target/core.c
drivers/nvme/target/loop.c
drivers/nvme/target/passthru.c
drivers/nvme/target/rdma.c
drivers/nvme/target/tcp.c
drivers/opp/core.c
drivers/opp/opp.h
drivers/parport/parport_amiga.c
drivers/parport/parport_atari.c
drivers/parport/parport_gsc.c
drivers/parport/parport_mfc3.c
drivers/parport/parport_sunbpp.c
drivers/pci/hotplug/rpadlpar_sysfs.c
drivers/pci/hotplug/s390_pci_hpc.c
drivers/pci/xen-pcifront.c
drivers/perf/arm_dmc620_pmu.c
drivers/platform/x86/intel_pmt_class.c
drivers/platform/x86/intel_pmt_class.h
drivers/platform/x86/intel_pmt_telemetry.c
drivers/power/supply/Kconfig
drivers/power/supply/ab8500-bm.h [new file with mode: 0644]
drivers/power/supply/ab8500-chargalg.h [new file with mode: 0644]
drivers/power/supply/ab8500_bmdata.c
drivers/power/supply/ab8500_btemp.c
drivers/power/supply/ab8500_charger.c
drivers/power/supply/ab8500_fg.c
drivers/power/supply/abx500_chargalg.c
drivers/power/supply/pm2301_charger.c
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/bd71815-regulator.c [new file with mode: 0644]
drivers/regulator/bd71828-regulator.c
drivers/regulator/bd718x7-regulator.c
drivers/regulator/helpers.c
drivers/regulator/mt6315-regulator.c
drivers/regulator/pca9450-regulator.c
drivers/regulator/qcom-rpmh-regulator.c
drivers/regulator/rohm-regulator.c
drivers/regulator/rt4831-regulator.c
drivers/rtc/Kconfig
drivers/rtc/rtc-bd70528.c
drivers/s390/block/dasd.c
drivers/s390/char/tty3270.c
drivers/s390/char/zcore.c
drivers/s390/cio/device_fsm.c
drivers/s390/cio/vfio_ccw_ops.c
drivers/s390/crypto/vfio_ap_ops.c
drivers/s390/net/qeth_core.h
drivers/s390/net/qeth_core_main.c
drivers/sbus/char/display7seg.c
drivers/scsi/hpsa.c
drivers/scsi/ibmvscsi/ibmvfc.c
drivers/scsi/ibmvscsi/ibmvscsi.c
drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
drivers/scsi/lpfc/lpfc_debugfs.c
drivers/scsi/mpt3sas/mpt3sas_scsih.c
drivers/scsi/myrs.c
drivers/scsi/pcmcia/nsp_cs.c
drivers/scsi/qla2xxx/qla_target.h
drivers/scsi/sd_zbc.c
drivers/scsi/smartpqi/smartpqi_init.c
drivers/scsi/st.c
drivers/scsi/ufs/ufs-mediatek.c
drivers/scsi/ufs/ufs-qcom.c
drivers/scsi/ufs/ufshcd.c
drivers/scsi/vmw_pvscsi.c
drivers/scsi/vmw_pvscsi.h
drivers/sh/maple/maple.c
drivers/spi/spi-cadence-quadspi.c
drivers/staging/comedi/drivers/addi_apci_1032.c
drivers/staging/comedi/drivers/addi_apci_1500.c
drivers/staging/comedi/drivers/adv_pci1710.c
drivers/staging/comedi/drivers/amplc_pc236_common.c
drivers/staging/comedi/drivers/cb_pcidas.c
drivers/staging/comedi/drivers/cb_pcidas64.c
drivers/staging/comedi/drivers/comedi_parport.c
drivers/staging/comedi/drivers/das6402.c
drivers/staging/comedi/drivers/das800.c
drivers/staging/comedi/drivers/dmm32at.c
drivers/staging/comedi/drivers/me4000.c
drivers/staging/comedi/drivers/ni_6527.c
drivers/staging/comedi/drivers/ni_65xx.c
drivers/staging/comedi/drivers/pcl711.c
drivers/staging/comedi/drivers/pcl726.c
drivers/staging/comedi/drivers/pcl818.c
drivers/staging/comedi/drivers/vmk80xx.c
drivers/staging/ks7010/ks_wlan_net.c
drivers/staging/rtl8188eu/core/rtw_ap.c
drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
drivers/staging/rtl8192e/Kconfig
drivers/staging/rtl8192e/rtl8192e/rtl_wx.c
drivers/staging/rtl8192u/r8192U_wx.c
drivers/staging/rtl8712/rtl871x_cmd.c
drivers/staging/rtl8712/rtl871x_ioctl_linux.c
drivers/staging/vt6655/rxtx.h
drivers/staging/wfx/bh.c
drivers/staging/wfx/bh.h
drivers/staging/wfx/bus.h
drivers/staging/wfx/bus_sdio.c
drivers/staging/wfx/bus_spi.c
drivers/staging/wfx/data_rx.c
drivers/staging/wfx/data_tx.c
drivers/staging/wfx/data_tx.h
drivers/staging/wfx/debug.c
drivers/staging/wfx/fwio.c
drivers/staging/wfx/hif_api_cmd.h
drivers/staging/wfx/hif_api_general.h
drivers/staging/wfx/hif_tx.c
drivers/staging/wfx/hif_tx_mib.c
drivers/staging/wfx/hwio.c
drivers/staging/wfx/hwio.h
drivers/staging/wfx/key.c
drivers/staging/wfx/key.h
drivers/staging/wfx/main.c
drivers/staging/wfx/main.h
drivers/staging/wfx/queue.c
drivers/staging/wfx/queue.h
drivers/staging/wfx/scan.h
drivers/staging/wfx/sta.c
drivers/staging/wfx/sta.h
drivers/staging/wfx/traces.h
drivers/staging/wfx/wfx.h
drivers/tee/optee/core.c
drivers/thermal/thermal_sysfs.c
drivers/thunderbolt/switch.c
drivers/thunderbolt/tb.c
drivers/tty/hvc/hvcs.c
drivers/tty/pty.c
drivers/tty/serial/icom.c
drivers/tty/serial/jsm/jsm_driver.c
drivers/tty/serial/max310x.c
drivers/tty/tty_io.c
drivers/usb/cdns3/cdnsp-ring.c
drivers/usb/class/cdc-acm.c
drivers/usb/class/usblp.c
drivers/usb/core/usb.c
drivers/usb/dwc3/dwc3-qcom.c
drivers/usb/dwc3/gadget.c
drivers/usb/gadget/configfs.c
drivers/usb/gadget/function/f_uac1.c
drivers/usb/gadget/function/f_uac2.c
drivers/usb/gadget/function/u_ether_configfs.h
drivers/usb/gadget/udc/s3c2410_udc.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/misc/ldusb.c
drivers/usb/renesas_usbhs/pipe.c
drivers/usb/serial/ch341.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/io_edgeport.c
drivers/usb/serial/xr_serial.c
drivers/usb/storage/transport.c
drivers/usb/storage/unusual_devs.h
drivers/usb/typec/tcpm/tcpm.c
drivers/usb/typec/tps6598x.c
drivers/usb/usbip/stub_dev.c
drivers/usb/usbip/vhci_sysfs.c
drivers/usb/usbip/vudc_sysfs.c
drivers/vdpa/ifcvf/ifcvf_main.c
drivers/vdpa/mlx5/net/mlx5_vnet.c
drivers/vdpa/vdpa.c
drivers/vdpa/vdpa_sim/vdpa_sim.c
drivers/vdpa/vdpa_sim/vdpa_sim_net.c
drivers/vfio/Kconfig
drivers/vfio/platform/Kconfig
drivers/vfio/vfio_iommu_type1.c
drivers/vhost/vdpa.c
drivers/vhost/vhost.c
drivers/video/fbdev/aty/atyfb.h
drivers/video/fbdev/aty/atyfb_base.c
drivers/virt/acrn/hsm.c
drivers/virt/acrn/irqfd.c
drivers/virtio/virtio.c
drivers/virtio/virtio_mmio.c
drivers/watchdog/cpu5wdt.c
drivers/watchdog/cpwd.c
drivers/watchdog/riowd.c
drivers/xen/events/events_2l.c
drivers/xen/events/events_base.c
drivers/xen/events/events_fifo.c
drivers/xen/events/events_internal.h
drivers/xen/gntdev.c
fs/Kconfig
fs/afs/dir.c
fs/afs/file.c
fs/afs/fs_operation.c
fs/afs/inode.c
fs/afs/internal.h
fs/afs/mntpt.c
fs/afs/xattr.c
fs/binfmt_misc.c
fs/block_dev.c
fs/btrfs/ctree.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/inode.c
fs/btrfs/reada.c
fs/btrfs/scrub.c
fs/btrfs/tree-log.c
fs/cifs/cifs_debug.c
fs/cifs/cifs_swn.c
fs/cifs/cifsacl.c
fs/cifs/cifsfs.c
fs/cifs/cifsglob.h
fs/cifs/connect.c
fs/cifs/fs_context.c
fs/cifs/inode.c
fs/cifs/sess.c
fs/cifs/smb2inode.c
fs/cifs/smb2misc.c
fs/cifs/smb2ops.c
fs/cifs/smb2pdu.c
fs/cifs/smb2proto.h
fs/cifs/transport.c
fs/configfs/file.c
fs/crypto/bio.c
fs/erofs/data.c
fs/erofs/zdata.c
fs/ext4/balloc.c
fs/ext4/ext4.h
fs/ext4/extents.c
fs/ext4/fast_commit.c
fs/ext4/inode.c
fs/ext4/mballoc.c
fs/ext4/namei.c
fs/ext4/page-io.c
fs/ext4/super.c
fs/ext4/sysfs.c
fs/ext4/verity.c
fs/ext4/xattr.c
fs/f2fs/checkpoint.c
fs/f2fs/data.c
fs/f2fs/segment.c
fs/f2fs/segment.h
fs/f2fs/super.c
fs/fuse/dev.c
fs/fuse/fuse_i.h
fs/fuse/virtio_fs.c
fs/gfs2/log.c
fs/gfs2/lops.c
fs/gfs2/ops_fstype.c
fs/gfs2/super.c
fs/gfs2/super.h
fs/gfs2/trans.c
fs/gfs2/util.c
fs/io-wq.c
fs/io-wq.h
fs/io_uring.c
fs/iomap/buffered-io.c
fs/iomap/direct-io.c
fs/iomap/swapfile.c
fs/locks.c
fs/mpage.c
fs/nfs/Kconfig
fs/nfs/dir.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/nfs3xdr.c
fs/nfs/nfs42proc.c
fs/nfs/nfs4proc.c
fs/nfs/unlink.c
fs/nfs/write.c
fs/nfsd/Kconfig
fs/nfsd/filecache.c
fs/nfsd/nfs4callback.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/nilfs2/segbuf.c
fs/pnode.h
fs/proc/task_mmu.c
fs/select.c
fs/squashfs/block.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_itable.c
fs/xfs/xfs_mount.c
fs/xfs/xfs_symlink.c
fs/zonefs/super.c
include/drm/ttm/ttm_bo_api.h
include/kvm/arm_pmu.h
include/linux/acpi.h
include/linux/amba/bus.h
include/linux/atmdev.h
include/linux/bio.h
include/linux/can/skb.h
include/linux/compiler-clang.h
include/linux/compiler-version.h [new file with mode: 0644]
include/linux/cpu.h
include/linux/efi.h
include/linux/gpio/consumer.h
include/linux/io_uring.h
include/linux/irqdomain.h
include/linux/kconfig.h
include/linux/memblock.h
include/linux/memcontrol.h
include/linux/mfd/abx500.h
include/linux/mfd/abx500/ab8500-bm.h [deleted file]
include/linux/mfd/abx500/ux500_chargalg.h [deleted file]
include/linux/mfd/atc260x/atc2603c.h [new file with mode: 0644]
include/linux/mfd/atc260x/atc2609a.h [new file with mode: 0644]
include/linux/mfd/atc260x/core.h [new file with mode: 0644]
include/linux/mfd/rohm-bd71815.h [new file with mode: 0644]
include/linux/mfd/rohm-bd71828.h
include/linux/mfd/rohm-bd718x7.h
include/linux/mfd/rohm-generic.h
include/linux/mm.h
include/linux/mm_types.h
include/linux/module.h
include/linux/netdevice.h
include/linux/perf_event.h
include/linux/pgtable.h
include/linux/property.h
include/linux/regulator/driver.h
include/linux/regulator/pca9450.h
include/linux/restart_block.h
include/linux/sched/mm.h
include/linux/seqlock.h
include/linux/stop_machine.h
include/linux/sunrpc/svc_rdma.h
include/linux/textsearch.h
include/linux/thread_info.h
include/linux/u64_stats_sync.h
include/linux/usb.h
include/linux/usb_usual.h
include/linux/vdpa.h
include/linux/virtio.h
include/linux/virtio_net.h
include/linux/ww_mutex.h
include/media/rc-map.h
include/trace/events/workqueue.h
include/uapi/linux/bpf.h
include/uapi/linux/fuse.h
include/uapi/linux/l2tp.h
include/uapi/linux/netfilter/nfnetlink_cthelper.h
include/xen/grant_table.h
include/xen/xenbus.h
init/Kconfig
kernel/bpf/btf.c
kernel/bpf/core.c
kernel/bpf/verifier.c
kernel/events/core.c
kernel/fork.c
kernel/freezer.c
kernel/futex.c
kernel/irq/irq_sim.c
kernel/irq/irqdomain.c
kernel/irq/manage.c
kernel/jump_label.c
kernel/locking/mutex.c
kernel/reboot.c
kernel/sched/core.c
kernel/sched/membarrier.c
kernel/signal.c
kernel/static_call.c
kernel/sys.c
kernel/time/alarmtimer.c
kernel/time/hrtimer.c
kernel/time/posix-cpu-timers.c
lib/Kconfig.kasan
lib/extable.c
mm/highmem.c
mm/huge_memory.c
mm/hugetlb.c
mm/internal.h
mm/kfence/report.c
mm/madvise.c
mm/memcontrol.c
mm/memory.c
mm/memory_hotplug.c
mm/page_alloc.c
mm/slab.c
mm/slub.c
net/9p/client.c
net/batman-adv/main.c
net/core/rtnetlink.c
net/core/skbuff.c
net/dsa/Kconfig
net/dsa/dsa_priv.h
net/dsa/slave.c
net/dsa/tag_mtk.c
net/dsa/tag_rtl4_a.c
net/ethtool/channels.c
net/ipv4/cipso_ipv4.c
net/ipv4/inetpeer.c
net/ipv4/ip_tunnel.c
net/ipv4/ip_vti.c
net/ipv4/nexthop.c
net/ipv4/tcp.c
net/ipv4/udp_offload.c
net/ipv6/calipso.c
net/ipv6/ip6_gre.c
net/ipv6/ip6_tunnel.c
net/ipv6/ip6_vti.c
net/ipv6/sit.c
net/l2tp/l2tp_core.c
net/l2tp/l2tp_core.h
net/l2tp/l2tp_netlink.c
net/mpls/mpls_gso.c
net/mptcp/protocol.c
net/mptcp/protocol.h
net/mptcp/subflow.c
net/netfilter/nf_conntrack_helper.c
net/netfilter/nf_conntrack_proto_tcp.c
net/netfilter/nf_nat_proto.c
net/netfilter/nf_tables_api.c
net/netfilter/x_tables.c
net/netlabel/netlabel_cipso_v4.c
net/qrtr/qrtr.c
net/sched/sch_api.c
net/sctp/tsnmap.c
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/sched.c
net/sunrpc/svc.c
net/sunrpc/svc_xprt.c
net/sunrpc/xprtrdma/svc_rdma_backchannel.c
net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
samples/bpf/xdpsock_user.c
scripts/Makefile.lib
scripts/dummy-tools/gcc
scripts/gcc-plugins/Makefile
scripts/ld-version.sh
security/commoncap.c
sound/drivers/aloop.c
sound/drivers/dummy.c
sound/drivers/mtpav.c
sound/drivers/mts64.c
sound/drivers/pcsp/pcsp.c
sound/drivers/portman2x4.c
sound/drivers/serial-u16550.c
sound/drivers/virmidi.c
sound/firewire/dice/dice-stream.c
sound/hda/intel-nhlt.c
sound/isa/ad1816a/ad1816a.c
sound/isa/ad1848/ad1848.c
sound/isa/als100.c
sound/isa/azt2320.c
sound/isa/cmi8330.c
sound/isa/cs423x/cs4231.c
sound/isa/cs423x/cs4236.c
sound/isa/es1688/es1688.c
sound/isa/es18xx.c
sound/isa/gus/gusclassic.c
sound/isa/gus/gusextreme.c
sound/isa/gus/gusmax.c
sound/isa/gus/interwave.c
sound/isa/opl3sa2.c
sound/isa/opti9xx/miro.c
sound/isa/opti9xx/opti92x-ad1848.c
sound/isa/sb/jazz16.c
sound/isa/sb/sb16.c
sound/isa/sb/sb8.c
sound/isa/sc6000.c
sound/isa/wavefront/wavefront.c
sound/mips/sgio2audio.c
sound/pci/ad1889.c
sound/pci/ali5451/ali5451.c
sound/pci/als300.c
sound/pci/als4000.c
sound/pci/atiixp.c
sound/pci/atiixp_modem.c
sound/pci/au88x0/au88x0.c
sound/pci/azt3328.c
sound/pci/bt87x.c
sound/pci/ca0106/ca0106_main.c
sound/pci/cmipci.c
sound/pci/cs4281.c
sound/pci/cs46xx/cs46xx.c
sound/pci/cs5535audio/cs5535audio.c
sound/pci/ctxfi/xfi.c
sound/pci/echoaudio/echoaudio.c
sound/pci/emu10k1/emu10k1.c
sound/pci/emu10k1/emu10k1x.c
sound/pci/ens1370.c
sound/pci/es1938.c
sound/pci/es1968.c
sound/pci/fm801.c
sound/pci/hda/hda_bind.c
sound/pci/hda/hda_controller.c
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_ca0132.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/ice1712/ice1712.c
sound/pci/ice1712/ice1724.c
sound/pci/intel8x0.c
sound/pci/intel8x0m.c
sound/pci/korg1212/korg1212.c
sound/pci/lola/lola.c
sound/pci/lx6464es/lx6464es.c
sound/pci/maestro3.c
sound/pci/mixart/mixart.c
sound/pci/nm256/nm256.c
sound/pci/oxygen/oxygen.c
sound/pci/oxygen/se6x.c
sound/pci/oxygen/virtuoso.c
sound/pci/pcxhr/pcxhr.c
sound/pci/riptide/riptide.c
sound/pci/rme32.c
sound/pci/rme96.c
sound/pci/rme9652/hdsp.c
sound/pci/rme9652/hdspm.c
sound/pci/rme9652/rme9652.c
sound/pci/sis7019.c
sound/pci/sonicvibes.c
sound/pci/trident/trident.c
sound/pci/via82xx.c
sound/pci/via82xx_modem.c
sound/pci/vx222/vx222.c
sound/pci/ymfpci/ymfpci.c
sound/pcmcia/pdaudiocf/pdaudiocf.c
sound/pcmcia/vx/vxpocket.c
sound/ppc/powermac.c
sound/sh/aica.c
sound/sh/sh_dac_audio.c
sound/soc/codecs/Kconfig
sound/soc/codecs/ak4458.c
sound/soc/codecs/ak5558.c
sound/soc/codecs/arizona-jack.c [new file with mode: 0644]
sound/soc/codecs/cs42l42.c
sound/soc/codecs/cs42l42.h
sound/soc/codecs/es8316.c
sound/soc/codecs/lpass-rx-macro.c
sound/soc/codecs/lpass-va-macro.c
sound/soc/codecs/lpass-wsa-macro.c
sound/soc/codecs/rt1015.c
sound/soc/codecs/rt5640.c
sound/soc/codecs/rt5651.c
sound/soc/codecs/rt5659.c
sound/soc/codecs/rt5670.c
sound/soc/codecs/rt5670.h
sound/soc/codecs/rt711.c
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/sirf-audio-codec.h [deleted file]
sound/soc/codecs/wcd934x.c
sound/soc/fsl/fsl_ssi.c
sound/soc/generic/simple-card-utils.c
sound/soc/intel/boards/bytcr_rt5640.c
sound/soc/mediatek/mt8192/mt8192-dai-tdm.c
sound/soc/mediatek/mt8192/mt8192-reg.h
sound/soc/qcom/lpass-cpu.c
sound/soc/qcom/sdm845.c
sound/soc/soc-core.c
sound/soc/sof/intel/hda-dsp.c
sound/soc/sof/intel/hda.c
sound/sparc/amd7930.c
sound/sparc/cs4231.c
sound/sparc/dbri.c
sound/usb/6fire/chip.c
sound/usb/caiaq/device.c
sound/usb/card.c
sound/usb/hiface/chip.c
sound/usb/misc/ua101.c
sound/usb/mixer_quirks.c
sound/usb/quirks.c
sound/usb/usbaudio.h
sound/usb/usx2y/usbusx2y.c
sound/x86/intel_hdmi_audio.c
sound/xen/xen_snd_front.c
tools/arch/s390/include/uapi/asm/ptrace.h
tools/arch/x86/include/asm/cpufeatures.h
tools/arch/x86/include/uapi/asm/kvm.h
tools/arch/x86/include/uapi/asm/vmx.h
tools/bpf/resolve_btfids/main.c
tools/build/Makefile
tools/include/linux/coresight-pmu.h
tools/include/uapi/drm/drm.h
tools/include/uapi/drm/i915_drm.h
tools/include/uapi/linux/bpf.h
tools/include/uapi/linux/kvm.h
tools/include/uapi/linux/mount.h
tools/include/uapi/linux/openat2.h
tools/lib/bpf/xsk.c
tools/lib/perf/evlist.c
tools/lib/perf/include/internal/evlist.h
tools/objtool/check.c
tools/perf/Documentation/perf-evlist.txt
tools/perf/Documentation/perf-ftrace.txt
tools/perf/Documentation/perf-kallsyms.txt
tools/perf/Documentation/perf-trace.txt
tools/perf/Makefile.perf
tools/perf/arch/arm/util/cs-etm.c
tools/perf/arch/powerpc/entry/syscalls/syscall.tbl
tools/perf/arch/s390/entry/syscalls/syscall.tbl
tools/perf/arch/x86/Makefile
tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
tools/perf/arch/x86/include/arch-tests.h
tools/perf/arch/x86/tests/Build
tools/perf/arch/x86/tests/arch-tests.c
tools/perf/arch/x86/tests/insn-x86.c
tools/perf/arch/x86/tests/sample-parsing.c [new file with mode: 0644]
tools/perf/arch/x86/util/archinsn.c
tools/perf/bench/numa.c
tools/perf/bench/sched-messaging.c
tools/perf/bench/sched-pipe.c
tools/perf/bench/syscall.c
tools/perf/builtin-daemon.c
tools/perf/builtin-diff.c
tools/perf/builtin-trace.c
tools/perf/perf-archive.sh
tools/perf/tests/attr.c
tools/perf/tests/code-reading.c
tools/perf/tests/cpumap.c
tools/perf/tests/keep-tracking.c
tools/perf/tests/mmap-basic.c
tools/perf/tests/perf-time-to-tsc.c
tools/perf/tests/sample-parsing.c
tools/perf/tests/shell/daemon.sh
tools/perf/tests/sw-clock.c
tools/perf/tests/switch-tracking.c
tools/perf/tests/task-exit.c
tools/perf/tests/thread-map.c
tools/perf/util/evlist.c
tools/perf/util/evsel.c
tools/perf/util/evsel.h
tools/perf/util/header.c
tools/perf/util/map.c
tools/perf/util/parse-events.y
tools/perf/util/python-ext-sources
tools/perf/util/sort.c
tools/perf/util/stat-display.c
tools/perf/util/stat.c
tools/perf/util/trace-event-read.c
tools/testing/selftests/arm64/fp/sve-ptrace.c
tools/testing/selftests/bpf/progs/netif_receive_skb.c
tools/testing/selftests/bpf/progs/test_global_func11.c
tools/testing/selftests/bpf/progs/test_tunnel_kern.c
tools/testing/selftests/bpf/verifier/array_access.c
tools/testing/selftests/bpf/verifier/atomic_and.c
tools/testing/selftests/bpf/verifier/atomic_cmpxchg.c
tools/testing/selftests/bpf/verifier/atomic_or.c
tools/testing/selftests/gpio/.gitignore
tools/testing/selftests/kvm/.gitignore
tools/testing/selftests/kvm/Makefile
tools/testing/selftests/kvm/include/kvm_util.h
tools/testing/selftests/kvm/lib/kvm_util.c
tools/testing/selftests/kvm/lib/kvm_util_internal.h
tools/testing/selftests/kvm/x86_64/get_msr_index_features.c [new file with mode: 0644]
tools/testing/selftests/kvm/x86_64/hyperv_clock.c [new file with mode: 0644]
tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c [new file with mode: 0644]
tools/testing/selftests/net/fib_nexthops.sh
tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d_vlan.sh
tools/testing/selftests/net/ipsec.c
tools/testing/selftests/netfilter/Makefile
tools/testing/selftests/netfilter/nf_nat_edemux.sh [new file with mode: 0755]

index ea0cc8c..f704925 100644 (file)
@@ -33,7 +33,7 @@ Contact:      xfs@oss.sgi.com
 Description:
                The current state of the log write grant head. It
                represents the total log reservation of all currently
-               oustanding transactions, including regrants due to
+               outstanding transactions, including regrants due to
                rolling transactions. The grant head is exported in
                "cycle:bytes" format.
 Users:         xfstests
index ab407f2..caba932 100644 (file)
@@ -34,4 +34,11 @@ properties:
       specify this property.
     $ref: /schemas/types.yaml#/definitions/uint32
 
+  reset-time-sec:
+    description:
+      Duration in seconds which the key should be kept pressed for device to
+      reset automatically. Device with key pressed reset feature can specify
+      this property.
+    $ref: /schemas/types.yaml#/definitions/uint32
+
 additionalProperties: true
index 0a046be..0358a77 100644 (file)
@@ -23,6 +23,7 @@ properties:
           - enum:
               - ingenic,jz4775-intc
               - ingenic,jz4770-intc
+              - ingenic,jz4760b-intc
           - const: ingenic,jz4760-intc
       - items:
           - const: ingenic,x1000-intc
diff --git a/Documentation/devicetree/bindings/mfd/actions,atc260x.yaml b/Documentation/devicetree/bindings/mfd/actions,atc260x.yaml
new file mode 100644 (file)
index 0000000..dd43a0c
--- /dev/null
@@ -0,0 +1,183 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/actions,atc260x.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Actions Semi ATC260x Power Management IC bindings
+
+maintainers:
+  - Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+  - Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
+
+description: |
+  ATC260x series PMICs integrates Audio Codec, Power Management, RTC, IR
+  and GPIO controller blocks. Currently only the PM related functionalities
+  (i.e. regulators and system power-off/reboot) for the ATC2603C and ATC2609A
+  chip variants are supported.
+  ATC2603C includes 3 programmable DC-DC converters, 9 programmable LDO
+  regulators and 1 fixed LDO regulator.
+  ATC2609A includes 5 programmable DC-DC converters and 10 programmable LDO
+  regulators.
+
+allOf:
+  - $ref: ../input/input.yaml
+
+properties:
+  compatible:
+    enum:
+      - actions,atc2603c
+      - actions,atc2609a
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  reset-time-sec:
+    description: |
+      Duration in seconds which the key should be kept pressed for device
+      to reset automatically. The hardware default is 8. Use 0 to disable
+      this functionality.
+    enum: [0, 6, 8, 10, 12]
+
+  regulators:
+    type: object
+    description: |
+      List of child nodes specifying the regulators, depending on chip variant:
+      * ATC2603C: dcdc[1-3], ldo[1-3,5-8,11,12], switchldo1
+      * ATC2609A: dcdc[0-4], ldo[0-9]
+
+    properties:
+      compatible:
+        enum:
+          - actions,atc2603c-regulator
+          - actions,atc2609a-regulator
+
+      switchldo1:
+        type: object
+        $ref: ../regulator/regulator.yaml
+
+        properties:
+          regulator-name: true
+          regulator-boot-on: true
+          regulator-always-on: true
+          regulator-min-microvolt: true
+          regulator-max-microvolt: true
+          regulator-allow-bypass: true
+          regulator-active-discharge: true
+
+        additionalProperties: false
+
+    patternProperties:
+      "^(dcdc[0-4]|ldo[0-9]|ldo1[1-2]|switchldo1)-supply$":
+        description: ATC260x voltage regulators supplies
+
+      "^(dcdc[0-4]|ldo[0-9]|ldo1[1-2])$":
+        type: object
+        $ref: ../regulator/regulator.yaml
+
+        properties:
+          regulator-name: true
+          regulator-boot-on: true
+          regulator-always-on: true
+          regulator-min-microvolt: true
+          regulator-max-microvolt: true
+          regulator-allow-bypass: true
+
+        additionalProperties: false
+
+    allOf:
+      - if:
+          properties:
+            compatible:
+              contains:
+                const: actions,atc2603c-regulator
+        then:
+          patternProperties:
+            "^(dcdc[0,4]|ldo[0,4,9])(-supply)?$": false
+
+            "^(ldo|dcdc)":
+              properties:
+                regulator-allow-bypass: false
+      - if:
+          properties:
+            compatible:
+              contains:
+                const: actions,atc2609a-regulator
+        then:
+          patternProperties:
+            "^(ldo1[1-2]|switchldo1)(-supply)?$": false
+
+            "^(dcdc|ldo[3-9])":
+              properties:
+                regulator-allow-bypass: false
+
+    required:
+      - compatible
+
+    additionalProperties: false
+
+additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    i2c0 {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        pmic@65 {
+            compatible = "actions,atc2603c";
+            reg = <0x65>;
+            interrupt-parent = <&sirq>;
+            interrupts = <2 IRQ_TYPE_LEVEL_HIGH>;
+
+            reset-time-sec = <6>;
+
+            regulators {
+                compatible = "actions,atc2603c-regulator";
+
+                dcdc1-supply = <&reg_5v0>;
+                dcdc3-supply = <&reg_5v0>;
+                ldo5-supply = <&reg_5v0>;
+                switchldo1-supply = <&vcc>;
+
+                vdd_cpu: dcdc1 {
+                    regulator-name = "VDD_CPU";
+                    regulator-min-microvolt = <700000>;
+                    regulator-max-microvolt = <1400000>;
+                    regulator-always-on;
+                };
+
+                vcc: dcdc3 {
+                    regulator-name = "VCC";
+                    regulator-min-microvolt = <2600000>;
+                    regulator-max-microvolt = <3300000>;
+                    regulator-always-on;
+                };
+
+                vcc_3v1: ldo5 {
+                    regulator-name = "VCC_3V1";
+                    regulator-min-microvolt = <2600000>;
+                    regulator-max-microvolt = <3300000>;
+                };
+
+                sd_vcc: switchldo1 {
+                    regulator-name = "SD_VCC";
+                    regulator-min-microvolt = <3000000>;
+                    regulator-max-microvolt = <3300000>;
+                    regulator-always-on;
+                    regulator-boot-on;
+                };
+            };
+        };
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml b/Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml
new file mode 100644 (file)
index 0000000..fe265bc
--- /dev/null
@@ -0,0 +1,201 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/rohm,bd71815-pmic.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ROHM BD71815 Power Management Integrated Circuit bindings
+
+maintainers:
+  - Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
+
+description: |
+  BD71815AGW is a single-chip power management ICs for battery-powered
+  portable devices. It integrates 5 buck converters, 8 LDOs, a boost driver
+  for LED and a 500 mA single-cell linear charger. Also included is a Coulomb
+  counter, a real-time clock (RTC), and a 32.768 kHz clock gate and two GPOs.
+
+properties:
+  compatible:
+    const: rohm,bd71815
+
+  reg:
+    description:
+      I2C slave address.
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  gpio-controller: true
+
+  "#gpio-cells":
+    const: 2
+    description: |
+      The first cell is the pin number and the second cell is used to specify
+      flags. See ../gpio/gpio.txt for more information.
+
+  clocks:
+    maxItems: 1
+
+  "#clock-cells":
+    const: 0
+
+  clock-output-names:
+    const: bd71815-32k-out
+
+  rohm,clkout-open-drain:
+    description: clk32kout mode. Set to 1 for "open-drain" or 0 for "cmos".
+    $ref: "/schemas/types.yaml#/definitions/uint32"
+    minimum: 0
+    maximum: 1
+
+  rohm,charger-sense-resistor-ohms:
+    minimum: 10000000
+    maximum: 50000000
+    description: |
+      BD71827 and BD71828 have SAR ADC for measuring charging currents.
+      External sense resistor (RSENSE in data sheet) should be used. If
+      something other but 30MOhm resistor is used the resistance value
+      should be given here in Ohms.
+    default: 30000000
+
+  regulators:
+    $ref: ../regulator/rohm,bd71815-regulator.yaml
+    description:
+      List of child nodes that specify the regulators.
+
+  gpio-reserved-ranges:
+    description: |
+      Usage of BD71828 GPIO pins can be changed via OTP. This property can be
+      used to mark the pins which should not be configured for GPIO. Please see
+      the ../gpio/gpio.txt for more information.
+
+  rohm,enable-hidden-gpo:
+    description: |
+      The BD71815 has undocumented GPO at pin E5. Pin is marked as GND at the
+      data-sheet as it's location in the middle of GND pins makes it hard to
+      use on PCB. If your board has managed to use this pin you can enable the
+      second GPO by defining this property. Dont enable this if you are unsure
+      about how the E5 pin is connected on your board.
+    type: boolean
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - "#clock-cells"
+  - regulators
+  - gpio-controller
+  - "#gpio-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/leds/common.h>
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        pmic: pmic@4b {
+            compatible = "rohm,bd71815";
+            reg = <0x4b>;
+
+            interrupt-parent = <&gpio1>;
+            interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
+
+            clocks = <&osc 0>;
+            #clock-cells = <0>;
+            clock-output-names = "bd71815-32k-out";
+
+            gpio-controller;
+            #gpio-cells = <2>;
+
+            rohm,charger-sense-resistor-ohms = <10000000>;
+
+            regulators {
+                buck1: buck1 {
+                    regulator-name = "buck1";
+                    regulator-min-microvolt = <800000>;
+                    regulator-max-microvolt = <2000000>;
+                    regulator-always-on;
+                    regulator-ramp-delay = <1250>;
+                    rohm,dvs-run-voltage = <1150000>;
+                    rohm,dvs-suspend-voltage = <950000>;
+                };
+                buck2: buck2 {
+                    regulator-name = "buck2";
+                    regulator-min-microvolt = <800000>;
+                    regulator-max-microvolt = <2000000>;
+                    regulator-always-on;
+                    regulator-ramp-delay = <1250>;
+                    rohm,dvs-run-voltage = <1150000>;
+                    rohm,dvs-suspend-voltage = <950000>;
+                };
+                buck3: buck3 {
+                    regulator-name = "buck3";
+                    regulator-min-microvolt = <1200000>;
+                    regulator-max-microvolt = <2700000>;
+                    regulator-always-on;
+                };
+                buck4: buck4 {
+                    regulator-name = "buck4";
+                    regulator-min-microvolt = <1100000>;
+                    regulator-max-microvolt = <1850000>;
+                    regulator-always-on;
+                };
+                buck5: buck5 {
+                    regulator-name = "buck5";
+                    regulator-min-microvolt = <1800000>;
+                    regulator-max-microvolt = <3300000>;
+                    regulator-always-on;
+                };
+                ldo1: ldo1 {
+                    regulator-name = "ldo1";
+                    regulator-min-microvolt = <800000>;
+                    regulator-max-microvolt = <3300000>;
+                    regulator-always-on;
+                };
+                ldo2: ldo2 {
+                    regulator-name = "ldo2";
+                    regulator-min-microvolt = <800000>;
+                    regulator-max-microvolt = <3300000>;
+                    regulator-always-on;
+                };
+                ldo3: ldo3 {
+                    regulator-name = "ldo3";
+                    regulator-min-microvolt = <800000>;
+                    regulator-max-microvolt = <3300000>;
+                    regulator-always-on;
+                };
+                ldo4: ldo4 {
+                    regulator-name = "ldo4";
+                    regulator-min-microvolt = <800000>;
+                    regulator-max-microvolt = <3300000>;
+                    regulator-always-on;
+                };
+                ldo5: ldo5 {
+                    regulator-name = "ldo5";
+                    regulator-min-microvolt = <800000>;
+                    regulator-max-microvolt = <3300000>;
+                    regulator-always-on;
+                };
+                ldo6: ldodvref {
+                    regulator-name = "ldodvref";
+                    regulator-always-on;
+                };
+                ldo7: ldolpsr {
+                    regulator-name = "ldolpsr";
+                    regulator-always-on;
+                };
+
+                boost: wled {
+                    regulator-name = "wled";
+                    regulator-min-microamp = <10>;
+                    regulator-max-microamp = <25000>;
+                };
+            };
+        };
+    };
index 3a6a1a2..8380166 100644 (file)
@@ -44,6 +44,12 @@ properties:
   clock-output-names:
     const: bd71828-32k-out
 
+  rohm,clkout-open-drain:
+    description: clk32kout mode. Set to 1 for "open-drain" or 0 for "cmos".
+    $ref: "/schemas/types.yaml#/definitions/uint32"
+    minimum: 0
+    maximum: 1
+
   rohm,charger-sense-resistor-ohms:
     minimum: 10000000
     maximum: 50000000
diff --git a/Documentation/devicetree/bindings/regulator/rohm,bd71815-regulator.yaml b/Documentation/devicetree/bindings/regulator/rohm,bd71815-regulator.yaml
new file mode 100644 (file)
index 0000000..7d0adb7
--- /dev/null
@@ -0,0 +1,116 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/rohm,bd71815-regulator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ROHM BD71815 Power Management Integrated Circuit regulators
+
+maintainers:
+  - Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
+
+description: |
+  This module is part of the ROHM BD718215 MFD device. For more details
+  see Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml.
+
+  The regulator controller is represented as a sub-node of the PMIC node
+  on the device tree.
+
+  The valid names for BD71815 regulator nodes are
+  buck1, buck2, buck3, buck4, buck5,
+  ldo1, ldo2, ldo3, ldo4, ldo5,
+  ldodvref, ldolpsr, wled
+
+properties:
+  wled:
+    type: object
+    description:
+      properties for wled regulator
+    $ref: regulator.yaml#
+
+    properties:
+      regulator-name:
+        const: wled
+
+patternProperties:
+  "^((ldo|buck)[1-5]|ldolpsr|ldodvref)$":
+    type: object
+    description:
+      Properties for single LDO/BUCK regulator.
+    $ref: regulator.yaml#
+
+    properties:
+      regulator-name:
+        pattern: "^((ldo|buck)[1-5]|ldolpsr|ldodvref)$"
+        description:
+          should be "ldo1", ..., "ldo5", "buck1", ..., "buck5" and "ldolpsr"
+          for ldolpsr regulator, "ldodvref" for ldodvref reglator.
+
+      rohm,vsel-gpios:
+        description:
+          GPIO used to control ldo4 state (when ldo4 is controlled by GPIO).
+
+      rohm,dvs-run-voltage:
+        description:
+          PMIC "RUN" state voltage in uV when PMIC HW states are used. See
+          comments below for bucks/LDOs which support this. 0 means
+          regulator should be disabled at RUN state.
+        $ref: "/schemas/types.yaml#/definitions/uint32"
+        minimum: 0
+        maximum: 3300000
+
+      rohm,dvs-snvs-voltage:
+        description:
+          Whether to keep regulator enabled at "SNVS" state or not.
+          0 means regulator should be disabled at SNVS state, non zero voltage
+          keeps regulator enabled. BD71815 does not change voltage level
+          when PMIC transitions to SNVS.SNVS voltage depends on the previous
+          state (from which the PMIC transitioned to SNVS).
+        $ref: "/schemas/types.yaml#/definitions/uint32"
+        minimum: 0
+        maximum: 3300000
+
+      rohm,dvs-suspend-voltage:
+        description:
+          PMIC "SUSPEND" state voltage in uV when PMIC HW states are used. See
+          comments below for bucks/LDOs which support this. 0 means
+          regulator should be disabled at SUSPEND state.
+        $ref: "/schemas/types.yaml#/definitions/uint32"
+        minimum: 0
+        maximum: 3300000
+
+      rohm,dvs-lpsr-voltage:
+        description:
+          PMIC "LPSR" state voltage in uV when PMIC HW states are used. See
+          comments below for bucks/LDOs which support this. 0 means
+          regulator should be disabled at LPSR state.
+        $ref: "/schemas/types.yaml#/definitions/uint32"
+        minimum: 0
+        maximum: 3300000
+
+        # Bucks 1 and 2 support giving separate voltages for operational states
+        # (RUN /CLEAN according to data-sheet) and non operational states
+        # (LPSR/SUSPEND). The voltage is automatically changed when HW
+        # state changes. Omitting these properties from bucks 1 and 2 leave
+        # buck voltages to not be toggled by HW state. Enable status may still
+        # be toggled by state changes depending on HW default settings.
+        #
+        # Bucks 3-5 and ldos 1-5 support setting the RUN state voltage here.
+        # Given RUN voltage is used at all states if regulator is enabled at
+        # given state.
+        # Values given for other states are regarded as enable/disable at
+        # given state (see below).
+        #
+        # All regulators except WLED support specifying enable/disable status
+        # for each of the HW states (RUN/SNVS/SUSPEND/LPSR). HW defaults can
+        # be overridden by setting voltage to 0 (regulator disabled at given
+        # state) or non-zero (regulator enabled at given state). Please note
+        # that setting non zero voltages for bucks 1/2 will also enable voltage
+        # changes according to state change.
+
+    required:
+      - regulator-name
+
+    unevaluatedProperties: false
+
+additionalProperties: false
index 50449b6..4454aca 100644 (file)
@@ -21,6 +21,10 @@ properties:
       - fsl,vf610-spdif
       - fsl,imx6sx-spdif
       - fsl,imx8qm-spdif
+      - fsl,imx8qxp-spdif
+      - fsl,imx8mq-spdif
+      - fsl,imx8mm-spdif
+      - fsl,imx8mn-spdif
 
   reg:
     maxItems: 1
index 40ccac6..22ce801 100644 (file)
@@ -613,6 +613,27 @@ Some of these date from the very introduction of KMS in 2008 ...
 
 Level: Intermediate
 
+Remove automatic page mapping from dma-buf importing
+----------------------------------------------------
+
+When importing dma-bufs, the dma-buf and PRIME frameworks automatically map
+imported pages into the importer's DMA area. drm_gem_prime_fd_to_handle() and
+drm_gem_prime_handle_to_fd() require that importers call dma_buf_attach()
+even if they never do actual device DMA, but only CPU access through
+dma_buf_vmap(). This is a problem for USB devices, which do not support DMA
+operations.
+
+To fix the issue, automatic page mappings should be removed from the
+buffer-sharing code. Fixing this is a bit more involved, since the import/export
+cache is also tied to &drm_gem_object.import_attach. Meanwhile we paper over
+this problem for USB devices by fishing out the USB host controller device, as
+long as that supports DMA. Otherwise importing can still needlessly fail.
+
+Contact: Thomas Zimmermann <tzimmermann@suse.de>, Daniel Vetter
+
+Level: Advanced
+
+
 Better Testing
 ==============
 
index 5f690f0..62f2aab 100644 (file)
@@ -1988,7 +1988,7 @@ netif_carrier.
 If use_carrier is 0, then the MII monitor will first query the
 device's (via ioctl) MII registers and check the link state.  If that
 request fails (not just that it returns carrier down), then the MII
-monitor will make an ethtool ETHOOL_GLINK request to attempt to obtain
+monitor will make an ethtool ETHTOOL_GLINK request to attempt to obtain
 the same information.  If both methods fail (i.e., the driver either
 does not support or had some error in processing both the MII register
 and ethtool requests), then the MII monitor will assume the link is
index a64c01b..91b2cf7 100644 (file)
@@ -142,73 +142,13 @@ Please send incremental versions on top of what has been merged in order to fix
 the patches the way they would look like if your latest patch series was to be
 merged.
 
-How can I tell what patches are queued up for backporting to the various stable releases?
------------------------------------------------------------------------------------------
-Normally Greg Kroah-Hartman collects stable commits himself, but for
-networking, Dave collects up patches he deems critical for the
-networking subsystem, and then hands them off to Greg.
-
-There is a patchworks queue that you can see here:
-
-  https://patchwork.kernel.org/bundle/netdev/stable/?state=*
-
-It contains the patches which Dave has selected, but not yet handed off
-to Greg.  If Greg already has the patch, then it will be here:
-
-  https://git.kernel.org/pub/scm/linux/kernel/git/stable/stable-queue.git
-
-A quick way to find whether the patch is in this stable-queue is to
-simply clone the repo, and then git grep the mainline commit ID, e.g.
-::
-
-  stable-queue$ git grep -l 284041ef21fdf2e
-  releases/3.0.84/ipv6-fix-possible-crashes-in-ip6_cork_release.patch
-  releases/3.4.51/ipv6-fix-possible-crashes-in-ip6_cork_release.patch
-  releases/3.9.8/ipv6-fix-possible-crashes-in-ip6_cork_release.patch
-  stable/stable-queue$
-
-I see a network patch and I think it should be backported to stable. Should I request it via stable@vger.kernel.org like the references in the kernel's Documentation/process/stable-kernel-rules.rst file say?
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-No, not for networking.  Check the stable queues as per above first
-to see if it is already queued.  If not, then send a mail to netdev,
-listing the upstream commit ID and why you think it should be a stable
-candidate.
-
-Before you jump to go do the above, do note that the normal stable rules
-in :ref:`Documentation/process/stable-kernel-rules.rst <stable_kernel_rules>`
-still apply.  So you need to explicitly indicate why it is a critical
-fix and exactly what users are impacted.  In addition, you need to
-convince yourself that you *really* think it has been overlooked,
-vs. having been considered and rejected.
-
-Generally speaking, the longer it has had a chance to "soak" in
-mainline, the better the odds that it is an OK candidate for stable.  So
-scrambling to request a commit be added the day after it appears should
-be avoided.
-
-I have created a network patch and I think it should be backported to stable. Should I add a Cc: stable@vger.kernel.org like the references in the kernel's Documentation/ directory say?
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-No.  See above answer.  In short, if you think it really belongs in
-stable, then ensure you write a decent commit log that describes who
-gets impacted by the bug fix and how it manifests itself, and when the
-bug was introduced.  If you do that properly, then the commit will get
-handled appropriately and most likely get put in the patchworks stable
-queue if it really warrants it.
-
-If you think there is some valid information relating to it being in
-stable that does *not* belong in the commit log, then use the three dash
-marker line as described in
-:ref:`Documentation/process/submitting-patches.rst <the_canonical_patch_format>`
-to temporarily embed that information into the patch that you send.
-
-Are all networking bug fixes backported to all stable releases?
+Are there special rules regarding stable submissions on netdev?
 ---------------------------------------------------------------
-Due to capacity, Dave could only take care of the backports for the
-last two stable releases. For earlier stable releases, each stable
-branch maintainer is supposed to take care of them. If you find any
-patch is missing from an earlier stable branch, please notify
-stable@vger.kernel.org with either a commit ID or a formal patch
-backported, and CC Dave and other relevant networking developers.
+While it used to be the case that netdev submissions were not supposed
+to carry explicit ``CC: stable@vger.kernel.org`` tags that is no longer
+the case today. Please follow the standard stable rules in
+:ref:`Documentation/process/stable-kernel-rules.rst <stable_kernel_rules>`,
+and make sure you include appropriate Fixes tags!
 
 Is the comment style convention different for the networking content?
 ---------------------------------------------------------------------
index 3973556..003c865 100644 (file)
@@ -35,12 +35,6 @@ Rules on what kind of patches are accepted, and which ones are not, into the
 Procedure for submitting patches to the -stable tree
 ----------------------------------------------------
 
- - If the patch covers files in net/ or drivers/net please follow netdev stable
-   submission guidelines as described in
-   :ref:`Documentation/networking/netdev-FAQ.rst <netdev-FAQ>`
-   after first checking the stable networking queue at
-   https://patchwork.kernel.org/bundle/netdev/stable/?state=*
-   to ensure the requested patch is not already queued up.
  - Security patches should not be handled (solely) by the -stable review
    process but should follow the procedures in
    :ref:`Documentation/admin-guide/security-bugs.rst <securitybugs>`.
index 8c991c8..91de63b 100644 (file)
@@ -250,11 +250,6 @@ should also read
 :ref:`Documentation/process/stable-kernel-rules.rst <stable_kernel_rules>`
 in addition to this file.
 
-Note, however, that some subsystem maintainers want to come to their own
-conclusions on which patches should go to the stable trees.  The networking
-maintainer, in particular, would rather not see individual developers
-adding lines like the above to their patches.
-
 If changes affect userland-kernel interfaces, please send the MAN-PAGES
 maintainer (as listed in the MAINTAINERS file) a man-pages patch, or at
 least a notification of the change, so that some information makes its way
index 1a2b521..307f2fc 100644 (file)
@@ -182,6 +182,9 @@ is dependent on the CPU capability and the kernel configuration. The limit can
 be retrieved using KVM_CAP_ARM_VM_IPA_SIZE of the KVM_CHECK_EXTENSION
 ioctl() at run-time.
 
+Creation of the VM will fail if the requested IPA size (whether it is
+implicit or explicit) is unsupported on the host.
+
 Please note that configuring the IPA size does not affect the capability
 exposed by the guest CPUs in ID_AA64MMFR0_EL1[PARange]. It only affects
 size of the address translated by the stage2 level (guest physical to
@@ -1492,7 +1495,8 @@ Fails if any VCPU has already been created.
 
 Define which vcpu is the Bootstrap Processor (BSP).  Values are the same
 as the vcpu id in KVM_CREATE_VCPU.  If this ioctl is not called, the default
-is vcpu 0.
+is vcpu 0. This ioctl has to be called before vcpu creation,
+otherwise it will return EBUSY error.
 
 
 4.42 KVM_GET_XSAVE
@@ -4803,8 +4807,10 @@ If an MSR access is not permitted through the filtering, it generates a
 allows user space to deflect and potentially handle various MSR accesses
 into user space.
 
-If a vCPU is in running state while this ioctl is invoked, the vCPU may
-experience inconsistent filtering behavior on MSR accesses.
+Note, invoking this ioctl with a vCPU is running is inherently racy.  However,
+KVM does guarantee that vCPUs will see either the previous filter or the new
+filter, e.g. MSRs with identical settings in both the old and new filter will
+have deterministic behavior.
 
 4.127 KVM_XEN_HVM_SET_ATTR
 --------------------------
index 9f8a05a..0386d7f 100644 (file)
@@ -261,8 +261,8 @@ ABI/API
 L:     linux-api@vger.kernel.org
 F:     include/linux/syscalls.h
 F:     kernel/sys_ni.c
-F:     include/uapi/
-F:     arch/*/include/uapi/
+X:     include/uapi/
+X:     arch/*/include/uapi/
 
 ABIT UGURU 1,2 HARDWARE MONITOR DRIVER
 M:     Hans de Goede <hdegoede@redhat.com>
@@ -1181,7 +1181,7 @@ M:        Joel Fernandes <joel@joelfernandes.org>
 M:     Christian Brauner <christian@brauner.io>
 M:     Hridya Valsaraju <hridya@google.com>
 M:     Suren Baghdasaryan <surenb@google.com>
-L:     devel@driverdev.osuosl.org
+L:     linux-kernel@vger.kernel.org
 S:     Supported
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
 F:     drivers/android/
@@ -2856,6 +2856,18 @@ W:       http://www.openaoe.org/
 F:     Documentation/admin-guide/aoe/
 F:     drivers/block/aoe/
 
+ATC260X PMIC MFD DRIVER
+M:     Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+M:     Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
+L:     linux-actions@lists.infradead.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/mfd/actions,atc260x.yaml
+F:     drivers/input/misc/atc260x-onkey.c
+F:     drivers/mfd/atc260*
+F:     drivers/power/reset/atc260x-poweroff.c
+F:     drivers/regulator/atc260x-regulator.c
+F:     include/linux/mfd/atc260x/*
+
 ATHEROS 71XX/9XXX GPIO DRIVER
 M:     Alban Bedel <albeu@free.fr>
 S:     Maintained
@@ -5835,7 +5847,7 @@ M:        David Airlie <airlied@linux.ie>
 M:     Daniel Vetter <daniel@ffwll.ch>
 L:     dri-devel@lists.freedesktop.org
 S:     Maintained
-B:     https://bugs.freedesktop.org/
+B:     https://gitlab.freedesktop.org/drm
 C:     irc://chat.freenode.net/dri-devel
 T:     git git://anongit.freedesktop.org/drm/drm
 F:     Documentation/devicetree/bindings/display/
@@ -8116,7 +8128,6 @@ F:        drivers/crypto/hisilicon/sec2/sec_main.c
 
 HISILICON STAGING DRIVERS FOR HIKEY 960/970
 M:     Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
-L:     devel@driverdev.osuosl.org
 S:     Maintained
 F:     drivers/staging/hikey9xx/
 
@@ -10716,7 +10727,8 @@ F:      drivers/net/ethernet/marvell/mvpp2/
 
 MARVELL MWIFIEX WIRELESS DRIVER
 M:     Amitkumar Karwar <amitkarwar@gmail.com>
-M:     Ganapathi Bhat <ganapathi.bhat@nxp.com>
+M:     Ganapathi Bhat <ganapathi017@gmail.com>
+M:     Sharvari Harisangam <sharvari.harisangam@nxp.com>
 M:     Xinming Hu <huxinming820@gmail.com>
 L:     linux-wireless@vger.kernel.org
 S:     Maintained
@@ -15461,18 +15473,21 @@ F:    Documentation/devicetree/bindings/mfd/rohm,bd70528-pmic.txt
 F:     Documentation/devicetree/bindings/regulator/rohm,bd70528-regulator.txt
 F:     drivers/clk/clk-bd718x7.c
 F:     drivers/gpio/gpio-bd70528.c
+F:     drivers/gpio/gpio-bd71815.c
 F:     drivers/gpio/gpio-bd71828.c
 F:     drivers/mfd/rohm-bd70528.c
 F:     drivers/mfd/rohm-bd71828.c
 F:     drivers/mfd/rohm-bd718x7.c
 F:     drivers/power/supply/bd70528-charger.c
 F:     drivers/regulator/bd70528-regulator.c
+F:     drivers/regulator/bd71815-regulator.c
 F:     drivers/regulator/bd71828-regulator.c
 F:     drivers/regulator/bd718x7-regulator.c
 F:     drivers/regulator/rohm-regulator.c
 F:     drivers/rtc/rtc-bd70528.c
 F:     drivers/watchdog/bd70528_wdt.c
 F:     include/linux/mfd/rohm-bd70528.h
+F:     include/linux/mfd/rohm-bd71815.h
 F:     include/linux/mfd/rohm-bd71828.h
 F:     include/linux/mfd/rohm-bd718x7.h
 F:     include/linux/mfd/rohm-generic.h
@@ -17048,7 +17063,7 @@ F:      drivers/staging/vt665?/
 
 STAGING SUBSYSTEM
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-L:     devel@driverdev.osuosl.org
+L:     linux-staging@lists.linux.dev
 S:     Supported
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
 F:     drivers/staging/
@@ -19143,7 +19158,7 @@ VME SUBSYSTEM
 M:     Martyn Welch <martyn@welchs.me.uk>
 M:     Manohar Vanga <manohar.vanga@gmail.com>
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-L:     devel@driverdev.osuosl.org
+L:     linux-kernel@vger.kernel.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git
 F:     Documentation/driver-api/vme.rst
@@ -19174,7 +19189,7 @@ S:      Maintained
 F:     drivers/infiniband/hw/vmw_pvrdma/
 
 VMware PVSCSI driver
-M:     Jim Gill <jgill@vmware.com>
+M:     Vishal Bhakta <vbhakta@vmware.com>
 M:     VMware PV-Drivers <pv-drivers@vmware.com>
 L:     linux-scsi@vger.kernel.org
 S:     Maintained
@@ -19387,7 +19402,6 @@ F:      Documentation/devicetree/bindings/sound/wlf,arizona.yaml
 F:     Documentation/hwmon/wm83??.rst
 F:     arch/arm/mach-s3c/mach-crag6410*
 F:     drivers/clk/clk-wm83*.c
-F:     drivers/extcon/extcon-arizona.c
 F:     drivers/gpio/gpio-*wm*.c
 F:     drivers/gpio/gpio-arizona.c
 F:     drivers/hwmon/wm83??-hwmon.c
@@ -19411,7 +19425,7 @@ F:      include/linux/mfd/wm8400*
 F:     include/linux/regulator/arizona*
 F:     include/linux/wm97xx.h
 F:     include/sound/wm????.h
-F:     sound/soc/codecs/arizona.?
+F:     sound/soc/codecs/arizona*
 F:     sound/soc/codecs/cs47l24*
 F:     sound/soc/codecs/wm*
 
index 31dcdb3..d4784d1 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 VERSION = 5
 PATCHLEVEL = 12
 SUBLEVEL = 0
-EXTRAVERSION = -rc2
+EXTRAVERSION = -rc4
 NAME = Frozen Wasteland
 
 # *DOCUMENTATION*
@@ -264,7 +264,8 @@ no-dot-config-targets := $(clean-targets) \
                         $(version_h) headers headers_% archheaders archscripts \
                         %asm-generic kernelversion %src-pkg dt_binding_check \
                         outputmakefile
-no-sync-config-targets := $(no-dot-config-targets) %install kernelrelease
+no-sync-config-targets := $(no-dot-config-targets) %install kernelrelease \
+                         image_name
 single-targets := %.a %.i %.ko %.lds %.ll %.lst %.mod %.o %.s %.symtypes %/
 
 config-build   :=
@@ -478,6 +479,7 @@ USERINCLUDE    := \
                -I$(objtree)/arch/$(SRCARCH)/include/generated/uapi \
                -I$(srctree)/include/uapi \
                -I$(objtree)/include/generated/uapi \
+                -include $(srctree)/include/linux/compiler-version.h \
                 -include $(srctree)/include/linux/kconfig.h
 
 # Use LINUXINCLUDE when you must reference the include/ directory.
index 2bb3067..ecfd352 100644 (file)
@@ -632,13 +632,12 @@ config HAS_LTO_CLANG
        def_bool y
        # Clang >= 11: https://github.com/ClangBuiltLinux/linux/issues/510
        depends on CC_IS_CLANG && CLANG_VERSION >= 110000 && LD_IS_LLD
-       depends on $(success,test $(LLVM) -eq 1)
        depends on $(success,test $(LLVM_IAS) -eq 1)
        depends on $(success,$(NM) --help | head -n 1 | grep -qi llvm)
        depends on $(success,$(AR) --help | head -n 1 | grep -qi llvm)
        depends on ARCH_SUPPORTS_LTO_CLANG
        depends on !FTRACE_MCOUNT_USE_RECORDMCOUNT
-       depends on !KASAN
+       depends on !KASAN || KASAN_HW_TAGS
        depends on !GCOV_KERNEL
        help
          The compiler and Kconfig options support building with Clang's
index 853aab5..5da96f5 100644 (file)
@@ -348,6 +348,7 @@ config ARCH_EP93XX
        select ARM_AMBA
        imply ARM_PATCH_PHYS_VIRT
        select ARM_VIC
+       select GENERIC_IRQ_MULTI_HANDLER
        select AUTO_ZRELADDR
        select CLKDEV_LOOKUP
        select CLKSRC_MMIO
index acb4645..84a1cea 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <xen/xen.h>
 #include <xen/interface/memory.h>
+#include <xen/grant_table.h>
 #include <xen/page.h>
 #include <xen/swiotlb-xen.h>
 
@@ -109,7 +110,7 @@ int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops,
                map_ops[i].status = GNTST_general_error;
                unmap.host_addr = map_ops[i].host_addr,
                unmap.handle = map_ops[i].handle;
-               map_ops[i].handle = ~0;
+               map_ops[i].handle = INVALID_GRANT_HANDLE;
                if (map_ops[i].flags & GNTMAP_device_map)
                        unmap.dev_bus_addr = map_ops[i].dev_bus_addr;
                else
@@ -130,7 +131,6 @@ int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops,
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(set_foreign_p2m_mapping);
 
 int clear_foreign_p2m_mapping(struct gnttab_unmap_grant_ref *unmap_ops,
                              struct gnttab_unmap_grant_ref *kunmap_ops,
@@ -145,7 +145,6 @@ int clear_foreign_p2m_mapping(struct gnttab_unmap_grant_ref *unmap_ops,
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(clear_foreign_p2m_mapping);
 
 bool __set_phys_to_machine_multi(unsigned long pfn,
                unsigned long mfn, unsigned long nr_pages)
index 1f212b4..5656e7a 100644 (file)
@@ -1055,8 +1055,6 @@ config HW_PERF_EVENTS
 config SYS_SUPPORTS_HUGETLBFS
        def_bool y
 
-config ARCH_WANT_HUGE_PMD_SHARE
-
 config ARCH_HAS_CACHE_LINE_SIZE
        def_bool y
 
@@ -1157,8 +1155,8 @@ config XEN
 
 config FORCE_MAX_ZONEORDER
        int
-       default "14" if (ARM64_64K_PAGES && TRANSPARENT_HUGEPAGE)
-       default "12" if (ARM64_16K_PAGES && TRANSPARENT_HUGEPAGE)
+       default "14" if ARM64_64K_PAGES
+       default "12" if ARM64_16K_PAGES
        default "11"
        help
          The kernel memory allocator divides physically contiguous memory
@@ -1855,12 +1853,6 @@ config CMDLINE_FROM_BOOTLOADER
          the boot loader doesn't provide any, the default kernel command
          string provided in CMDLINE will be used.
 
-config CMDLINE_EXTEND
-       bool "Extend bootloader kernel arguments"
-       help
-         The command-line arguments provided by the boot loader will be
-         appended to the default kernel command string.
-
 config CMDLINE_FORCE
        bool "Always use the default kernel command string"
        help
index 22d933e..a7ab84f 100644 (file)
 #define __KVM_HOST_SMCCC_FUNC___kvm_flush_vm_context           2
 #define __KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_vmid_ipa         3
 #define __KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_vmid             4
-#define __KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_local_vmid       5
+#define __KVM_HOST_SMCCC_FUNC___kvm_flush_cpu_context          5
 #define __KVM_HOST_SMCCC_FUNC___kvm_timer_set_cntvoff          6
 #define __KVM_HOST_SMCCC_FUNC___kvm_enable_ssbs                        7
-#define __KVM_HOST_SMCCC_FUNC___vgic_v3_get_ich_vtr_el2                8
+#define __KVM_HOST_SMCCC_FUNC___vgic_v3_get_gic_config         8
 #define __KVM_HOST_SMCCC_FUNC___vgic_v3_read_vmcr              9
 #define __KVM_HOST_SMCCC_FUNC___vgic_v3_write_vmcr             10
 #define __KVM_HOST_SMCCC_FUNC___vgic_v3_init_lrs               11
@@ -183,16 +183,16 @@ DECLARE_KVM_HYP_SYM(__bp_harden_hyp_vecs);
 #define __bp_harden_hyp_vecs   CHOOSE_HYP_SYM(__bp_harden_hyp_vecs)
 
 extern void __kvm_flush_vm_context(void);
+extern void __kvm_flush_cpu_context(struct kvm_s2_mmu *mmu);
 extern void __kvm_tlb_flush_vmid_ipa(struct kvm_s2_mmu *mmu, phys_addr_t ipa,
                                     int level);
 extern void __kvm_tlb_flush_vmid(struct kvm_s2_mmu *mmu);
-extern void __kvm_tlb_flush_local_vmid(struct kvm_s2_mmu *mmu);
 
 extern void __kvm_timer_set_cntvoff(u64 cntvoff);
 
 extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
 
-extern u64 __vgic_v3_get_ich_vtr_el2(void);
+extern u64 __vgic_v3_get_gic_config(void);
 extern u64 __vgic_v3_read_vmcr(void);
 extern void __vgic_v3_write_vmcr(u32 vmcr);
 extern void __vgic_v3_init_lrs(void);
index c045082..32ae676 100644 (file)
@@ -83,6 +83,11 @@ void sysreg_restore_guest_state_vhe(struct kvm_cpu_context *ctxt);
 void __debug_switch_to_guest(struct kvm_vcpu *vcpu);
 void __debug_switch_to_host(struct kvm_vcpu *vcpu);
 
+#ifdef __KVM_NVHE_HYPERVISOR__
+void __debug_save_host_buffers_nvhe(struct kvm_vcpu *vcpu);
+void __debug_restore_host_buffers_nvhe(struct kvm_vcpu *vcpu);
+#endif
+
 void __fpsimd_save_state(struct user_fpsimd_state *fp_regs);
 void __fpsimd_restore_state(struct user_fpsimd_state *fp_regs);
 
@@ -97,7 +102,8 @@ bool kvm_host_psci_handler(struct kvm_cpu_context *host_ctxt);
 
 void __noreturn hyp_panic(void);
 #ifdef __KVM_NVHE_HYPERVISOR__
-void __noreturn __hyp_do_panic(bool restore_host, u64 spsr, u64 elr, u64 par);
+void __noreturn __hyp_do_panic(struct kvm_cpu_context *host_ctxt, u64 spsr,
+                              u64 elr, u64 par);
 #endif
 
 #endif /* __ARM64_KVM_HYP_H__ */
index c759faf..0aabc3b 100644 (file)
@@ -328,6 +328,11 @@ static inline void *phys_to_virt(phys_addr_t x)
 #define ARCH_PFN_OFFSET                ((unsigned long)PHYS_PFN_OFFSET)
 
 #if !defined(CONFIG_SPARSEMEM_VMEMMAP) || defined(CONFIG_DEBUG_VIRTUAL)
+#define page_to_virt(x)        ({                                              \
+       __typeof__(x) __page = x;                                       \
+       void *__addr = __va(page_to_phys(__page));                      \
+       (void *)__tag_set((const void *)__addr, page_kasan_tag(__page));\
+})
 #define virt_to_page(x)                pfn_to_page(virt_to_pfn(x))
 #else
 #define page_to_virt(x)        ({                                              \
index 70ce8c1..bd02e99 100644 (file)
@@ -63,23 +63,6 @@ static inline void cpu_switch_mm(pgd_t *pgd, struct mm_struct *mm)
 extern u64 idmap_t0sz;
 extern u64 idmap_ptrs_per_pgd;
 
-static inline bool __cpu_uses_extended_idmap(void)
-{
-       if (IS_ENABLED(CONFIG_ARM64_VA_BITS_52))
-               return false;
-
-       return unlikely(idmap_t0sz != TCR_T0SZ(VA_BITS));
-}
-
-/*
- * True if the extended ID map requires an extra level of translation table
- * to be configured.
- */
-static inline bool __cpu_uses_extended_idmap_level(void)
-{
-       return ARM64_HW_PGTABLE_LEVELS(64 - idmap_t0sz) > CONFIG_PGTABLE_LEVELS;
-}
-
 /*
  * Ensure TCR.T0SZ is set to the provided value.
  */
index 046be78..9a65fb5 100644 (file)
@@ -66,7 +66,6 @@ extern bool arm64_use_ng_mappings;
 #define _PAGE_DEFAULT          (_PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL))
 
 #define PAGE_KERNEL            __pgprot(PROT_NORMAL)
-#define PAGE_KERNEL_TAGGED     __pgprot(PROT_NORMAL_TAGGED)
 #define PAGE_KERNEL_RO         __pgprot((PROT_NORMAL & ~PTE_WRITE) | PTE_RDONLY)
 #define PAGE_KERNEL_ROX                __pgprot((PROT_NORMAL & ~(PTE_WRITE | PTE_PXN)) | PTE_RDONLY)
 #define PAGE_KERNEL_EXEC       __pgprot(PROT_NORMAL & ~PTE_PXN)
index e17b96d..4702779 100644 (file)
@@ -486,6 +486,9 @@ static inline pmd_t pmd_mkdevmap(pmd_t pmd)
        __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC) | PTE_PXN | PTE_UXN)
 #define pgprot_device(prot) \
        __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRE) | PTE_PXN | PTE_UXN)
+#define pgprot_tagged(prot) \
+       __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_TAGGED))
+#define pgprot_mhp     pgprot_tagged
 /*
  * DMA allocations for non-coherent devices use what the Arm architecture calls
  * "Normal non-cacheable" memory, which permits speculation, unaligned accesses
index dfd4edb..d4a5fca 100644 (file)
 #define ID_AA64MMFR0_PARANGE_48                0x5
 #define ID_AA64MMFR0_PARANGE_52                0x6
 
+#define ID_AA64MMFR0_TGRAN_2_SUPPORTED_DEFAULT 0x0
+#define ID_AA64MMFR0_TGRAN_2_SUPPORTED_NONE    0x1
+#define ID_AA64MMFR0_TGRAN_2_SUPPORTED_MIN     0x2
+#define ID_AA64MMFR0_TGRAN_2_SUPPORTED_MAX     0x7
+
 #ifdef CONFIG_ARM64_PA_BITS_52
 #define ID_AA64MMFR0_PARANGE_MAX       ID_AA64MMFR0_PARANGE_52
 #else
 #define ID_PFR1_PROGMOD_SHIFT          0
 
 #if defined(CONFIG_ARM64_4K_PAGES)
-#define ID_AA64MMFR0_TGRAN_SHIFT       ID_AA64MMFR0_TGRAN4_SHIFT
-#define ID_AA64MMFR0_TGRAN_SUPPORTED   ID_AA64MMFR0_TGRAN4_SUPPORTED
+#define ID_AA64MMFR0_TGRAN_SHIFT               ID_AA64MMFR0_TGRAN4_SHIFT
+#define ID_AA64MMFR0_TGRAN_SUPPORTED_MIN       ID_AA64MMFR0_TGRAN4_SUPPORTED
+#define ID_AA64MMFR0_TGRAN_SUPPORTED_MAX       0x7
 #elif defined(CONFIG_ARM64_16K_PAGES)
-#define ID_AA64MMFR0_TGRAN_SHIFT       ID_AA64MMFR0_TGRAN16_SHIFT
-#define ID_AA64MMFR0_TGRAN_SUPPORTED   ID_AA64MMFR0_TGRAN16_SUPPORTED
+#define ID_AA64MMFR0_TGRAN_SHIFT               ID_AA64MMFR0_TGRAN16_SHIFT
+#define ID_AA64MMFR0_TGRAN_SUPPORTED_MIN       ID_AA64MMFR0_TGRAN16_SUPPORTED
+#define ID_AA64MMFR0_TGRAN_SUPPORTED_MAX       0xF
 #elif defined(CONFIG_ARM64_64K_PAGES)
-#define ID_AA64MMFR0_TGRAN_SHIFT       ID_AA64MMFR0_TGRAN64_SHIFT
-#define ID_AA64MMFR0_TGRAN_SUPPORTED   ID_AA64MMFR0_TGRAN64_SUPPORTED
+#define ID_AA64MMFR0_TGRAN_SHIFT               ID_AA64MMFR0_TGRAN64_SHIFT
+#define ID_AA64MMFR0_TGRAN_SUPPORTED_MIN       ID_AA64MMFR0_TGRAN64_SUPPORTED
+#define ID_AA64MMFR0_TGRAN_SUPPORTED_MAX       0x7
 #endif
 
 #define MVFR2_FPMISC_SHIFT             4
index 66b0e0b..840bda1 100644 (file)
@@ -319,7 +319,7 @@ SYM_FUNC_START_LOCAL(__create_page_tables)
         */
        adrp    x5, __idmap_text_end
        clz     x5, x5
-       cmp     x5, TCR_T0SZ(VA_BITS)   // default T0SZ small enough?
+       cmp     x5, TCR_T0SZ(VA_BITS_MIN) // default T0SZ small enough?
        b.ge    1f                      // .. then skip VA range extension
 
        adr_l   x6, idmap_t0sz
@@ -655,8 +655,10 @@ SYM_FUNC_END(__secondary_too_slow)
 SYM_FUNC_START(__enable_mmu)
        mrs     x2, ID_AA64MMFR0_EL1
        ubfx    x2, x2, #ID_AA64MMFR0_TGRAN_SHIFT, 4
-       cmp     x2, #ID_AA64MMFR0_TGRAN_SUPPORTED
-       b.ne    __no_granule_support
+       cmp     x2, #ID_AA64MMFR0_TGRAN_SUPPORTED_MIN
+       b.lt    __no_granule_support
+       cmp     x2, #ID_AA64MMFR0_TGRAN_SUPPORTED_MAX
+       b.gt    __no_granule_support
        update_early_cpu_boot_status 0, x2, x3
        adrp    x2, idmap_pg_dir
        phys_to_ttbr x1, x1
index dffb166..83f1c4b 100644 (file)
@@ -163,33 +163,36 @@ static __init void __parse_cmdline(const char *cmdline, bool parse_aliases)
        } while (1);
 }
 
-static __init void parse_cmdline(void)
+static __init const u8 *get_bootargs_cmdline(void)
 {
-       if (!IS_ENABLED(CONFIG_CMDLINE_FORCE)) {
-               const u8 *prop;
-               void *fdt;
-               int node;
+       const u8 *prop;
+       void *fdt;
+       int node;
 
-               fdt = get_early_fdt_ptr();
-               if (!fdt)
-                       goto out;
+       fdt = get_early_fdt_ptr();
+       if (!fdt)
+               return NULL;
 
-               node = fdt_path_offset(fdt, "/chosen");
-               if (node < 0)
-                       goto out;
+       node = fdt_path_offset(fdt, "/chosen");
+       if (node < 0)
+               return NULL;
 
-               prop = fdt_getprop(fdt, node, "bootargs", NULL);
-               if (!prop)
-                       goto out;
+       prop = fdt_getprop(fdt, node, "bootargs", NULL);
+       if (!prop)
+               return NULL;
 
-               __parse_cmdline(prop, true);
+       return strlen(prop) ? prop : NULL;
+}
 
-               if (!IS_ENABLED(CONFIG_CMDLINE_EXTEND))
-                       return;
-       }
+static __init void parse_cmdline(void)
+{
+       const u8 *prop = get_bootargs_cmdline();
 
-out:
-       __parse_cmdline(CONFIG_CMDLINE, true);
+       if (IS_ENABLED(CONFIG_CMDLINE_FORCE) || !prop)
+               __parse_cmdline(CONFIG_CMDLINE, true);
+
+       if (!IS_ENABLED(CONFIG_CMDLINE_FORCE) && prop)
+               __parse_cmdline(prop, true);
 }
 
 /* Keep checkers quiet */
index 23f1a55..5aa9ed1 100644 (file)
@@ -101,6 +101,9 @@ KVM_NVHE_ALIAS(__stop___kvm_ex_table);
 /* Array containing bases of nVHE per-CPU memory regions. */
 KVM_NVHE_ALIAS(kvm_arm_hyp_percpu_base);
 
+/* PMU available static key */
+KVM_NVHE_ALIAS(kvm_arm_pmu_available);
+
 #endif /* CONFIG_KVM */
 
 #endif /* __ARM64_KERNEL_IMAGE_VARS_H */
index 7d2318f..4658fcf 100644 (file)
@@ -460,7 +460,7 @@ static inline int armv8pmu_counter_has_overflowed(u32 pmnc, int idx)
        return pmnc & BIT(ARMV8_IDX_TO_COUNTER(idx));
 }
 
-static inline u32 armv8pmu_read_evcntr(int idx)
+static inline u64 armv8pmu_read_evcntr(int idx)
 {
        u32 counter = ARMV8_IDX_TO_COUNTER(idx);
 
index fc4c95d..7f06ba7 100644 (file)
@@ -385,11 +385,16 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
        last_ran = this_cpu_ptr(mmu->last_vcpu_ran);
 
        /*
+        * We guarantee that both TLBs and I-cache are private to each
+        * vcpu. If detecting that a vcpu from the same VM has
+        * previously run on the same physical CPU, call into the
+        * hypervisor code to nuke the relevant contexts.
+        *
         * We might get preempted before the vCPU actually runs, but
         * over-invalidation doesn't affect correctness.
         */
        if (*last_ran != vcpu->vcpu_id) {
-               kvm_call_hyp(__kvm_tlb_flush_local_vmid, mmu);
+               kvm_call_hyp(__kvm_flush_cpu_context, mmu);
                *last_ran = vcpu->vcpu_id;
        }
 
index b0afad7..e831d3d 100644 (file)
@@ -85,8 +85,10 @@ SYM_INNER_LABEL(__guest_exit_panic, SYM_L_GLOBAL)
 
        // If the hyp context is loaded, go straight to hyp_panic
        get_loaded_vcpu x0, x1
-       cbz     x0, hyp_panic
+       cbnz    x0, 1f
+       b       hyp_panic
 
+1:
        // The hyp context is saved so make sure it is restored to allow
        // hyp_panic to run at hyp and, subsequently, panic to run in the host.
        // This makes use of __guest_exit to avoid duplication but sets the
@@ -94,7 +96,7 @@ SYM_INNER_LABEL(__guest_exit_panic, SYM_L_GLOBAL)
        // current state is saved to the guest context but it will only be
        // accurate if the guest had been completely restored.
        adr_this_cpu x0, kvm_hyp_ctxt, x1
-       adr     x1, hyp_panic
+       adr_l   x1, hyp_panic
        str     x1, [x0, #CPU_XREG_OFFSET(30)]
 
        get_vcpu_ptr    x1, x0
@@ -146,7 +148,7 @@ SYM_INNER_LABEL(__guest_exit, SYM_L_GLOBAL)
        // Now restore the hyp regs
        restore_callee_saved_regs x2
 
-       set_loaded_vcpu xzr, x1, x2
+       set_loaded_vcpu xzr, x2, x3
 
 alternative_if ARM64_HAS_RAS_EXTN
        // If we have the RAS extensions we can consume a pending error
index 54f4860..6c1f51f 100644 (file)
@@ -90,15 +90,18 @@ static inline void __activate_traps_common(struct kvm_vcpu *vcpu)
         * counter, which could make a PMXEVCNTR_EL0 access UNDEF at
         * EL1 instead of being trapped to EL2.
         */
-       write_sysreg(0, pmselr_el0);
-       write_sysreg(ARMV8_PMU_USERENR_MASK, pmuserenr_el0);
+       if (kvm_arm_support_pmu_v3()) {
+               write_sysreg(0, pmselr_el0);
+               write_sysreg(ARMV8_PMU_USERENR_MASK, pmuserenr_el0);
+       }
        write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
 }
 
 static inline void __deactivate_traps_common(void)
 {
        write_sysreg(0, hstr_el2);
-       write_sysreg(0, pmuserenr_el0);
+       if (kvm_arm_support_pmu_v3())
+               write_sysreg(0, pmuserenr_el0);
 }
 
 static inline void ___activate_traps(struct kvm_vcpu *vcpu)
index 91a711a..f401724 100644 (file)
@@ -58,16 +58,24 @@ static void __debug_restore_spe(u64 pmscr_el1)
        write_sysreg_s(pmscr_el1, SYS_PMSCR_EL1);
 }
 
-void __debug_switch_to_guest(struct kvm_vcpu *vcpu)
+void __debug_save_host_buffers_nvhe(struct kvm_vcpu *vcpu)
 {
        /* Disable and flush SPE data generation */
        __debug_save_spe(&vcpu->arch.host_debug_state.pmscr_el1);
+}
+
+void __debug_switch_to_guest(struct kvm_vcpu *vcpu)
+{
        __debug_switch_to_guest_common(vcpu);
 }
 
-void __debug_switch_to_host(struct kvm_vcpu *vcpu)
+void __debug_restore_host_buffers_nvhe(struct kvm_vcpu *vcpu)
 {
        __debug_restore_spe(vcpu->arch.host_debug_state.pmscr_el1);
+}
+
+void __debug_switch_to_host(struct kvm_vcpu *vcpu)
+{
        __debug_switch_to_host_common(vcpu);
 }
 
index 6585a7c..5d94584 100644 (file)
@@ -71,7 +71,8 @@ SYM_FUNC_START(__host_enter)
 SYM_FUNC_END(__host_enter)
 
 /*
- * void __noreturn __hyp_do_panic(bool restore_host, u64 spsr, u64 elr, u64 par);
+ * void __noreturn __hyp_do_panic(struct kvm_cpu_context *host_ctxt, u64 spsr,
+ *                               u64 elr, u64 par);
  */
 SYM_FUNC_START(__hyp_do_panic)
        /* Prepare and exit to the host's panic funciton. */
@@ -82,9 +83,11 @@ SYM_FUNC_START(__hyp_do_panic)
        hyp_kimg_va lr, x6
        msr     elr_el2, lr
 
-       /* Set the panic format string. Use the, now free, LR as scratch. */
-       ldr     lr, =__hyp_panic_string
-       hyp_kimg_va lr, x6
+       mov     x29, x0
+
+       /* Load the format string into x0 and arguments into x1-7 */
+       ldr     x0, =__hyp_panic_string
+       hyp_kimg_va x0, x6
 
        /* Load the format arguments into x1-7. */
        mov     x6, x3
@@ -94,9 +97,7 @@ SYM_FUNC_START(__hyp_do_panic)
        mrs     x5, hpfar_el2
 
        /* Enter the host, conditionally restoring the host context. */
-       cmp     x0, xzr
-       mov     x0, lr
-       b.eq    __host_enter_without_restoring
+       cbz     x29, __host_enter_without_restoring
        b       __host_enter_for_panic
 SYM_FUNC_END(__hyp_do_panic)
 
index f012f86..9363282 100644 (file)
@@ -46,11 +46,11 @@ static void handle___kvm_tlb_flush_vmid(struct kvm_cpu_context *host_ctxt)
        __kvm_tlb_flush_vmid(kern_hyp_va(mmu));
 }
 
-static void handle___kvm_tlb_flush_local_vmid(struct kvm_cpu_context *host_ctxt)
+static void handle___kvm_flush_cpu_context(struct kvm_cpu_context *host_ctxt)
 {
        DECLARE_REG(struct kvm_s2_mmu *, mmu, host_ctxt, 1);
 
-       __kvm_tlb_flush_local_vmid(kern_hyp_va(mmu));
+       __kvm_flush_cpu_context(kern_hyp_va(mmu));
 }
 
 static void handle___kvm_timer_set_cntvoff(struct kvm_cpu_context *host_ctxt)
@@ -67,9 +67,9 @@ static void handle___kvm_enable_ssbs(struct kvm_cpu_context *host_ctxt)
        write_sysreg_el2(tmp, SYS_SCTLR);
 }
 
-static void handle___vgic_v3_get_ich_vtr_el2(struct kvm_cpu_context *host_ctxt)
+static void handle___vgic_v3_get_gic_config(struct kvm_cpu_context *host_ctxt)
 {
-       cpu_reg(host_ctxt, 1) = __vgic_v3_get_ich_vtr_el2();
+       cpu_reg(host_ctxt, 1) = __vgic_v3_get_gic_config();
 }
 
 static void handle___vgic_v3_read_vmcr(struct kvm_cpu_context *host_ctxt)
@@ -115,10 +115,10 @@ static const hcall_t host_hcall[] = {
        HANDLE_FUNC(__kvm_flush_vm_context),
        HANDLE_FUNC(__kvm_tlb_flush_vmid_ipa),
        HANDLE_FUNC(__kvm_tlb_flush_vmid),
-       HANDLE_FUNC(__kvm_tlb_flush_local_vmid),
+       HANDLE_FUNC(__kvm_flush_cpu_context),
        HANDLE_FUNC(__kvm_timer_set_cntvoff),
        HANDLE_FUNC(__kvm_enable_ssbs),
-       HANDLE_FUNC(__vgic_v3_get_ich_vtr_el2),
+       HANDLE_FUNC(__vgic_v3_get_gic_config),
        HANDLE_FUNC(__vgic_v3_read_vmcr),
        HANDLE_FUNC(__vgic_v3_write_vmcr),
        HANDLE_FUNC(__vgic_v3_init_lrs),
index f3d0e9e..68ab6b4 100644 (file)
@@ -192,6 +192,14 @@ int __kvm_vcpu_run(struct kvm_vcpu *vcpu)
        pmu_switch_needed = __pmu_switch_to_guest(host_ctxt);
 
        __sysreg_save_state_nvhe(host_ctxt);
+       /*
+        * We must flush and disable the SPE buffer for nVHE, as
+        * the translation regime(EL1&0) is going to be loaded with
+        * that of the guest. And we must do this before we change the
+        * translation regime to EL2 (via MDCR_EL2_E2PB == 0) and
+        * before we load guest Stage1.
+        */
+       __debug_save_host_buffers_nvhe(vcpu);
 
        __adjust_pc(vcpu);
 
@@ -234,11 +242,12 @@ int __kvm_vcpu_run(struct kvm_vcpu *vcpu)
        if (vcpu->arch.flags & KVM_ARM64_FP_ENABLED)
                __fpsimd_save_fpexc32(vcpu);
 
+       __debug_switch_to_host(vcpu);
        /*
         * This must come after restoring the host sysregs, since a non-VHE
         * system may enable SPE here and make use of the TTBRs.
         */
-       __debug_switch_to_host(vcpu);
+       __debug_restore_host_buffers_nvhe(vcpu);
 
        if (pmu_switch_needed)
                __pmu_switch_to_host(host_ctxt);
@@ -257,7 +266,6 @@ void __noreturn hyp_panic(void)
        u64 spsr = read_sysreg_el2(SYS_SPSR);
        u64 elr = read_sysreg_el2(SYS_ELR);
        u64 par = read_sysreg_par();
-       bool restore_host = true;
        struct kvm_cpu_context *host_ctxt;
        struct kvm_vcpu *vcpu;
 
@@ -271,7 +279,7 @@ void __noreturn hyp_panic(void)
                __sysreg_restore_state_nvhe(host_ctxt);
        }
 
-       __hyp_do_panic(restore_host, spsr, elr, par);
+       __hyp_do_panic(host_ctxt, spsr, elr, par);
        unreachable();
 }
 
index fbde89a..229b067 100644 (file)
@@ -123,7 +123,7 @@ void __kvm_tlb_flush_vmid(struct kvm_s2_mmu *mmu)
        __tlb_switch_to_host(&cxt);
 }
 
-void __kvm_tlb_flush_local_vmid(struct kvm_s2_mmu *mmu)
+void __kvm_flush_cpu_context(struct kvm_s2_mmu *mmu)
 {
        struct tlb_inv_context cxt;
 
@@ -131,6 +131,7 @@ void __kvm_tlb_flush_local_vmid(struct kvm_s2_mmu *mmu)
        __tlb_switch_to_guest(mmu, &cxt);
 
        __tlbi(vmalle1);
+       asm volatile("ic iallu");
        dsb(nsh);
        isb();
 
index 4d177ce..926fc07 100644 (file)
@@ -223,6 +223,7 @@ static inline int __kvm_pgtable_visit(struct kvm_pgtable_walk_data *data,
                goto out;
 
        if (!table) {
+               data->addr = ALIGN_DOWN(data->addr, kvm_granule_size(level));
                data->addr += kvm_granule_size(level);
                goto out;
        }
index 80406f4..ee3682b 100644 (file)
@@ -405,9 +405,45 @@ void __vgic_v3_init_lrs(void)
                __gic_v3_set_lr(0, i);
 }
 
-u64 __vgic_v3_get_ich_vtr_el2(void)
+/*
+ * Return the GIC CPU configuration:
+ * - [31:0]  ICH_VTR_EL2
+ * - [62:32] RES0
+ * - [63]    MMIO (GICv2) capable
+ */
+u64 __vgic_v3_get_gic_config(void)
 {
-       return read_gicreg(ICH_VTR_EL2);
+       u64 val, sre = read_gicreg(ICC_SRE_EL1);
+       unsigned long flags = 0;
+
+       /*
+        * To check whether we have a MMIO-based (GICv2 compatible)
+        * CPU interface, we need to disable the system register
+        * view. To do that safely, we have to prevent any interrupt
+        * from firing (which would be deadly).
+        *
+        * Note that this only makes sense on VHE, as interrupts are
+        * already masked for nVHE as part of the exception entry to
+        * EL2.
+        */
+       if (has_vhe())
+               flags = local_daif_save();
+
+       write_gicreg(0, ICC_SRE_EL1);
+       isb();
+
+       val = read_gicreg(ICC_SRE_EL1);
+
+       write_gicreg(sre, ICC_SRE_EL1);
+       isb();
+
+       if (has_vhe())
+               local_daif_restore(flags);
+
+       val  = (val & ICC_SRE_EL1_SRE) ? 0 : (1ULL << 63);
+       val |= read_gicreg(ICH_VTR_EL2);
+
+       return val;
 }
 
 u64 __vgic_v3_read_vmcr(void)
index fd78959..66f1734 100644 (file)
@@ -127,7 +127,7 @@ void __kvm_tlb_flush_vmid(struct kvm_s2_mmu *mmu)
        __tlb_switch_to_host(&cxt);
 }
 
-void __kvm_tlb_flush_local_vmid(struct kvm_s2_mmu *mmu)
+void __kvm_flush_cpu_context(struct kvm_s2_mmu *mmu)
 {
        struct tlb_inv_context cxt;
 
@@ -135,6 +135,7 @@ void __kvm_tlb_flush_local_vmid(struct kvm_s2_mmu *mmu)
        __tlb_switch_to_guest(mmu, &cxt);
 
        __tlbi(vmalle1);
+       asm volatile("ic iallu");
        dsb(nsh);
        isb();
 
index 77cb2d2..8711894 100644 (file)
@@ -1312,8 +1312,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
         * Prevent userspace from creating a memory region outside of the IPA
         * space addressable by the KVM guest IPA space.
         */
-       if (memslot->base_gfn + memslot->npages >=
-           (kvm_phys_size(kvm) >> PAGE_SHIFT))
+       if ((memslot->base_gfn + memslot->npages) > (kvm_phys_size(kvm) >> PAGE_SHIFT))
                return -EFAULT;
 
        mmap_read_lock(current->mm);
index d45b8b9..7391643 100644 (file)
@@ -11,6 +11,8 @@
 
 #include <asm/kvm_emulate.h>
 
+DEFINE_STATIC_KEY_FALSE(kvm_arm_pmu_available);
+
 static int kvm_is_in_guest(void)
 {
         return kvm_get_running_vcpu() != NULL;
@@ -48,6 +50,14 @@ static struct perf_guest_info_callbacks kvm_guest_cbs = {
 
 int kvm_perf_init(void)
 {
+       /*
+        * Check if HW_PERF_EVENTS are supported by checking the number of
+        * hardware performance counters. This could ensure the presence of
+        * a physical PMU and CONFIG_PERF_EVENT is selected.
+        */
+       if (IS_ENABLED(CONFIG_ARM_PMU) && perf_num_counters() > 0)
+               static_branch_enable(&kvm_arm_pmu_available);
+
        return perf_register_guest_info_callbacks(&kvm_guest_cbs);
 }
 
index e9ec08b..e32c6e1 100644 (file)
@@ -823,16 +823,6 @@ u64 kvm_pmu_get_pmceid(struct kvm_vcpu *vcpu, bool pmceid1)
        return val & mask;
 }
 
-bool kvm_arm_support_pmu_v3(void)
-{
-       /*
-        * Check if HW_PERF_EVENTS are supported by checking the number of
-        * hardware performance counters. This could ensure the presence of
-        * a physical PMU and CONFIG_PERF_EVENT is selected.
-        */
-       return (perf_num_counters() > 0);
-}
-
 int kvm_arm_pmu_v3_enable(struct kvm_vcpu *vcpu)
 {
        if (!kvm_vcpu_has_pmu(vcpu))
index 47f3f03..bd354cd 100644 (file)
@@ -311,23 +311,24 @@ int kvm_set_ipa_limit(void)
        }
 
        switch (cpuid_feature_extract_unsigned_field(mmfr0, tgran_2)) {
-       default:
-       case 1:
+       case ID_AA64MMFR0_TGRAN_2_SUPPORTED_NONE:
                kvm_err("PAGE_SIZE not supported at Stage-2, giving up\n");
                return -EINVAL;
-       case 0:
+       case ID_AA64MMFR0_TGRAN_2_SUPPORTED_DEFAULT:
                kvm_debug("PAGE_SIZE supported at Stage-2 (default)\n");
                break;
-       case 2:
+       case ID_AA64MMFR0_TGRAN_2_SUPPORTED_MIN ... ID_AA64MMFR0_TGRAN_2_SUPPORTED_MAX:
                kvm_debug("PAGE_SIZE supported at Stage-2 (advertised)\n");
                break;
+       default:
+               kvm_err("Unsupported value for TGRAN_2, giving up\n");
+               return -EINVAL;
        }
 
        kvm_ipa_limit = id_aa64mmfr0_parange_to_phys_shift(parange);
-       WARN(kvm_ipa_limit < KVM_PHYS_SHIFT,
-            "KVM IPA Size Limit (%d bits) is smaller than default size\n",
-            kvm_ipa_limit);
-       kvm_info("IPA Size Limit: %d bits\n", kvm_ipa_limit);
+       kvm_info("IPA Size Limit: %d bits%s\n", kvm_ipa_limit,
+                ((kvm_ipa_limit < KVM_PHYS_SHIFT) ?
+                 " (Reduced IPA size, limited VM/VMM compatibility)" : ""));
 
        return 0;
 }
@@ -356,6 +357,11 @@ int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type)
                        return -EINVAL;
        } else {
                phys_shift = KVM_PHYS_SHIFT;
+               if (phys_shift > kvm_ipa_limit) {
+                       pr_warn_once("%s using unsupported default IPA limit, upgrade your VMM\n",
+                                    current->comm);
+                       return -EINVAL;
+               }
        }
 
        mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
index 52915b3..6f53092 100644 (file)
@@ -574,9 +574,13 @@ early_param("kvm-arm.vgic_v4_enable", early_gicv4_enable);
  */
 int vgic_v3_probe(const struct gic_kvm_info *info)
 {
-       u32 ich_vtr_el2 = kvm_call_hyp_ret(__vgic_v3_get_ich_vtr_el2);
+       u64 ich_vtr_el2 = kvm_call_hyp_ret(__vgic_v3_get_gic_config);
+       bool has_v2;
        int ret;
 
+       has_v2 = ich_vtr_el2 >> 63;
+       ich_vtr_el2 = (u32)ich_vtr_el2;
+
        /*
         * The ListRegs field is 5 bits, but there is an architectural
         * maximum of 16 list registers. Just ignore bit 4...
@@ -594,13 +598,15 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
                         gicv4_enable ? "en" : "dis");
        }
 
+       kvm_vgic_global_state.vcpu_base = 0;
+
        if (!info->vcpu.start) {
                kvm_info("GICv3: no GICV resource entry\n");
-               kvm_vgic_global_state.vcpu_base = 0;
+       } else if (!has_v2) {
+               pr_warn(FW_BUG "CPU interface incapable of MMIO access\n");
        } else if (!PAGE_ALIGNED(info->vcpu.start)) {
                pr_warn("GICV physical address 0x%llx not page aligned\n",
                        (unsigned long long)info->vcpu.start);
-               kvm_vgic_global_state.vcpu_base = 0;
        } else {
                kvm_vgic_global_state.vcpu_base = info->vcpu.start;
                kvm_vgic_global_state.can_emulate_gicv2 = true;
index 0ace5e6..3685e12 100644 (file)
@@ -219,17 +219,40 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)
 
 int pfn_valid(unsigned long pfn)
 {
-       phys_addr_t addr = pfn << PAGE_SHIFT;
+       phys_addr_t addr = PFN_PHYS(pfn);
 
-       if ((addr >> PAGE_SHIFT) != pfn)
+       /*
+        * Ensure the upper PAGE_SHIFT bits are clear in the
+        * pfn. Else it might lead to false positives when
+        * some of the upper bits are set, but the lower bits
+        * match a valid pfn.
+        */
+       if (PHYS_PFN(addr) != pfn)
                return 0;
 
 #ifdef CONFIG_SPARSEMEM
+{
+       struct mem_section *ms;
+
        if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS)
                return 0;
 
-       if (!valid_section(__pfn_to_section(pfn)))
+       ms = __pfn_to_section(pfn);
+       if (!valid_section(ms))
                return 0;
+
+       /*
+        * ZONE_DEVICE memory does not have the memblock entries.
+        * memblock_is_map_memory() check for ZONE_DEVICE based
+        * addresses will always fail. Even the normal hotplugged
+        * memory will never have MEMBLOCK_NOMAP flag set in their
+        * memblock entries. Skip memblock search for all non early
+        * memory sections covering all of hotplug memory including
+        * both normal and ZONE_DEVICE based.
+        */
+       if (!early_section(ms))
+               return pfn_section_valid(ms, pfn);
+}
 #endif
        return memblock_is_map_memory(addr);
 }
index 3802cfb..7484ea4 100644 (file)
@@ -40,7 +40,7 @@
 #define NO_BLOCK_MAPPINGS      BIT(0)
 #define NO_CONT_MAPPINGS       BIT(1)
 
-u64 idmap_t0sz = TCR_T0SZ(VA_BITS);
+u64 idmap_t0sz = TCR_T0SZ(VA_BITS_MIN);
 u64 idmap_ptrs_per_pgd = PTRS_PER_PGD;
 
 u64 __section(".mmuoff.data.write") vabits_actual;
@@ -512,7 +512,8 @@ static void __init map_mem(pgd_t *pgdp)
                 * if MTE is present. Otherwise, it has the same attributes as
                 * PAGE_KERNEL.
                 */
-               __map_memblock(pgdp, start, end, PAGE_KERNEL_TAGGED, flags);
+               __map_memblock(pgdp, start, end, pgprot_tagged(PAGE_KERNEL),
+                              flags);
        }
 
        /*
index ae2b1c7..ef2bb9b 100644 (file)
@@ -9,7 +9,7 @@ int arch_check_ftrace_location(struct kprobe *p)
        return 0;
 }
 
-/* Ftrace callback handler for kprobes -- called under preepmt disabed */
+/* Ftrace callback handler for kprobes -- called under preepmt disabled */
 void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
                           struct ftrace_ops *ops, struct ftrace_regs *fregs)
 {
index 6c6f16e..0d23c00 100644 (file)
@@ -32,7 +32,7 @@ static inline void syscall_rollback(struct task_struct *task,
 static inline long syscall_get_error(struct task_struct *task,
                                     struct pt_regs *regs)
 {
-       return regs->r10 == -1 ? regs->r8:0;
+       return regs->r10 == -1 ? -regs->r8:0;
 }
 
 static inline long syscall_get_return_value(struct task_struct *task,
index c3490ee..e14f565 100644 (file)
@@ -2013,27 +2013,39 @@ static void syscall_get_set_args_cb(struct unw_frame_info *info, void *data)
 {
        struct syscall_get_set_args *args = data;
        struct pt_regs *pt = args->regs;
-       unsigned long *krbs, cfm, ndirty;
+       unsigned long *krbs, cfm, ndirty, nlocals, nouts;
        int i, count;
 
        if (unw_unwind_to_user(info) < 0)
                return;
 
+       /*
+        * We get here via a few paths:
+        * - break instruction: cfm is shared with caller.
+        *   syscall args are in out= regs, locals are non-empty.
+        * - epsinstruction: cfm is set by br.call
+        *   locals don't exist.
+        *
+        * For both cases argguments are reachable in cfm.sof - cfm.sol.
+        * CFM: [ ... | sor: 17..14 | sol : 13..7 | sof : 6..0 ]
+        */
        cfm = pt->cr_ifs;
+       nlocals = (cfm >> 7) & 0x7f; /* aka sol */
+       nouts = (cfm & 0x7f) - nlocals; /* aka sof - sol */
        krbs = (unsigned long *)info->task + IA64_RBS_OFFSET/8;
        ndirty = ia64_rse_num_regs(krbs, krbs + (pt->loadrs >> 19));
 
        count = 0;
        if (in_syscall(pt))
-               count = min_t(int, args->n, cfm & 0x7f);
+               count = min_t(int, args->n, nouts);
 
+       /* Iterate over outs. */
        for (i = 0; i < count; i++) {
+               int j = ndirty + nlocals + i + args->i;
                if (args->rw)
-                       *ia64_rse_skip_regs(krbs, ndirty + i + args->i) =
-                               args->args[i];
+                       *ia64_rse_skip_regs(krbs, j) = args->args[i];
                else
-                       args->args[i] = *ia64_rse_skip_regs(krbs,
-                               ndirty + i + args->i);
+                       args->args[i] = *ia64_rse_skip_regs(krbs, j);
        }
 
        if (!args->rw) {
index 7f5912a..9e8f0cc 100644 (file)
@@ -171,7 +171,7 @@ static inline __attribute_const__ int __virt_to_node_shift(void)
 #include <asm-generic/memory_model.h>
 #endif
 
-#define virt_addr_valid(kaddr) ((void *)(kaddr) >= (void *)PAGE_OFFSET && (void *)(kaddr) < high_memory)
+#define virt_addr_valid(kaddr) ((unsigned long)(kaddr) >= PAGE_OFFSET && (unsigned long)(kaddr) < (unsigned long)high_memory)
 #define pfn_valid(pfn)         virt_addr_valid(pfn_to_virt(pfn))
 
 #endif /* __ASSEMBLY__ */
index 6bbe520..8d0f862 100644 (file)
@@ -30,8 +30,8 @@ extern unsigned long memory_end;
 #define page_to_pfn(page)      virt_to_pfn(page_to_virt(page))
 #define pfn_valid(pfn)         ((pfn) < max_mapnr)
 
-#define        virt_addr_valid(kaddr)  (((void *)(kaddr) >= (void *)PAGE_OFFSET) && \
-                               ((void *)(kaddr) < (void *)memory_end))
+#define        virt_addr_valid(kaddr)  (((unsigned long)(kaddr) >= PAGE_OFFSET) && \
+                               ((unsigned long)(kaddr) < memory_end))
 
 #endif /* __ASSEMBLY__ */
 
index e3946b0..3d70d15 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <asm/addrspace.h>
 #include <asm/unaligned.h>
+#include <asm-generic/vmlinux.lds.h>
 
 /*
  * These two variables specify the free mem region
@@ -120,6 +121,13 @@ void decompress_kernel(unsigned long boot_heap_start)
                /* last four bytes is always image size in little endian */
                image_size = get_unaligned_le32((void *)&__image_end - 4);
 
+               /* The device tree's address must be properly aligned  */
+               image_size = ALIGN(image_size, STRUCT_ALIGNMENT);
+
+               puts("Copy device tree to address  ");
+               puthex(VMLINUX_LOAD_ADDRESS_ULL + image_size);
+               puts("\n");
+
                /* copy dtb to where the booted kernel will expect it */
                memcpy((void *)VMLINUX_LOAD_ADDRESS_ULL + image_size,
                       __appended_dtb, dtb_size);
index 8e1deaf..5e4105c 100644 (file)
@@ -12,8 +12,8 @@ AFLAGS_chacha-core.o += -O2 # needed to fill branch delay slots
 obj-$(CONFIG_CRYPTO_POLY1305_MIPS) += poly1305-mips.o
 poly1305-mips-y := poly1305-core.o poly1305-glue.o
 
-perlasm-flavour-$(CONFIG_CPU_MIPS32) := o32
-perlasm-flavour-$(CONFIG_CPU_MIPS64) := 64
+perlasm-flavour-$(CONFIG_32BIT) := o32
+perlasm-flavour-$(CONFIG_64BIT) := 64
 
 quiet_cmd_perlasm = PERLASM $@
       cmd_perlasm = $(PERL) $(<) $(perlasm-flavour-y) $(@)
index 6aa8f12..b710e76 100644 (file)
@@ -24,8 +24,11 @@ extern void (*board_ebase_setup)(void);
 extern void (*board_cache_error_setup)(void);
 
 extern int register_nmi_notifier(struct notifier_block *nb);
+extern void reserve_exception_space(phys_addr_t addr, unsigned long size);
 extern char except_vec_nmi[];
 
+#define VECTORSPACING 0x100    /* for EI/VI mode */
+
 #define nmi_notifier(fn, pri)                                          \
 ({                                                                     \
        static struct notifier_block fn##_nb = {                        \
index 9a89637..b718920 100644 (file)
@@ -26,6 +26,7 @@
 #include <asm/elf.h>
 #include <asm/pgtable-bits.h>
 #include <asm/spram.h>
+#include <asm/traps.h>
 #include <linux/uaccess.h>
 
 #include "fpu-probe.h"
@@ -1628,6 +1629,7 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu)
                c->cputype = CPU_BMIPS3300;
                __cpu_name[cpu] = "Broadcom BMIPS3300";
                set_elf_platform(cpu, "bmips3300");
+               reserve_exception_space(0x400, VECTORSPACING * 64);
                break;
        case PRID_IMP_BMIPS43XX: {
                int rev = c->processor_id & PRID_REV_MASK;
@@ -1638,6 +1640,7 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu)
                        __cpu_name[cpu] = "Broadcom BMIPS4380";
                        set_elf_platform(cpu, "bmips4380");
                        c->options |= MIPS_CPU_RIXI;
+                       reserve_exception_space(0x400, VECTORSPACING * 64);
                } else {
                        c->cputype = CPU_BMIPS4350;
                        __cpu_name[cpu] = "Broadcom BMIPS4350";
@@ -1654,6 +1657,7 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu)
                        __cpu_name[cpu] = "Broadcom BMIPS5000";
                set_elf_platform(cpu, "bmips5000");
                c->options |= MIPS_CPU_ULRI | MIPS_CPU_RIXI;
+               reserve_exception_space(0x1000, VECTORSPACING * 64);
                break;
        }
 }
@@ -2133,6 +2137,8 @@ void cpu_probe(void)
        if (cpu == 0)
                __ua_limit = ~((1ull << cpu_vmbits) - 1);
 #endif
+
+       reserve_exception_space(0, 0x1000);
 }
 
 void cpu_report(void)
index abdbbe8..af65477 100644 (file)
@@ -21,6 +21,7 @@
 #include <asm/fpu.h>
 #include <asm/mipsregs.h>
 #include <asm/elf.h>
+#include <asm/traps.h>
 
 #include "fpu-probe.h"
 
@@ -158,6 +159,8 @@ void cpu_probe(void)
                cpu_set_fpu_opts(c);
        else
                cpu_set_nofpu_opts(c);
+
+       reserve_exception_space(0, 0x400);
 }
 
 void cpu_report(void)
index e035295..808b8b6 100644 (file)
@@ -2009,13 +2009,16 @@ void __noreturn nmi_exception_handler(struct pt_regs *regs)
        nmi_exit();
 }
 
-#define VECTORSPACING 0x100    /* for EI/VI mode */
-
 unsigned long ebase;
 EXPORT_SYMBOL_GPL(ebase);
 unsigned long exception_handlers[32];
 unsigned long vi_handlers[64];
 
+void reserve_exception_space(phys_addr_t addr, unsigned long size)
+{
+       memblock_reserve(addr, size);
+}
+
 void __init *set_except_vector(int n, void *addr)
 {
        unsigned long handler = (unsigned long) addr;
@@ -2367,10 +2370,7 @@ void __init trap_init(void)
 
        if (!cpu_has_mips_r2_r6) {
                ebase = CAC_BASE;
-               ebase_pa = virt_to_phys((void *)ebase);
                vec_size = 0x400;
-
-               memblock_reserve(ebase_pa, vec_size);
        } else {
                if (cpu_has_veic || cpu_has_vint)
                        vec_size = 0x200 + VECTORSPACING*64;
index c1c345b..1f98947 100644 (file)
@@ -145,6 +145,7 @@ SECTIONS
        }
 
 #ifdef CONFIG_MIPS_ELF_APPENDED_DTB
+       STRUCT_ALIGN();
        .appended_dtb : AT(ADDR(.appended_dtb) - LOAD_OFFSET) {
                *(.appended_dtb)
                KEEP(*(.appended_dtb))
@@ -172,6 +173,11 @@ SECTIONS
 #endif
 
 #ifdef CONFIG_MIPS_RAW_APPENDED_DTB
+       .fill : {
+               FILL(0);
+               BYTE(0);
+               STRUCT_ALIGN();
+       }
        __appended_dtb = .;
        /* leave space for appended DTB */
        . += 0x100000;
index 4e53ac4..afc3b8d 100644 (file)
@@ -203,9 +203,12 @@ config PREFETCH
        def_bool y
        depends on PA8X00 || PA7200
 
+config PARISC_HUGE_KERNEL
+       def_bool y if !MODULES || UBSAN || FTRACE || COMPILE_TEST
+
 config MLONGCALLS
-       def_bool y if !MODULES || UBSAN || FTRACE
-       bool "Enable the -mlong-calls compiler option for big kernels" if MODULES && !UBSAN && !FTRACE
+       def_bool y if PARISC_HUGE_KERNEL
+       bool "Enable the -mlong-calls compiler option for big kernels" if !PARISC_HUGE_KERNEL
        depends on PA8X00
        help
          If you configure the kernel to include many drivers built-in instead
index 2127974..65de6c4 100644 (file)
@@ -567,8 +567,6 @@ static const struct user_regset_view user_parisc_native_view = {
 };
 
 #ifdef CONFIG_64BIT
-#include <linux/compat.h>
-
 static int gpr32_get(struct task_struct *target,
                     const struct user_regset *regset,
                     struct membuf to)
index eacc910..f1d029b 100644 (file)
@@ -73,9 +73,10 @@ void __patch_exception(int exc, unsigned long addr);
 #endif
 
 #define OP_RT_RA_MASK  0xffff0000UL
-#define LIS_R2         0x3c020000UL
-#define ADDIS_R2_R12   0x3c4c0000UL
-#define ADDI_R2_R2     0x38420000UL
+#define LIS_R2         (PPC_INST_ADDIS | __PPC_RT(R2))
+#define ADDIS_R2_R12   (PPC_INST_ADDIS | __PPC_RT(R2) | __PPC_RA(R12))
+#define ADDI_R2_R2     (PPC_INST_ADDI  | __PPC_RT(R2) | __PPC_RA(R2))
+
 
 static inline unsigned long ppc_function_entry(void *func)
 {
index 7897d16..727d4b3 100644 (file)
@@ -7,7 +7,7 @@
 #include <linux/bug.h>
 #include <asm/cputable.h>
 
-static inline bool early_cpu_has_feature(unsigned long feature)
+static __always_inline bool early_cpu_has_feature(unsigned long feature)
 {
        return !!((CPU_FTRS_ALWAYS & feature) ||
                  (CPU_FTRS_POSSIBLE & cur_cpu_spec->cpu_features & feature));
@@ -46,7 +46,7 @@ static __always_inline bool cpu_has_feature(unsigned long feature)
        return static_branch_likely(&cpu_feature_keys[i]);
 }
 #else
-static inline bool cpu_has_feature(unsigned long feature)
+static __always_inline bool cpu_has_feature(unsigned long feature)
 {
        return early_cpu_has_feature(feature);
 }
index 7141cce..a920599 100644 (file)
@@ -53,8 +53,8 @@ static inline void mtdcrx(unsigned int reg, unsigned int val)
 #define mfdcr(rn)                                              \
        ({unsigned int rval;                                    \
        if (__builtin_constant_p(rn) && rn < 1024)              \
-               asm volatile("mfdcr %0," __stringify(rn)        \
-                             : "=r" (rval));                   \
+               asm volatile("mfdcr %0, %1" : "=r" (rval)       \
+                             : "n" (rn));                      \
        else if (likely(cpu_has_feature(CPU_FTR_INDEXED_DCR)))  \
                rval = mfdcrx(rn);                              \
        else                                                    \
@@ -64,8 +64,8 @@ static inline void mtdcrx(unsigned int reg, unsigned int val)
 #define mtdcr(rn, v)                                           \
 do {                                                           \
        if (__builtin_constant_p(rn) && rn < 1024)              \
-               asm volatile("mtdcr " __stringify(rn) ",%0"     \
-                             : : "r" (v));                     \
+               asm volatile("mtdcr %0, %1"                     \
+                             : : "n" (rn), "r" (v));           \
        else if (likely(cpu_has_feature(CPU_FTR_INDEXED_DCR)))  \
                mtdcrx(rn, v);                                  \
        else                                                    \
index aedfba2..e8d09a8 100644 (file)
@@ -410,7 +410,6 @@ DECLARE_INTERRUPT_HANDLER(altivec_assist_exception);
 DECLARE_INTERRUPT_HANDLER(CacheLockingException);
 DECLARE_INTERRUPT_HANDLER(SPEFloatingPointException);
 DECLARE_INTERRUPT_HANDLER(SPEFloatingPointRoundException);
-DECLARE_INTERRUPT_HANDLER(unrecoverable_exception);
 DECLARE_INTERRUPT_HANDLER(WatchdogException);
 DECLARE_INTERRUPT_HANDLER(kernel_bad_stack);
 
@@ -437,6 +436,8 @@ DECLARE_INTERRUPT_HANDLER_NMI(hmi_exception_realmode);
 
 DECLARE_INTERRUPT_HANDLER_ASYNC(TAUException);
 
+void unrecoverable_exception(struct pt_regs *regs);
+
 void replay_system_reset(void);
 void replay_soft_interrupts(void);
 
index 80b27f5..607168b 100644 (file)
@@ -228,7 +228,7 @@ enum {
 #define MMU_FTRS_ALWAYS                0
 #endif
 
-static inline bool early_mmu_has_feature(unsigned long feature)
+static __always_inline bool early_mmu_has_feature(unsigned long feature)
 {
        if (MMU_FTRS_ALWAYS & feature)
                return true;
@@ -286,7 +286,7 @@ static inline void mmu_feature_keys_init(void)
 
 }
 
-static inline bool mmu_has_feature(unsigned long feature)
+static __always_inline bool mmu_has_feature(unsigned long feature)
 {
        return early_mmu_has_feature(feature);
 }
index 975ba26..1499e92 100644 (file)
@@ -195,7 +195,7 @@ static inline void regs_set_return_value(struct pt_regs *regs, unsigned long rc)
 #define TRAP_FLAGS_MASK                0x11
 #define TRAP(regs)             ((regs)->trap & ~TRAP_FLAGS_MASK)
 #define FULL_REGS(regs)                (((regs)->trap & 1) == 0)
-#define SET_FULL_REGS(regs)    ((regs)->trap |= 1)
+#define SET_FULL_REGS(regs)    ((regs)->trap &= ~1)
 #endif
 #define CHECK_FULL_REGS(regs)  BUG_ON(!FULL_REGS(regs))
 #define NV_REG_POISON          0xdeadbeefdeadbeefUL
@@ -210,7 +210,7 @@ static inline void regs_set_return_value(struct pt_regs *regs, unsigned long rc)
 #define TRAP_FLAGS_MASK                0x1F
 #define TRAP(regs)             ((regs)->trap & ~TRAP_FLAGS_MASK)
 #define FULL_REGS(regs)                (((regs)->trap & 1) == 0)
-#define SET_FULL_REGS(regs)    ((regs)->trap |= 1)
+#define SET_FULL_REGS(regs)    ((regs)->trap &= ~1)
 #define IS_CRITICAL_EXC(regs)  (((regs)->trap & 2) != 0)
 #define IS_MCHECK_EXC(regs)    (((regs)->trap & 4) != 0)
 #define IS_DEBUG_EXC(regs)     (((regs)->trap & 8) != 0)
index fdab934..9d1fbd8 100644 (file)
@@ -71,6 +71,16 @@ static inline void disable_kernel_vsx(void)
 {
        msr_check_and_clear(MSR_FP|MSR_VEC|MSR_VSX);
 }
+#else
+static inline void enable_kernel_vsx(void)
+{
+       BUILD_BUG();
+}
+
+static inline void disable_kernel_vsx(void)
+{
+       BUILD_BUG();
+}
 #endif
 
 #ifdef CONFIG_SPE
index 0cf5274..721c0d6 100644 (file)
@@ -113,7 +113,7 @@ struct vio_driver {
        const char *name;
        const struct vio_device_id *id_table;
        int (*probe)(struct vio_dev *dev, const struct vio_device_id *id);
-       int (*remove)(struct vio_dev *dev);
+       void (*remove)(struct vio_dev *dev);
        /* A driver must have a get_desired_dma() function to
         * be loaded in a CMO environment if it uses DMA.
         */
index 60d3051..8082b69 100644 (file)
@@ -466,7 +466,7 @@ DEFINE_FIXED_SYMBOL(\name\()_common_real)
 
        ld      r10,PACAKMSR(r13)       /* get MSR value for kernel */
        /* MSR[RI] is clear iff using SRR regs */
-       .if IHSRR == EXC_HV_OR_STD
+       .if IHSRR_IF_HVMODE
        BEGIN_FTR_SECTION
        xori    r10,r10,MSR_RI
        END_FTR_SECTION_IFCLR(CPU_FTR_HVMODE)
index 727fdab..565e84e 100644 (file)
@@ -457,11 +457,12 @@ InstructionTLBMiss:
        cmplw   0,r1,r3
 #endif
        mfspr   r2, SPRN_SDR1
-       li      r1,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_EXEC
+       li      r1,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_EXEC | _PAGE_USER
        rlwinm  r2, r2, 28, 0xfffff000
 #ifdef CONFIG_MODULES
        bgt-    112f
        lis     r2, (swapper_pg_dir - PAGE_OFFSET)@ha   /* if kernel address, use */
+       li      r1,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_EXEC
        addi    r2, r2, (swapper_pg_dir - PAGE_OFFSET)@l        /* kernel page table */
 #endif
 112:   rlwimi  r2,r3,12,20,29          /* insert top 10 bits of address */
@@ -520,10 +521,11 @@ DataLoadTLBMiss:
        lis     r1, TASK_SIZE@h         /* check if kernel address */
        cmplw   0,r1,r3
        mfspr   r2, SPRN_SDR1
-       li      r1, _PAGE_PRESENT | _PAGE_ACCESSED
+       li      r1, _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_USER
        rlwinm  r2, r2, 28, 0xfffff000
        bgt-    112f
        lis     r2, (swapper_pg_dir - PAGE_OFFSET)@ha   /* if kernel address, use */
+       li      r1, _PAGE_PRESENT | _PAGE_ACCESSED
        addi    r2, r2, (swapper_pg_dir - PAGE_OFFSET)@l        /* kernel page table */
 112:   rlwimi  r2,r3,12,20,29          /* insert top 10 bits of address */
        lwz     r2,0(r2)                /* get pmd entry */
@@ -597,10 +599,11 @@ DataStoreTLBMiss:
        lis     r1, TASK_SIZE@h         /* check if kernel address */
        cmplw   0,r1,r3
        mfspr   r2, SPRN_SDR1
-       li      r1, _PAGE_RW | _PAGE_DIRTY | _PAGE_PRESENT | _PAGE_ACCESSED
+       li      r1, _PAGE_RW | _PAGE_DIRTY | _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_USER
        rlwinm  r2, r2, 28, 0xfffff000
        bgt-    112f
        lis     r2, (swapper_pg_dir - PAGE_OFFSET)@ha   /* if kernel address, use */
+       li      r1, _PAGE_RW | _PAGE_DIRTY | _PAGE_PRESENT | _PAGE_ACCESSED
        addi    r2, r2, (swapper_pg_dir - PAGE_OFFSET)@l        /* kernel page table */
 112:   rlwimi  r2,r3,12,20,29          /* insert top 10 bits of address */
        lwz     r2,0(r2)                /* get pmd entry */
index 398cd86..c475a22 100644 (file)
@@ -149,7 +149,7 @@ notrace long system_call_exception(long r3, long r4, long r5,
  * enabled when the interrupt handler returns (indicating a process-context /
  * synchronous interrupt) then irqs_enabled should be true.
  */
-static notrace inline bool __prep_irq_for_enabled_exit(bool clear_ri)
+static notrace __always_inline bool __prep_irq_for_enabled_exit(bool clear_ri)
 {
        /* This must be done with RI=1 because tracing may touch vmaps */
        trace_hardirqs_on();
@@ -436,7 +436,6 @@ again:
        return ret;
 }
 
-void unrecoverable_exception(struct pt_regs *regs);
 void preempt_schedule_irq(void);
 
 notrace unsigned long interrupt_exit_kernel_prepare(struct pt_regs *regs, unsigned long msr)
index 1583fd1..a44a30b 100644 (file)
@@ -2170,7 +2170,7 @@ DEFINE_INTERRUPT_HANDLER(SPEFloatingPointRoundException)
  * in the MSR is 0.  This indicates that SRR0/1 are live, and that
  * we therefore lost state by taking this exception.
  */
-DEFINE_INTERRUPT_HANDLER(unrecoverable_exception)
+void unrecoverable_exception(struct pt_regs *regs)
 {
        pr_emerg("Unrecoverable exception %lx at %lx (msr=%lx)\n",
                 regs->trap, regs->nip, regs->msr);
index a6e29f8..d21d081 100644 (file)
@@ -65,3 +65,14 @@ V_FUNCTION_END(__kernel_clock_getres)
 V_FUNCTION_BEGIN(__kernel_time)
        cvdso_call_time __c_kernel_time
 V_FUNCTION_END(__kernel_time)
+
+/* Routines for restoring integer registers, called by the compiler.  */
+/* Called with r11 pointing to the stack header word of the caller of the */
+/* function, just beyond the end of the integer restore area.  */
+_GLOBAL(_restgpr_31_x)
+_GLOBAL(_rest32gpr_31_x)
+       lwz     r0,4(r11)
+       lwz     r31,-4(r11)
+       mtlr    r0
+       mr      r1,r11
+       blr
index bb5c20d..c6aebc1 100644 (file)
@@ -904,7 +904,7 @@ static nokprobe_inline int do_vsx_load(struct instruction_op *op,
        if (!address_ok(regs, ea, size) || copy_mem_in(mem, ea, size, regs))
                return -EFAULT;
 
-       nr_vsx_regs = size / sizeof(__vector128);
+       nr_vsx_regs = max(1ul, size / sizeof(__vector128));
        emulate_vsx_load(op, buf, mem, cross_endian);
        preempt_disable();
        if (reg < 32) {
@@ -951,7 +951,7 @@ static nokprobe_inline int do_vsx_store(struct instruction_op *op,
        if (!address_ok(regs, ea, size))
                return -EFAULT;
 
-       nr_vsx_regs = size / sizeof(__vector128);
+       nr_vsx_regs = max(1ul, size / sizeof(__vector128));
        preempt_disable();
        if (reg < 32) {
                /* FP regs + extensions */
index 6817331..766f064 100644 (file)
@@ -222,7 +222,7 @@ static inline void perf_get_data_addr(struct perf_event *event, struct pt_regs *
        if (!(mmcra & MMCRA_SAMPLE_ENABLE) || sdar_valid)
                *addrp = mfspr(SPRN_SDAR);
 
-       if (is_kernel_addr(mfspr(SPRN_SDAR)) && perf_allow_kernel(&event->attr) != 0)
+       if (is_kernel_addr(mfspr(SPRN_SDAR)) && event->attr.exclude_kernel)
                *addrp = 0;
 }
 
@@ -507,7 +507,7 @@ static void power_pmu_bhrb_read(struct perf_event *event, struct cpu_hw_events *
                         * addresses, hence include a check before filtering code
                         */
                        if (!(ppmu->flags & PPMU_ARCH_31) &&
-                               is_kernel_addr(addr) && perf_allow_kernel(&event->attr) != 0)
+                           is_kernel_addr(addr) && event->attr.exclude_kernel)
                                continue;
 
                        /* Branches are read most recent first (ie. mfbhrb 0 is
index b3ac245..6373003 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright 2006-2007 Michael Ellerman, IBM Corp.
  */
 
+#include <linux/crash_dump.h>
 #include <linux/device.h>
 #include <linux/irq.h>
 #include <linux/msi.h>
@@ -458,8 +459,28 @@ again:
                        return hwirq;
                }
 
-               virq = irq_create_mapping_affinity(NULL, hwirq,
-                                                  entry->affinity);
+               /*
+                * Depending on the number of online CPUs in the original
+                * kernel, it is likely for CPU #0 to be offline in a kdump
+                * kernel. The associated IRQs in the affinity mappings
+                * provided by irq_create_affinity_masks() are thus not
+                * started by irq_startup(), as per-design for managed IRQs.
+                * This can be a problem with multi-queue block devices driven
+                * by blk-mq : such a non-started IRQ is very likely paired
+                * with the single queue enforced by blk-mq during kdump (see
+                * blk_mq_alloc_tag_set()). This causes the device to remain
+                * silent and likely hangs the guest at some point.
+                *
+                * We don't really care for fine-grained affinity when doing
+                * kdump actually : simply ignore the pre-computed affinity
+                * masks in this case and let the default mask with all CPUs
+                * be used when creating the IRQ mappings.
+                */
+               if (is_kdump_kernel())
+                       virq = irq_create_mapping(NULL, hwirq);
+               else
+                       virq = irq_create_mapping_affinity(NULL, hwirq,
+                                                          entry->affinity);
 
                if (!virq) {
                        pr_debug("rtas_msi: Failed mapping hwirq %d\n", hwirq);
index b2797cf..9cb4fc8 100644 (file)
@@ -1261,7 +1261,6 @@ static int vio_bus_remove(struct device *dev)
        struct vio_dev *viodev = to_vio_dev(dev);
        struct vio_driver *viodrv = to_vio_driver(dev->driver);
        struct device *devptr;
-       int ret = 1;
 
        /*
         * Hold a reference to the device after the remove function is called
@@ -1270,13 +1269,13 @@ static int vio_bus_remove(struct device *dev)
        devptr = get_device(dev);
 
        if (viodrv->remove)
-               ret = viodrv->remove(viodev);
+               viodrv->remove(viodev);
 
-       if (!ret && firmware_has_feature(FW_FEATURE_CMO))
+       if (firmware_has_feature(FW_FEATURE_CMO))
                vio_cmo_bus_remove(viodev);
 
        put_device(devptr);
-       return ret;
+       return 0;
 }
 
 /**
index 85d626b..87d7b52 100644 (file)
@@ -93,7 +93,6 @@ config RISCV
        select PCI_MSI if PCI
        select RISCV_INTC
        select RISCV_TIMER if RISCV_SBI
-       select SPARSEMEM_STATIC if 32BIT
        select SPARSE_IRQ
        select SYSCTL_EXCEPTION_TRACE
        select THREAD_INFO_IN_TASK
@@ -154,7 +153,8 @@ config ARCH_FLATMEM_ENABLE
 config ARCH_SPARSEMEM_ENABLE
        def_bool y
        depends on MMU
-       select SPARSEMEM_VMEMMAP_ENABLE
+       select SPARSEMEM_STATIC if 32BIT && SPARSMEM
+       select SPARSEMEM_VMEMMAP_ENABLE if 64BIT
 
 config ARCH_SELECT_MEMORY_MODEL
        def_bool ARCH_SPARSEMEM_ENABLE
index 7efcece..e1b2690 100644 (file)
@@ -31,6 +31,8 @@ config SOC_CANAAN
        select SIFIVE_PLIC
        select ARCH_HAS_RESET_CONTROLLER
        select PINCTRL
+       select COMMON_CLK
+       select COMMON_CLK_K210
        help
          This enables support for Canaan Kendryte K210 SoC platform hardware.
 
index 27e005f..2a652b0 100644 (file)
@@ -9,4 +9,20 @@ long long __lshrti3(long long a, int b);
 long long __ashrti3(long long a, int b);
 long long __ashlti3(long long a, int b);
 
+
+#define DECLARE_DO_ERROR_INFO(name)    asmlinkage void name(struct pt_regs *regs)
+
+DECLARE_DO_ERROR_INFO(do_trap_unknown);
+DECLARE_DO_ERROR_INFO(do_trap_insn_misaligned);
+DECLARE_DO_ERROR_INFO(do_trap_insn_fault);
+DECLARE_DO_ERROR_INFO(do_trap_insn_illegal);
+DECLARE_DO_ERROR_INFO(do_trap_load_fault);
+DECLARE_DO_ERROR_INFO(do_trap_load_misaligned);
+DECLARE_DO_ERROR_INFO(do_trap_store_misaligned);
+DECLARE_DO_ERROR_INFO(do_trap_store_fault);
+DECLARE_DO_ERROR_INFO(do_trap_ecall_u);
+DECLARE_DO_ERROR_INFO(do_trap_ecall_s);
+DECLARE_DO_ERROR_INFO(do_trap_ecall_m);
+DECLARE_DO_ERROR_INFO(do_trap_break);
+
 #endif /* _ASM_RISCV_PROTOTYPES_H */
index 9807ad1..e4c4355 100644 (file)
@@ -12,4 +12,6 @@
 
 #include <asm-generic/irq.h>
 
+extern void __init init_IRQ(void);
+
 #endif /* _ASM_RISCV_IRQ_H */
index 3a24003..021ed64 100644 (file)
@@ -71,6 +71,7 @@ int riscv_of_processor_hartid(struct device_node *node);
 int riscv_of_parent_hartid(struct device_node *node);
 
 extern void riscv_fill_hwcap(void);
+extern int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src);
 
 #endif /* __ASSEMBLY__ */
 
index cb4abb6..09ad4e9 100644 (file)
@@ -119,6 +119,11 @@ extern int regs_query_register_offset(const char *name);
 extern unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
                                               unsigned int n);
 
+void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
+                          unsigned long frame_pointer);
+int do_syscall_trace_enter(struct pt_regs *regs);
+void do_syscall_trace_exit(struct pt_regs *regs);
+
 /**
  * regs_get_register() - get register value from its offset
  * @regs:      pt_regs from which register value is gotten
index 99895d9..d702741 100644 (file)
@@ -51,10 +51,10 @@ enum sbi_ext_rfence_fid {
        SBI_EXT_RFENCE_REMOTE_FENCE_I = 0,
        SBI_EXT_RFENCE_REMOTE_SFENCE_VMA,
        SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID,
-       SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA,
        SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID,
-       SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA,
+       SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA,
        SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID,
+       SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA,
 };
 
 enum sbi_ext_hsm_fid {
index 81de51e..507cae2 100644 (file)
@@ -88,4 +88,6 @@ static inline int read_current_timer(unsigned long *timer_val)
        return 0;
 }
 
+extern void time_init(void);
+
 #endif /* _ASM_RISCV_TIMEX_H */
index 3dc0abd..647a47f 100644 (file)
@@ -8,6 +8,7 @@ CFLAGS_REMOVE_ftrace.o  = $(CC_FLAGS_FTRACE)
 CFLAGS_REMOVE_patch.o  = $(CC_FLAGS_FTRACE)
 CFLAGS_REMOVE_sbi.o    = $(CC_FLAGS_FTRACE)
 endif
+CFLAGS_syscall_table.o += $(call cc-option,-Wno-override-init,)
 
 extra-y += head.o
 extra-y += vmlinux.lds
index e637249..17ca5e9 100644 (file)
@@ -2,39 +2,41 @@
 
 #include <linux/kprobes.h>
 
-/* Ftrace callback handler for kprobes -- called under preepmt disabed */
+/* Ftrace callback handler for kprobes -- called under preepmt disabled */
 void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
-                          struct ftrace_ops *ops, struct ftrace_regs *regs)
+                          struct ftrace_ops *ops, struct ftrace_regs *fregs)
 {
        struct kprobe *p;
+       struct pt_regs *regs;
        struct kprobe_ctlblk *kcb;
 
        p = get_kprobe((kprobe_opcode_t *)ip);
        if (unlikely(!p) || kprobe_disabled(p))
                return;
 
+       regs = ftrace_get_regs(fregs);
        kcb = get_kprobe_ctlblk();
        if (kprobe_running()) {
                kprobes_inc_nmissed_count(p);
        } else {
-               unsigned long orig_ip = instruction_pointer(&(regs->regs));
+               unsigned long orig_ip = instruction_pointer(regs);
 
-               instruction_pointer_set(&(regs->regs), ip);
+               instruction_pointer_set(regs, ip);
 
                __this_cpu_write(current_kprobe, p);
                kcb->kprobe_status = KPROBE_HIT_ACTIVE;
-               if (!p->pre_handler || !p->pre_handler(p, &(regs->regs))) {
+               if (!p->pre_handler || !p->pre_handler(p, regs)) {
                        /*
                         * Emulate singlestep (and also recover regs->pc)
                         * as if there is a nop
                         */
-                       instruction_pointer_set(&(regs->regs),
+                       instruction_pointer_set(regs,
                                (unsigned long)p->addr + MCOUNT_INSN_SIZE);
                        if (unlikely(p->post_handler)) {
                                kcb->kprobe_status = KPROBE_HIT_SSDONE;
-                               p->post_handler(p, &(regs->regs), 0);
+                               p->post_handler(p, regs, 0);
                        }
-                       instruction_pointer_set(&(regs->regs), orig_ip);
+                       instruction_pointer_set(regs, orig_ip);
                }
 
                /*
index a2ec186..7e2c78e 100644 (file)
@@ -256,8 +256,7 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int trapnr)
                 * normal page fault.
                 */
                regs->epc = (unsigned long) cur->addr;
-               if (!instruction_pointer(regs))
-                       BUG();
+               BUG_ON(!instruction_pointer(regs));
 
                if (kcb->kprobe_status == KPROBE_REENTER)
                        restore_previous_kprobe(kcb);
index 6f728e7..f9cd57c 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/cpu.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/sched/debug.h>
 #include <linux/sched/task_stack.h>
 #include <linux/tick.h>
 #include <linux/ptrace.h>
index f4a7db3..d3bf756 100644 (file)
@@ -116,7 +116,7 @@ void sbi_clear_ipi(void)
 EXPORT_SYMBOL(sbi_clear_ipi);
 
 /**
- * sbi_set_timer_v01() - Program the timer for next timer event.
+ * __sbi_set_timer_v01() - Program the timer for next timer event.
  * @stime_value: The value after which next timer event should fire.
  *
  * Return: None
index e85bacf..f8f1533 100644 (file)
@@ -147,7 +147,8 @@ static void __init init_resources(void)
        bss_res.end = __pa_symbol(__bss_stop) - 1;
        bss_res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
 
-       mem_res_sz = (memblock.memory.cnt + memblock.reserved.cnt) * sizeof(*mem_res);
+       /* + 1 as memblock_alloc() might increase memblock.reserved.cnt */
+       mem_res_sz = (memblock.memory.cnt + memblock.reserved.cnt + 1) * sizeof(*mem_res);
        mem_res = memblock_alloc(mem_res_sz, SMP_CACHE_BYTES);
        if (!mem_res)
                panic("%s: Failed to allocate %zu bytes\n", __func__, mem_res_sz);
index 8a5cf99..1b43226 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/delay.h>
 #include <asm/sbi.h>
 #include <asm/processor.h>
+#include <asm/timex.h>
 
 unsigned long riscv_timebase;
 EXPORT_SYMBOL_GPL(riscv_timebase);
index 3ed2c23..0879b5d 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/module.h>
 #include <linux/irq.h>
 
+#include <asm/asm-prototypes.h>
 #include <asm/bug.h>
 #include <asm/processor.h>
 #include <asm/ptrace.h>
index 3fc18f4..4f85c6d 100644 (file)
@@ -155,7 +155,7 @@ static void __init kasan_populate(void *start, void *end)
        memset(start, KASAN_SHADOW_INIT, end - start);
 }
 
-void __init kasan_shallow_populate(void *start, void *end)
+static void __init kasan_shallow_populate(void *start, void *end)
 {
        unsigned long vaddr = (unsigned long)start & PAGE_MASK;
        unsigned long vend = PAGE_ALIGN((unsigned long)end);
@@ -187,6 +187,8 @@ void __init kasan_shallow_populate(void *start, void *end)
                }
                vaddr += PAGE_SIZE;
        }
+
+       local_flush_tlb_all();
 }
 
 void __init kasan_init(void)
index 02056b0..dc0b690 100644 (file)
@@ -275,9 +275,9 @@ CONFIG_IP_VS_DH=m
 CONFIG_IP_VS_SH=m
 CONFIG_IP_VS_SED=m
 CONFIG_IP_VS_NQ=m
+CONFIG_IP_VS_TWOS=m
 CONFIG_IP_VS_FTP=m
 CONFIG_IP_VS_PE_SIP=m
-CONFIG_NF_TABLES_IPV4=y
 CONFIG_NFT_FIB_IPV4=m
 CONFIG_NF_TABLES_ARP=y
 CONFIG_IP_NF_IPTABLES=m
@@ -298,7 +298,6 @@ CONFIG_IP_NF_SECURITY=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
-CONFIG_NF_TABLES_IPV6=y
 CONFIG_NFT_FIB_IPV6=m
 CONFIG_IP6_NF_IPTABLES=m
 CONFIG_IP6_NF_MATCH_AH=m
@@ -481,7 +480,6 @@ CONFIG_NLMON=m
 # CONFIG_NET_VENDOR_AQUANTIA is not set
 # CONFIG_NET_VENDOR_ARC is not set
 # CONFIG_NET_VENDOR_ATHEROS is not set
-# CONFIG_NET_VENDOR_AURORA is not set
 # CONFIG_NET_VENDOR_BROADCOM is not set
 # CONFIG_NET_VENDOR_BROCADE is not set
 # CONFIG_NET_VENDOR_CADENCE is not set
@@ -581,7 +579,6 @@ CONFIG_VIRTIO_BALLOON=m
 CONFIG_VIRTIO_INPUT=y
 CONFIG_VHOST_NET=m
 CONFIG_VHOST_VSOCK=m
-# CONFIG_SURFACE_PLATFORMS is not set
 CONFIG_S390_CCW_IOMMU=y
 CONFIG_S390_AP_IOMMU=y
 CONFIG_EXT4_FS=y
@@ -635,6 +632,7 @@ CONFIG_NTFS_RW=y
 CONFIG_PROC_KCORE=y
 CONFIG_TMPFS=y
 CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_TMPFS_INODE64=y
 CONFIG_HUGETLBFS=y
 CONFIG_CONFIGFS_FS=m
 CONFIG_ECRYPT_FS=m
@@ -714,12 +712,8 @@ CONFIG_CRYPTO_VMAC=m
 CONFIG_CRYPTO_CRC32=m
 CONFIG_CRYPTO_BLAKE2S=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_RMD128=m
 CONFIG_CRYPTO_RMD160=m
-CONFIG_CRYPTO_RMD256=m
-CONFIG_CRYPTO_RMD320=m
 CONFIG_CRYPTO_SHA3=m
-CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_WP512=m
 CONFIG_CRYPTO_AES_TI=m
 CONFIG_CRYPTO_ANUBIS=m
@@ -731,7 +725,6 @@ CONFIG_CRYPTO_CAST6=m
 CONFIG_CRYPTO_DES=m
 CONFIG_CRYPTO_FCRYPT=m
 CONFIG_CRYPTO_KHAZAD=m
-CONFIG_CRYPTO_SALSA20=m
 CONFIG_CRYPTO_SEED=m
 CONFIG_CRYPTO_SERPENT=m
 CONFIG_CRYPTO_SM4=m
@@ -796,12 +789,9 @@ CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
 CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y
 CONFIG_SLUB_DEBUG_ON=y
 CONFIG_SLUB_STATS=y
-CONFIG_DEBUG_KMEMLEAK=y
-CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
 CONFIG_DEBUG_STACK_USAGE=y
 CONFIG_DEBUG_VM=y
 CONFIG_DEBUG_VM_VMACACHE=y
-CONFIG_DEBUG_VM_RB=y
 CONFIG_DEBUG_VM_PGFLAGS=y
 CONFIG_DEBUG_MEMORY_INIT=y
 CONFIG_MEMORY_NOTIFIER_ERROR_INJECT=m
@@ -838,6 +828,7 @@ CONFIG_BPF_KPROBE_OVERRIDE=y
 CONFIG_HIST_TRIGGERS=y
 CONFIG_FTRACE_STARTUP_TEST=y
 # CONFIG_EVENT_TRACE_STARTUP_TEST is not set
+CONFIG_DEBUG_ENTRY=y
 CONFIG_NOTIFIER_ERROR_INJECTION=m
 CONFIG_NETDEV_NOTIFIER_ERROR_INJECT=m
 CONFIG_FAULT_INJECTION=y
@@ -861,4 +852,3 @@ CONFIG_PERCPU_TEST=m
 CONFIG_ATOMIC64_SELFTEST=y
 CONFIG_TEST_BITOPS=m
 CONFIG_TEST_BPF=m
-CONFIG_DEBUG_ENTRY=y
index bac721a..320379d 100644 (file)
@@ -266,9 +266,9 @@ CONFIG_IP_VS_DH=m
 CONFIG_IP_VS_SH=m
 CONFIG_IP_VS_SED=m
 CONFIG_IP_VS_NQ=m
+CONFIG_IP_VS_TWOS=m
 CONFIG_IP_VS_FTP=m
 CONFIG_IP_VS_PE_SIP=m
-CONFIG_NF_TABLES_IPV4=y
 CONFIG_NFT_FIB_IPV4=m
 CONFIG_NF_TABLES_ARP=y
 CONFIG_IP_NF_IPTABLES=m
@@ -289,7 +289,6 @@ CONFIG_IP_NF_SECURITY=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
-CONFIG_NF_TABLES_IPV6=y
 CONFIG_NFT_FIB_IPV6=m
 CONFIG_IP6_NF_IPTABLES=m
 CONFIG_IP6_NF_MATCH_AH=m
@@ -473,7 +472,6 @@ CONFIG_NLMON=m
 # CONFIG_NET_VENDOR_AQUANTIA is not set
 # CONFIG_NET_VENDOR_ARC is not set
 # CONFIG_NET_VENDOR_ATHEROS is not set
-# CONFIG_NET_VENDOR_AURORA is not set
 # CONFIG_NET_VENDOR_BROADCOM is not set
 # CONFIG_NET_VENDOR_BROCADE is not set
 # CONFIG_NET_VENDOR_CADENCE is not set
@@ -573,7 +571,6 @@ CONFIG_VIRTIO_BALLOON=m
 CONFIG_VIRTIO_INPUT=y
 CONFIG_VHOST_NET=m
 CONFIG_VHOST_VSOCK=m
-# CONFIG_SURFACE_PLATFORMS is not set
 CONFIG_S390_CCW_IOMMU=y
 CONFIG_S390_AP_IOMMU=y
 CONFIG_EXT4_FS=y
@@ -623,6 +620,7 @@ CONFIG_NTFS_RW=y
 CONFIG_PROC_KCORE=y
 CONFIG_TMPFS=y
 CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_TMPFS_INODE64=y
 CONFIG_HUGETLBFS=y
 CONFIG_CONFIGFS_FS=m
 CONFIG_ECRYPT_FS=m
@@ -703,12 +701,8 @@ CONFIG_CRYPTO_VMAC=m
 CONFIG_CRYPTO_CRC32=m
 CONFIG_CRYPTO_BLAKE2S=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_RMD128=m
 CONFIG_CRYPTO_RMD160=m
-CONFIG_CRYPTO_RMD256=m
-CONFIG_CRYPTO_RMD320=m
 CONFIG_CRYPTO_SHA3=m
-CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_WP512=m
 CONFIG_CRYPTO_AES_TI=m
 CONFIG_CRYPTO_ANUBIS=m
@@ -720,7 +714,6 @@ CONFIG_CRYPTO_CAST6=m
 CONFIG_CRYPTO_DES=m
 CONFIG_CRYPTO_FCRYPT=m
 CONFIG_CRYPTO_KHAZAD=m
-CONFIG_CRYPTO_SALSA20=m
 CONFIG_CRYPTO_SEED=m
 CONFIG_CRYPTO_SERPENT=m
 CONFIG_CRYPTO_SM4=m
index acf982a..76123a4 100644 (file)
@@ -26,7 +26,6 @@ CONFIG_CRASH_DUMP=y
 # CONFIG_SECCOMP is not set
 # CONFIG_GCC_PLUGINS is not set
 CONFIG_PARTITION_ADVANCED=y
-CONFIG_IBM_PARTITION=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 # CONFIG_COMPACTION is not set
 # CONFIG_MIGRATION is not set
@@ -61,11 +60,9 @@ CONFIG_RAW_DRIVER=y
 # CONFIG_HID is not set
 # CONFIG_VIRTIO_MENU is not set
 # CONFIG_VHOST_MENU is not set
-# CONFIG_SURFACE_PLATFORMS is not set
 # CONFIG_IOMMU_SUPPORT is not set
 # CONFIG_DNOTIFY is not set
 # CONFIG_INOTIFY_USER is not set
-CONFIG_CONFIGFS_FS=y
 # CONFIG_MISC_FILESYSTEMS is not set
 # CONFIG_NETWORK_FILESYSTEMS is not set
 CONFIG_LSM="yama,loadpin,safesetid,integrity"
index b04f6a7..5cea629 100644 (file)
 
 struct s390_idle_data {
        seqcount_t seqcount;
-       unsigned long long idle_count;
-       unsigned long long idle_time;
-       unsigned long long clock_idle_enter;
-       unsigned long long clock_idle_exit;
-       unsigned long long timer_idle_enter;
-       unsigned long long timer_idle_exit;
+       unsigned long idle_count;
+       unsigned long idle_time;
+       unsigned long clock_idle_enter;
+       unsigned long clock_idle_exit;
+       unsigned long timer_idle_enter;
+       unsigned long timer_idle_exit;
        unsigned long mt_cycles_enter[8];
 };
 
index 053fe8b..a75d94a 100644 (file)
@@ -202,7 +202,7 @@ extern unsigned int s390_pci_no_rid;
 ----------------------------------------------------------------------------- */
 /* Base stuff */
 int zpci_create_device(u32 fid, u32 fh, enum zpci_state state);
-void zpci_remove_device(struct zpci_dev *zdev);
+void zpci_remove_device(struct zpci_dev *zdev, bool set_error);
 int zpci_enable_device(struct zpci_dev *);
 int zpci_disable_device(struct zpci_dev *);
 int zpci_register_ioat(struct zpci_dev *, u8, u64, u64, u64);
index c4e23e9..f6326c6 100644 (file)
@@ -98,10 +98,10 @@ extern unsigned char ptff_function_mask[16];
 
 /* Query TOD offset result */
 struct ptff_qto {
-       unsigned long long physical_clock;
-       unsigned long long tod_offset;
-       unsigned long long logical_tod_offset;
-       unsigned long long tod_epoch_difference;
+       unsigned long physical_clock;
+       unsigned long tod_offset;
+       unsigned long logical_tod_offset;
+       unsigned long tod_epoch_difference;
 } __packed;
 
 static inline int ptff_query(unsigned int nr)
@@ -151,9 +151,9 @@ struct ptff_qui {
        rc;                                                             \
 })
 
-static inline unsigned long long local_tick_disable(void)
+static inline unsigned long local_tick_disable(void)
 {
-       unsigned long long old;
+       unsigned long old;
 
        old = S390_lowcore.clock_comparator;
        S390_lowcore.clock_comparator = clock_comparator_max;
@@ -161,7 +161,7 @@ static inline unsigned long long local_tick_disable(void)
        return old;
 }
 
-static inline void local_tick_enable(unsigned long long comp)
+static inline void local_tick_enable(unsigned long comp)
 {
        S390_lowcore.clock_comparator = comp;
        set_clock_comparator(S390_lowcore.clock_comparator);
@@ -169,9 +169,9 @@ static inline void local_tick_enable(unsigned long long comp)
 
 #define CLOCK_TICK_RATE                1193180 /* Underlying HZ */
 
-typedef unsigned long long cycles_t;
+typedef unsigned long cycles_t;
 
-static inline unsigned long long get_tod_clock(void)
+static inline unsigned long get_tod_clock(void)
 {
        union tod_clock clk;
 
@@ -179,10 +179,10 @@ static inline unsigned long long get_tod_clock(void)
        return clk.tod;
 }
 
-static inline unsigned long long get_tod_clock_fast(void)
+static inline unsigned long get_tod_clock_fast(void)
 {
 #ifdef CONFIG_HAVE_MARCH_Z9_109_FEATURES
-       unsigned long long clk;
+       unsigned long clk;
 
        asm volatile("stckf %0" : "=Q" (clk) : : "cc");
        return clk;
@@ -208,9 +208,9 @@ extern union tod_clock tod_clock_base;
  * Therefore preemption must be disabled, otherwise the returned
  * value is not guaranteed to be monotonic.
  */
-static inline unsigned long long get_tod_clock_monotonic(void)
+static inline unsigned long get_tod_clock_monotonic(void)
 {
-       unsigned long long tod;
+       unsigned long tod;
 
        preempt_disable_notrace();
        tod = get_tod_clock() - tod_clock_base.tod;
@@ -237,7 +237,7 @@ static inline unsigned long long get_tod_clock_monotonic(void)
  * -> ns = (th * 125) + ((tl * 125) >> 9);
  *
  */
-static inline unsigned long long tod_to_ns(unsigned long long todval)
+static inline unsigned long tod_to_ns(unsigned long todval)
 {
        return ((todval >> 9) * 125) + (((todval & 0x1ff) * 125) >> 9);
 }
@@ -249,10 +249,10 @@ static inline unsigned long long tod_to_ns(unsigned long long todval)
  *
  * Returns: true if a is later than b
  */
-static inline int tod_after(unsigned long long a, unsigned long long b)
+static inline int tod_after(unsigned long a, unsigned long b)
 {
        if (MACHINE_HAS_SCC)
-               return (long long) a > (long long) b;
+               return (long) a > (long) b;
        return a > b;
 }
 
@@ -263,10 +263,10 @@ static inline int tod_after(unsigned long long a, unsigned long long b)
  *
  * Returns: true if a is later than b
  */
-static inline int tod_after_eq(unsigned long long a, unsigned long long b)
+static inline int tod_after_eq(unsigned long a, unsigned long b)
 {
        if (MACHINE_HAS_SCC)
-               return (long long) a >= (long long) b;
+               return (long) a >= (long) b;
        return a >= b;
 }
 
diff --git a/arch/s390/include/uapi/asm/hwctrset.h b/arch/s390/include/uapi/asm/hwctrset.h
new file mode 100644 (file)
index 0000000..3d8284b
--- /dev/null
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * Copyright IBM Corp. 2021
+ * Interface implementation for communication with the CPU Measurement
+ * counter facility device driver.
+ *
+ * Author(s): Thomas Richter <tmricht@linux.ibm.com>
+ *
+ * Define for ioctl() commands to communicate with the CPU Measurement
+ * counter facility device driver.
+ */
+
+#ifndef _PERF_CPUM_CF_DIAG_H
+#define _PERF_CPUM_CF_DIAG_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+#define S390_HWCTR_DEVICE              "hwctr"
+#define S390_HWCTR_START_VERSION       1
+
+struct s390_ctrset_start {             /* Set CPUs to operate on */
+       __u64 version;                  /* Version of interface */
+       __u64 data_bytes;               /* # of bytes required */
+       __u64 cpumask_len;              /* Length of CPU mask in bytes */
+       __u64 *cpumask;                 /* Pointer to CPU mask */
+       __u64 counter_sets;             /* Bit mask of counter sets to get */
+};
+
+struct s390_ctrset_setdata {           /* Counter set data */
+       __u32 set;                      /* Counter set number */
+       __u32 no_cnts;                  /* # of counters stored in cv[] */
+       __u64 cv[0];                    /* Counter values (variable length) */
+};
+
+struct s390_ctrset_cpudata {           /* Counter set data per CPU */
+       __u32 cpu_nr;                   /* CPU number */
+       __u32 no_sets;                  /* # of counters sets in data[] */
+       struct s390_ctrset_setdata data[0];
+};
+
+struct s390_ctrset_read {              /* Structure to get all ctr sets */
+       __u64 no_cpus;                  /* Total # of CPUs data taken from */
+       struct s390_ctrset_cpudata data[0];
+};
+
+#define S390_HWCTR_MAGIC       'C'     /* Random magic # for ioctls */
+#define        S390_HWCTR_START        _IOWR(S390_HWCTR_MAGIC, 1, struct s390_ctrset_start)
+#define        S390_HWCTR_STOP         _IO(S390_HWCTR_MAGIC, 2)
+#define        S390_HWCTR_READ         _IOWR(S390_HWCTR_MAGIC, 3, struct s390_ctrset_read)
+#endif
diff --git a/arch/s390/include/uapi/asm/perf_cpum_cf_diag.h b/arch/s390/include/uapi/asm/perf_cpum_cf_diag.h
deleted file mode 100644 (file)
index 3d8284b..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-/*
- * Copyright IBM Corp. 2021
- * Interface implementation for communication with the CPU Measurement
- * counter facility device driver.
- *
- * Author(s): Thomas Richter <tmricht@linux.ibm.com>
- *
- * Define for ioctl() commands to communicate with the CPU Measurement
- * counter facility device driver.
- */
-
-#ifndef _PERF_CPUM_CF_DIAG_H
-#define _PERF_CPUM_CF_DIAG_H
-
-#include <linux/ioctl.h>
-#include <linux/types.h>
-
-#define S390_HWCTR_DEVICE              "hwctr"
-#define S390_HWCTR_START_VERSION       1
-
-struct s390_ctrset_start {             /* Set CPUs to operate on */
-       __u64 version;                  /* Version of interface */
-       __u64 data_bytes;               /* # of bytes required */
-       __u64 cpumask_len;              /* Length of CPU mask in bytes */
-       __u64 *cpumask;                 /* Pointer to CPU mask */
-       __u64 counter_sets;             /* Bit mask of counter sets to get */
-};
-
-struct s390_ctrset_setdata {           /* Counter set data */
-       __u32 set;                      /* Counter set number */
-       __u32 no_cnts;                  /* # of counters stored in cv[] */
-       __u64 cv[0];                    /* Counter values (variable length) */
-};
-
-struct s390_ctrset_cpudata {           /* Counter set data per CPU */
-       __u32 cpu_nr;                   /* CPU number */
-       __u32 no_sets;                  /* # of counters sets in data[] */
-       struct s390_ctrset_setdata data[0];
-};
-
-struct s390_ctrset_read {              /* Structure to get all ctr sets */
-       __u64 no_cpus;                  /* Total # of CPUs data taken from */
-       struct s390_ctrset_cpudata data[0];
-};
-
-#define S390_HWCTR_MAGIC       'C'     /* Random magic # for ioctls */
-#define        S390_HWCTR_START        _IOWR(S390_HWCTR_MAGIC, 1, struct s390_ctrset_start)
-#define        S390_HWCTR_STOP         _IO(S390_HWCTR_MAGIC, 2)
-#define        S390_HWCTR_READ         _IOWR(S390_HWCTR_MAGIC, 3, struct s390_ctrset_read)
-#endif
index 812073e..4bf1ee2 100644 (file)
@@ -47,7 +47,7 @@ void account_idle_time_irq(void)
 void arch_cpu_idle(void)
 {
        struct s390_idle_data *idle = this_cpu_ptr(&s390_idle);
-       unsigned long long idle_time;
+       unsigned long idle_time;
        unsigned long psw_mask;
 
        /* Wait for external, I/O or machine check interrupt. */
@@ -73,7 +73,7 @@ static ssize_t show_idle_count(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
        struct s390_idle_data *idle = &per_cpu(s390_idle, dev->id);
-       unsigned long long idle_count;
+       unsigned long idle_count;
        unsigned int seq;
 
        do {
@@ -82,14 +82,14 @@ static ssize_t show_idle_count(struct device *dev,
                if (READ_ONCE(idle->clock_idle_enter))
                        idle_count++;
        } while (read_seqcount_retry(&idle->seqcount, seq));
-       return sprintf(buf, "%llu\n", idle_count);
+       return sprintf(buf, "%lu\n", idle_count);
 }
 DEVICE_ATTR(idle_count, 0444, show_idle_count, NULL);
 
 static ssize_t show_idle_time(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
-       unsigned long long now, idle_time, idle_enter, idle_exit, in_idle;
+       unsigned long now, idle_time, idle_enter, idle_exit, in_idle;
        struct s390_idle_data *idle = &per_cpu(s390_idle, dev->id);
        unsigned int seq;
 
@@ -109,14 +109,14 @@ static ssize_t show_idle_time(struct device *dev,
                }
        }
        idle_time += in_idle;
-       return sprintf(buf, "%llu\n", idle_time >> 12);
+       return sprintf(buf, "%lu\n", idle_time >> 12);
 }
 DEVICE_ATTR(idle_time_us, 0444, show_idle_time, NULL);
 
 u64 arch_cpu_idle_time(int cpu)
 {
        struct s390_idle_data *idle = &per_cpu(s390_idle, cpu);
-       unsigned long long now, idle_enter, idle_exit, in_idle;
+       unsigned long now, idle_enter, idle_exit, in_idle;
        unsigned int seq;
 
        do {
index 0eb1d1c..b3beef6 100644 (file)
@@ -269,7 +269,7 @@ static int __hw_perf_event_init(struct perf_event *event, unsigned int type)
        case CPUMF_CTR_SET_MAX:
                /* The counter could not be associated to a counter set */
                return -EINVAL;
-       };
+       }
 
        /* Initialize for using the CPU-measurement counter facility */
        if (!atomic_inc_not_zero(&num_events)) {
index db4877b..2e3e7ed 100644 (file)
 #include <asm/timex.h>
 #include <asm/debug.h>
 
-#include <asm/perf_cpum_cf_diag.h>
+#include <asm/hwctrset.h>
 
 #define        CF_DIAG_CTRSET_DEF              0xfeef  /* Counter set header mark */
-#define CF_DIAG_MIN_INTERVAL           60      /* Minimum counter set read */
                                                /* interval in seconds */
-static unsigned long cf_diag_interval = CF_DIAG_MIN_INTERVAL;
 static unsigned int cf_diag_cpu_speed;
 static debug_info_t *cf_diag_dbg;
 
@@ -729,7 +727,6 @@ static DEFINE_MUTEX(cf_diag_ctrset_mutex);
 static struct cf_diag_ctrset {
        unsigned long ctrset;           /* Bit mask of counter set to read */
        cpumask_t mask;                 /* CPU mask to read from */
-       time64_t lastread;              /* Epoch counter set last read */
 } cf_diag_ctrset;
 
 static void cf_diag_ctrset_clear(void)
@@ -866,27 +863,16 @@ static int cf_diag_all_read(unsigned long arg)
 {
        struct cf_diag_call_on_cpu_parm p;
        cpumask_var_t mask;
-       time64_t now;
-       int rc = 0;
+       int rc;
 
        debug_sprintf_event(cf_diag_dbg, 5, "%s\n", __func__);
        if (!alloc_cpumask_var(&mask, GFP_KERNEL))
                return -ENOMEM;
-       now = ktime_get_seconds();
-       if (cf_diag_ctrset.lastread + cf_diag_interval > now) {
-               debug_sprintf_event(cf_diag_dbg, 5, "%s now %lld "
-                                   " lastread %lld\n", __func__, now,
-                                   cf_diag_ctrset.lastread);
-               rc = -EAGAIN;
-               goto out;
-       } else {
-               cf_diag_ctrset.lastread = now;
-       }
+
        p.sets = cf_diag_ctrset.ctrset;
        cpumask_and(mask, &cf_diag_ctrset.mask, cpu_online_mask);
        on_each_cpu_mask(mask, cf_diag_cpu_read, &p, 1);
        rc = cf_diag_all_copy(arg, mask);
-out:
        free_cpumask_var(mask);
        debug_sprintf_event(cf_diag_dbg, 5, "%s rc %d\n", __func__, rc);
        return rc;
@@ -982,7 +968,7 @@ static int cf_diag_all_start(void)
  */
 static size_t cf_diag_needspace(unsigned int sets)
 {
-       struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events);
+       struct cpu_cf_events *cpuhw = get_cpu_ptr(&cpu_cf_events);
        size_t bytes = 0;
        int i;
 
@@ -998,6 +984,7 @@ static size_t cf_diag_needspace(unsigned int sets)
                     sizeof(((struct s390_ctrset_cpudata *)0)->no_sets));
        debug_sprintf_event(cf_diag_dbg, 5, "%s bytes %ld\n", __func__,
                            bytes);
+       put_cpu_ptr(&cpu_cf_events);
        return bytes;
 }
 
index 06bcfa6..165da96 100644 (file)
@@ -68,10 +68,10 @@ EXPORT_SYMBOL(s390_epoch_delta_notifier);
 
 unsigned char ptff_function_mask[16];
 
-static unsigned long long lpar_offset;
-static unsigned long long initial_leap_seconds;
-static unsigned long long tod_steering_end;
-static long long tod_steering_delta;
+static unsigned long lpar_offset;
+static unsigned long initial_leap_seconds;
+static unsigned long tod_steering_end;
+static long tod_steering_delta;
 
 /*
  * Get time offsets with PTFF
@@ -96,7 +96,7 @@ void __init time_early_init(void)
 
        /* get initial leap seconds */
        if (ptff_query(PTFF_QUI) && ptff(&qui, sizeof(qui), PTFF_QUI) == 0)
-               initial_leap_seconds = (unsigned long long)
+               initial_leap_seconds = (unsigned long)
                        ((long) qui.old_leap * 4096000000L);
 }
 
@@ -222,7 +222,7 @@ void __init read_persistent_wall_and_boot_offset(struct timespec64 *wall_time,
 
 static u64 read_tod_clock(struct clocksource *cs)
 {
-       unsigned long long now, adj;
+       unsigned long now, adj;
 
        preempt_disable(); /* protect from changes to steering parameters */
        now = get_tod_clock();
@@ -362,7 +362,7 @@ static inline int check_sync_clock(void)
  * Apply clock delta to the global data structures.
  * This is called once on the CPU that performed the clock sync.
  */
-static void clock_sync_global(unsigned long long delta)
+static void clock_sync_global(unsigned long delta)
 {
        unsigned long now, adj;
        struct ptff_qto qto;
@@ -378,7 +378,7 @@ static void clock_sync_global(unsigned long long delta)
                        -(adj >> 15) : (adj >> 15);
        tod_steering_delta += delta;
        if ((abs(tod_steering_delta) >> 48) != 0)
-               panic("TOD clock sync offset %lli is too large to drift\n",
+               panic("TOD clock sync offset %li is too large to drift\n",
                      tod_steering_delta);
        tod_steering_end = now + (abs(tod_steering_delta) << 15);
        vdso_data->arch_data.tod_steering_end = tod_steering_end;
@@ -394,7 +394,7 @@ static void clock_sync_global(unsigned long long delta)
  * Apply clock delta to the per-CPU data structures of this CPU.
  * This is called for each online CPU after the call to clock_sync_global.
  */
-static void clock_sync_local(unsigned long long delta)
+static void clock_sync_local(unsigned long delta)
 {
        /* Add the delta to the clock comparator. */
        if (S390_lowcore.clock_comparator != clock_comparator_max) {
@@ -418,7 +418,7 @@ static void __init time_init_wq(void)
 struct clock_sync_data {
        atomic_t cpus;
        int in_sync;
-       unsigned long long clock_delta;
+       unsigned long clock_delta;
 };
 
 /*
@@ -538,7 +538,7 @@ static int stpinfo_valid(void)
 static int stp_sync_clock(void *data)
 {
        struct clock_sync_data *sync = data;
-       unsigned long long clock_delta, flags;
+       u64 clock_delta, flags;
        static int first;
        int rc;
 
@@ -720,8 +720,8 @@ static ssize_t ctn_id_show(struct device *dev,
 
        mutex_lock(&stp_mutex);
        if (stpinfo_valid())
-               ret = sprintf(buf, "%016llx\n",
-                             *(unsigned long long *) stp_info.ctnid);
+               ret = sprintf(buf, "%016lx\n",
+                             *(unsigned long *) stp_info.ctnid);
        mutex_unlock(&stp_mutex);
        return ret;
 }
@@ -794,7 +794,7 @@ static ssize_t leap_seconds_scheduled_show(struct device *dev,
        if (!stzi.lsoib.p)
                return sprintf(buf, "0,0\n");
 
-       return sprintf(buf, "%llu,%d\n",
+       return sprintf(buf, "%lu,%d\n",
                       tod_to_ns(stzi.lsoib.nlsout - TOD_UNIX_EPOCH) / NSEC_PER_SEC,
                       stzi.lsoib.nlso - stzi.lsoib.also);
 }
index e7ce447..bfcc327 100644 (file)
@@ -76,8 +76,6 @@ static void cpu_group_map(cpumask_t *dst, struct mask_info *info, unsigned int c
                        }
                        info = info->next;
                }
-               if (cpumask_empty(&mask))
-                       cpumask_copy(&mask, cpumask_of(cpu));
                break;
        case TOPOLOGY_MODE_PACKAGE:
                cpumask_copy(&mask, cpu_present_mask);
index 73c7afc..f216a1b 100644 (file)
@@ -214,7 +214,7 @@ void vtime_flush(struct task_struct *tsk)
        avg_steal = S390_lowcore.avg_steal_timer / 2;
        if ((s64) steal > 0) {
                S390_lowcore.steal_timer = 0;
-               account_steal_time(steal);
+               account_steal_time(cputime_to_nsecs(steal));
                avg_steal += steal;
        }
        S390_lowcore.avg_steal_timer = avg_steal;
index e3183bd..d548d60 100644 (file)
@@ -1287,7 +1287,7 @@ static u64 __calculate_sltime(struct kvm_vcpu *vcpu)
                        /* already expired? */
                        if (cputm >> 63)
                                return 0;
-                       return min(sltime, tod_to_ns(cputm));
+                       return min_t(u64, sltime, tod_to_ns(cputm));
                }
        } else if (cpu_timer_interrupts_enabled(vcpu)) {
                sltime = kvm_s390_get_cpu_timer(vcpu);
index 600881d..9106407 100644 (file)
@@ -682,16 +682,36 @@ int zpci_disable_device(struct zpci_dev *zdev)
 }
 EXPORT_SYMBOL_GPL(zpci_disable_device);
 
-void zpci_remove_device(struct zpci_dev *zdev)
+/* zpci_remove_device - Removes the given zdev from the PCI core
+ * @zdev: the zdev to be removed from the PCI core
+ * @set_error: if true the device's error state is set to permanent failure
+ *
+ * Sets a zPCI device to a configured but offline state; the zPCI
+ * device is still accessible through its hotplug slot and the zPCI
+ * API but is removed from the common code PCI bus, making it
+ * no longer available to drivers.
+ */
+void zpci_remove_device(struct zpci_dev *zdev, bool set_error)
 {
        struct zpci_bus *zbus = zdev->zbus;
        struct pci_dev *pdev;
 
+       if (!zdev->zbus->bus)
+               return;
+
        pdev = pci_get_slot(zbus->bus, zdev->devfn);
        if (pdev) {
-               if (pdev->is_virtfn)
-                       return zpci_iov_remove_virtfn(pdev, zdev->vfn);
+               if (set_error)
+                       pdev->error_state = pci_channel_io_perm_failure;
+               if (pdev->is_virtfn) {
+                       zpci_iov_remove_virtfn(pdev, zdev->vfn);
+                       /* balance pci_get_slot */
+                       pci_dev_put(pdev);
+                       return;
+               }
                pci_stop_and_remove_bus_device_locked(pdev);
+               /* balance pci_get_slot */
+               pci_dev_put(pdev);
        }
 }
 
@@ -765,7 +785,7 @@ void zpci_release_device(struct kref *kref)
        struct zpci_dev *zdev = container_of(kref, struct zpci_dev, kref);
 
        if (zdev->zbus->bus)
-               zpci_remove_device(zdev);
+               zpci_remove_device(zdev, false);
 
        switch (zdev->state) {
        case ZPCI_FN_STATE_ONLINE:
index b4162da..ac0c65c 100644 (file)
@@ -76,13 +76,10 @@ void zpci_event_error(void *data)
 static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
 {
        struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
-       struct pci_dev *pdev = NULL;
        enum zpci_state state;
+       struct pci_dev *pdev;
        int ret;
 
-       if (zdev && zdev->zbus->bus)
-               pdev = pci_get_slot(zdev->zbus->bus, zdev->devfn);
-
        zpci_err("avail CCDF:\n");
        zpci_err_hex(ccdf, sizeof(*ccdf));
 
@@ -124,8 +121,7 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
        case 0x0303: /* Deconfiguration requested */
                if (!zdev)
                        break;
-               if (pdev)
-                       zpci_remove_device(zdev);
+               zpci_remove_device(zdev, false);
 
                ret = zpci_disable_device(zdev);
                if (ret)
@@ -140,12 +136,10 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
        case 0x0304: /* Configured -> Standby|Reserved */
                if (!zdev)
                        break;
-               if (pdev) {
-                       /* Give the driver a hint that the function is
-                        * already unusable. */
-                       pdev->error_state = pci_channel_io_perm_failure;
-                       zpci_remove_device(zdev);
-               }
+               /* Give the driver a hint that the function is
+                * already unusable.
+                */
+               zpci_remove_device(zdev, true);
 
                zdev->fh = ccdf->fh;
                zpci_disable_device(zdev);
index 148f44b..12a4fb0 100644 (file)
@@ -93,7 +93,7 @@ CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=m
 CONFIG_SUNLANCE=m
-CONFIG_HAPPYMEAL=m
+CONFIG_HAPPYMEAL=y
 CONFIG_SUNGEM=m
 CONFIG_SUNVNET=m
 CONFIG_LDMVSW=m
@@ -234,9 +234,7 @@ CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRC16=m
 CONFIG_LIBCRC32C=m
 CONFIG_VCC=m
-CONFIG_ATA=y
 CONFIG_PATA_CMD64X=y
-CONFIG_HAPPYMEAL=y
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 CONFIG_DEVTMPFS=y
index 7e078bc..8fb09ee 100644 (file)
@@ -8,7 +8,6 @@
 
 #include <asm/ptrace.h>
 #include <asm/processor.h>
-#include <asm/extable_64.h>
 #include <asm/spitfire.h>
 #include <asm/adi.h>
 
diff --git a/arch/sparc/include/asm/extable.h b/arch/sparc/include/asm/extable.h
new file mode 100644 (file)
index 0000000..554a9dc
--- /dev/null
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_EXTABLE_H
+#define __ASM_EXTABLE_H
+/*
+ * The exception table consists of pairs of addresses: the first is the
+ * address of an instruction that is allowed to fault, and the second is
+ * the address at which the program should continue.  No registers are
+ * modified, so it is entirely up to the continuation code to figure out
+ * what to do.
+ *
+ * All the routines below use bits of fixup code that are out of line
+ * with the main instruction path.  This means when everything is well,
+ * we don't even have to jump over them.  Further, they do not intrude
+ * on our cache or tlb entries.
+ */
+
+struct exception_table_entry {
+        unsigned int insn, fixup;
+};
+
+#endif
diff --git a/arch/sparc/include/asm/extable_64.h b/arch/sparc/include/asm/extable_64.h
deleted file mode 100644 (file)
index 5a01719..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __ASM_EXTABLE64_H
-#define __ASM_EXTABLE64_H
-/*
- * The exception table consists of pairs of addresses: the first is the
- * address of an instruction that is allowed to fault, and the second is
- * the address at which the program should continue.  No registers are
- * modified, so it is entirely up to the continuation code to figure out
- * what to do.
- *
- * All the routines below use bits of fixup code that are out of line
- * with the main instruction path.  This means when everything is well,
- * we don't even have to jump over them.  Further, they do not intrude
- * on our cache or tlb entries.
- */
-
-struct exception_table_entry {
-        unsigned int insn, fixup;
-};
-
-#endif
index 3c4bc21..b6242f7 100644 (file)
@@ -50,16 +50,12 @@ struct thread_struct {
        unsigned long   fsr;
        unsigned long   fpqdepth;
        struct fpq      fpqueue[16];
-       unsigned long flags;
        mm_segment_t current_ds;
 };
 
-#define SPARC_FLAG_KTHREAD      0x1    /* task is a kernel thread */
-#define SPARC_FLAG_UNALIGNED    0x2    /* is allowed to do unaligned accesses */
-
 #define INIT_THREAD  { \
-       .flags = SPARC_FLAG_KTHREAD, \
        .current_ds = KERNEL_DS, \
+       .kregs = (struct pt_regs *)(init_stack+THREAD_SIZE)-1 \
 }
 
 /* Do necessary setup to start up a newly executed thread. */
index 42cd4cd..8047a9c 100644 (file)
@@ -118,6 +118,7 @@ struct thread_info {
        .task           =       &tsk,                   \
        .current_ds     =       ASI_P,                  \
        .preempt_count  =       INIT_PREEMPT_COUNT,     \
+       .kregs          =       (struct pt_regs *)(init_stack+THREAD_SIZE)-1 \
 }
 
 /* how to get the thread information struct from C */
index dd85bc2..3900942 100644 (file)
@@ -1,6 +1,9 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 #ifndef ___ASM_SPARC_UACCESS_H
 #define ___ASM_SPARC_UACCESS_H
+
+#include <asm/extable.h>
+
 #if defined(__sparc__) && defined(__arch64__)
 #include <asm/uaccess_64.h>
 #else
index 0a2d3eb..4a12346 100644 (file)
@@ -13,9 +13,6 @@
 
 #include <asm/processor.h>
 
-#define ARCH_HAS_SORT_EXTABLE
-#define ARCH_HAS_SEARCH_EXTABLE
-
 /* Sparc is not segmented, however we need to be able to fool access_ok()
  * when doing system calls from kernel mode legitimately.
  *
 #define __access_ok(addr, size) (__user_ok((addr) & get_fs().seg, (size)))
 #define access_ok(addr, size) __access_ok((unsigned long)(addr), size)
 
-/*
- * The exception table consists of pairs of addresses: the first is the
- * address of an instruction that is allowed to fault, and the second is
- * the address at which the program should continue.  No registers are
- * modified, so it is entirely up to the continuation code to figure out
- * what to do.
- *
- * All the routines below use bits of fixup code that are out of line
- * with the main instruction path.  This means when everything is well,
- * we don't even have to jump over them.  Further, they do not intrude
- * on our cache or tlb entries.
- *
- * There is a special way how to put a range of potentially faulting
- * insns (like twenty ldd/std's with now intervening other instructions)
- * You specify address of first in insn and 0 in fixup and in the next
- * exception_table_entry you specify last potentially faulting insn + 1
- * and in fixup the routine which should handle the fault.
- * That fixup code will get
- * (faulting_insn_address - first_insn_in_the_range_address)/4
- * in %g2 (ie. index of the faulting instruction in the range).
- */
-
-struct exception_table_entry
-{
-        unsigned long insn, fixup;
-};
-
-/* Returns 0 if exception not found and fixup otherwise.  */
-unsigned long search_extables_range(unsigned long addr, unsigned long *g2);
-
 /* Uh, these should become the main single-value transfer routines..
  * They automatically use the right size if we just have the right
  * pointer type..
@@ -252,12 +219,7 @@ static inline unsigned long __clear_user(void __user *addr, unsigned long size)
        unsigned long ret;
 
        __asm__ __volatile__ (
-               ".section __ex_table,#alloc\n\t"
-               ".align 4\n\t"
-               ".word 1f,3\n\t"
-               ".previous\n\t"
                "mov %2, %%o1\n"
-               "1:\n\t"
                "call __bzero\n\t"
                " mov %1, %%o0\n\t"
                "mov %%o0, %0\n"
index 698cf69..30eb4c6 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/string.h>
 #include <asm/asi.h>
 #include <asm/spitfire.h>
-#include <asm/extable_64.h>
 
 #include <asm/processor.h>
 
index be30c8d..6044b82 100644 (file)
@@ -515,7 +515,7 @@ continue_boot:
 
                /* I want a kernel stack NOW! */
                set     init_thread_union, %g1
-               set     (THREAD_SIZE - STACKFRAME_SZ), %g2
+               set     (THREAD_SIZE - STACKFRAME_SZ - TRACEREG_SZ), %g2
                add     %g1, %g2, %sp
                mov     0, %fp                  /* And for good luck */
 
index c5ff247..72a5bdc 100644 (file)
@@ -706,7 +706,7 @@ tlb_fixup_done:
        wr      %g0, ASI_P, %asi
        mov     1, %g1
        sllx    %g1, THREAD_SHIFT, %g1
-       sub     %g1, (STACKFRAME_SZ + STACK_BIAS), %g1
+       sub     %g1, (STACKFRAME_SZ + STACK_BIAS + TRACEREG_SZ), %g1
        add     %g6, %g1, %sp
 
        /* Set per-cpu pointer initially to zero, this makes
index b91e880..3b97949 100644 (file)
@@ -216,16 +216,6 @@ void flush_thread(void)
                clear_thread_flag(TIF_USEDFPU);
 #endif
        }
-
-       /* This task is no longer a kernel thread. */
-       if (current->thread.flags & SPARC_FLAG_KTHREAD) {
-               current->thread.flags &= ~SPARC_FLAG_KTHREAD;
-
-               /* We must fixup kregs as well. */
-               /* XXX This was not fixed for ti for a while, worked. Unused? */
-               current->thread.kregs = (struct pt_regs *)
-                   (task_stack_page(current) + (THREAD_SIZE - TRACEREG_SZ));
-       }
 }
 
 static inline struct sparc_stackf __user *
@@ -313,7 +303,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg,
                extern int nwindows;
                unsigned long psr;
                memset(new_stack, 0, STACKFRAME_SZ + TRACEREG_SZ);
-               p->thread.flags |= SPARC_FLAG_KTHREAD;
                p->thread.current_ds = KERNEL_DS;
                ti->kpc = (((unsigned long) ret_from_kernel_thread) - 0x8);
                childregs->u_regs[UREG_G1] = sp; /* function */
@@ -325,7 +314,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg,
        }
        memcpy(new_stack, (char *)regs - STACKFRAME_SZ, STACKFRAME_SZ + TRACEREG_SZ);
        childregs->u_regs[UREG_FP] = sp;
-       p->thread.flags &= ~SPARC_FLAG_KTHREAD;
        p->thread.current_ds = USER_DS;
        ti->kpc = (((unsigned long) ret_from_fork) - 0x8);
        ti->kpsr = current->thread.fork_kpsr | PSR_PIL;
index eea43a1..c8e0dd9 100644 (file)
@@ -266,7 +266,6 @@ static __init void leon_patch(void)
 }
 
 struct tt_entry *sparc_ttable;
-static struct pt_regs fake_swapper_regs;
 
 /* Called from head_32.S - before we have setup anything
  * in the kernel. Be very careful with what you do here.
@@ -363,8 +362,6 @@ void __init setup_arch(char **cmdline_p)
                (*(linux_dbvec->teach_debugger))();
        }
 
-       init_task.thread.kregs = &fake_swapper_regs;
-
        /* Run-time patch instructions to match the cpu model */
        per_cpu_patch();
 
index d872441..48abee4 100644 (file)
@@ -165,8 +165,6 @@ extern int root_mountflags;
 
 char reboot_command[COMMAND_LINE_SIZE];
 
-static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 };
-
 static void __init per_cpu_patch(void)
 {
        struct cpuid_patch_entry *p;
@@ -661,8 +659,6 @@ void __init setup_arch(char **cmdline_p)
        rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK;
 #endif
 
-       task_thread_info(&init_task)->kregs = &fake_swapper_regs;
-
 #ifdef CONFIG_IP_PNP
        if (!ic_set_manually) {
                phandle chosen = prom_finddevice("/chosen");
index d92e5ea..a850dcc 100644 (file)
@@ -275,14 +275,13 @@ bool is_no_fault_exception(struct pt_regs *regs)
                        asi = (regs->tstate >> 24); /* saved %asi       */
                else
                        asi = (insn >> 5);          /* immediate asi    */
-               if ((asi & 0xf2) == ASI_PNF) {
-                       if (insn & 0x1000000) {     /* op3[5:4]=3       */
-                               handle_ldf_stq(insn, regs);
-                               return true;
-                       } else if (insn & 0x200000) { /* op3[2], stores */
+               if ((asi & 0xf6) == ASI_PNF) {
+                       if (insn & 0x200000)        /* op3[2], stores   */
                                return false;
-                       }
-                       handle_ld_nf(insn, regs);
+                       if (insn & 0x1000000)       /* op3[5:4]=3 (fp)  */
+                               handle_ldf_stq(insn, regs);
+                       else
+                               handle_ld_nf(insn, regs);
                        return true;
                }
        }
index 83db94c..ef5c520 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/uaccess.h>
 #include <linux/smp.h>
 #include <linux/perf_event.h>
+#include <linux/extable.h>
 
 #include <asm/setup.h>
 
@@ -213,10 +214,10 @@ static inline int ok_for_kernel(unsigned int insn)
 
 static void kernel_mna_trap_fault(struct pt_regs *regs, unsigned int insn)
 {
-       unsigned long g2 = regs->u_regs [UREG_G2];
-       unsigned long fixup = search_extables_range(regs->pc, &g2);
+       const struct exception_table_entry *entry;
 
-       if (!fixup) {
+       entry = search_exception_tables(regs->pc);
+       if (!entry) {
                unsigned long address = compute_effective_address(regs, insn);
                if(address < PAGE_SIZE) {
                        printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference in mna handler");
@@ -232,9 +233,8 @@ static void kernel_mna_trap_fault(struct pt_regs *regs, unsigned int insn)
                die_if_kernel("Oops", regs);
                /* Not reached */
        }
-       regs->pc = fixup;
+       regs->pc = entry->fixup;
        regs->npc = regs->pc + 4;
-       regs->u_regs [UREG_G2] = g2;
 }
 
 asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
@@ -274,103 +274,9 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
        }
 }
 
-static inline int ok_for_user(struct pt_regs *regs, unsigned int insn,
-                             enum direction dir)
-{
-       unsigned int reg;
-       int size = ((insn >> 19) & 3) == 3 ? 8 : 4;
-
-       if ((regs->pc | regs->npc) & 3)
-               return 0;
-
-       /* Must access_ok() in all the necessary places. */
-#define WINREG_ADDR(regnum) \
-       ((void __user *)(((unsigned long *)regs->u_regs[UREG_FP])+(regnum)))
-
-       reg = (insn >> 25) & 0x1f;
-       if (reg >= 16) {
-               if (!access_ok(WINREG_ADDR(reg - 16), size))
-                       return -EFAULT;
-       }
-       reg = (insn >> 14) & 0x1f;
-       if (reg >= 16) {
-               if (!access_ok(WINREG_ADDR(reg - 16), size))
-                       return -EFAULT;
-       }
-       if (!(insn & 0x2000)) {
-               reg = (insn & 0x1f);
-               if (reg >= 16) {
-                       if (!access_ok(WINREG_ADDR(reg - 16), size))
-                               return -EFAULT;
-               }
-       }
-#undef WINREG_ADDR
-       return 0;
-}
-
-static void user_mna_trap_fault(struct pt_regs *regs, unsigned int insn)
+asmlinkage void user_unaligned_trap(struct pt_regs *regs, unsigned int insn)
 {
        send_sig_fault(SIGBUS, BUS_ADRALN,
                       (void __user *)safe_compute_effective_address(regs, insn),
                       0, current);
 }
-
-asmlinkage void user_unaligned_trap(struct pt_regs *regs, unsigned int insn)
-{
-       enum direction dir;
-
-       if(!(current->thread.flags & SPARC_FLAG_UNALIGNED) ||
-          (((insn >> 30) & 3) != 3))
-               goto kill_user;
-       dir = decode_direction(insn);
-       if(!ok_for_user(regs, insn, dir)) {
-               goto kill_user;
-       } else {
-               int err, size = decode_access_size(insn);
-               unsigned long addr;
-
-               if(floating_point_load_or_store_p(insn)) {
-                       printk("User FPU load/store unaligned unsupported.\n");
-                       goto kill_user;
-               }
-
-               addr = compute_effective_address(regs, insn);
-               perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, addr);
-               switch(dir) {
-               case load:
-                       err = do_int_load(fetch_reg_addr(((insn>>25)&0x1f),
-                                                        regs),
-                                         size, (unsigned long *) addr,
-                                         decode_signedness(insn));
-                       break;
-
-               case store:
-                       err = do_int_store(((insn>>25)&0x1f), size,
-                                          (unsigned long *) addr, regs);
-                       break;
-
-               case both:
-                       /*
-                        * This was supported in 2.4. However, we question
-                        * the value of SWAP instruction across word boundaries.
-                        */
-                       printk("Unaligned SWAP unsupported.\n");
-                       err = -EFAULT;
-                       break;
-
-               default:
-                       unaligned_panic("Impossible user unaligned trap.");
-                       goto out;
-               }
-               if (err)
-                       goto kill_user;
-               else
-                       advance(regs);
-               goto out;
-       }
-
-kill_user:
-       user_mna_trap_fault(regs, insn);
-out:
-       ;
-}
index 7488d13..781e39b 100644 (file)
@@ -155,13 +155,6 @@ cpout:     retl                                            ! get outta here
         .text;                                  \
         .align  4
 
-#define EXT(start,end)                         \
-        .section __ex_table,ALLOC;             \
-        .align  4;                              \
-        .word   start, 0, end, cc_fault;         \
-        .text;                                  \
-        .align  4
-
        /* This aligned version executes typically in 8.5 superscalar cycles, this
         * is the best I can do.  I say 8.5 because the final add will pair with
         * the next ldd in the main unrolled loop.  Thus the pipe is always full.
@@ -169,20 +162,20 @@ cpout:    retl                                            ! get outta here
         * please check the fixup code below as well.
         */
 #define CSUMCOPY_BIGCHUNK_ALIGNED(src, dst, sum, off, t0, t1, t2, t3, t4, t5, t6, t7)  \
-       ldd     [src + off + 0x00], t0;                                                 \
-       ldd     [src + off + 0x08], t2;                                                 \
+       EX(ldd  [src + off + 0x00], t0);                                                \
+       EX(ldd  [src + off + 0x08], t2);                                                \
        addxcc  t0, sum, sum;                                                           \
-       ldd     [src + off + 0x10], t4;                                                 \
+       EX(ldd  [src + off + 0x10], t4);                                                \
        addxcc  t1, sum, sum;                                                           \
-       ldd     [src + off + 0x18], t6;                                                 \
+       EX(ldd  [src + off + 0x18], t6);                                                \
        addxcc  t2, sum, sum;                                                           \
-       std     t0, [dst + off + 0x00];                                                 \
+       EX(std  t0, [dst + off + 0x00]);                                                \
        addxcc  t3, sum, sum;                                                           \
-       std     t2, [dst + off + 0x08];                                                 \
+       EX(std  t2, [dst + off + 0x08]);                                                \
        addxcc  t4, sum, sum;                                                           \
-       std     t4, [dst + off + 0x10];                                                 \
+       EX(std  t4, [dst + off + 0x10]);                                                \
        addxcc  t5, sum, sum;                                                           \
-       std     t6, [dst + off + 0x18];                                                 \
+       EX(std  t6, [dst + off + 0x18]);                                                \
        addxcc  t6, sum, sum;                                                           \
        addxcc  t7, sum, sum;
 
@@ -191,39 +184,39 @@ cpout:    retl                                            ! get outta here
         * Viking MXCC into streaming mode.  Ho hum...
         */
 #define CSUMCOPY_BIGCHUNK(src, dst, sum, off, t0, t1, t2, t3, t4, t5, t6, t7)  \
-       ldd     [src + off + 0x00], t0;                                         \
-       ldd     [src + off + 0x08], t2;                                         \
-       ldd     [src + off + 0x10], t4;                                         \
-       ldd     [src + off + 0x18], t6;                                         \
-       st      t0, [dst + off + 0x00];                                         \
+       EX(ldd  [src + off + 0x00], t0);                                        \
+       EX(ldd  [src + off + 0x08], t2);                                        \
+       EX(ldd  [src + off + 0x10], t4);                                        \
+       EX(ldd  [src + off + 0x18], t6);                                        \
+       EX(st   t0, [dst + off + 0x00]);                                        \
        addxcc  t0, sum, sum;                                                   \
-       st      t1, [dst + off + 0x04];                                         \
+       EX(st   t1, [dst + off + 0x04]);                                        \
        addxcc  t1, sum, sum;                                                   \
-       st      t2, [dst + off + 0x08];                                         \
+       EX(st   t2, [dst + off + 0x08]);                                        \
        addxcc  t2, sum, sum;                                                   \
-       st      t3, [dst + off + 0x0c];                                         \
+       EX(st   t3, [dst + off + 0x0c]);                                        \
        addxcc  t3, sum, sum;                                                   \
-       st      t4, [dst + off + 0x10];                                         \
+       EX(st   t4, [dst + off + 0x10]);                                        \
        addxcc  t4, sum, sum;                                                   \
-       st      t5, [dst + off + 0x14];                                         \
+       EX(st   t5, [dst + off + 0x14]);                                        \
        addxcc  t5, sum, sum;                                                   \
-       st      t6, [dst + off + 0x18];                                         \
+       EX(st   t6, [dst + off + 0x18]);                                        \
        addxcc  t6, sum, sum;                                                   \
-       st      t7, [dst + off + 0x1c];                                         \
+       EX(st   t7, [dst + off + 0x1c]);                                        \
        addxcc  t7, sum, sum;
 
        /* Yuck, 6 superscalar cycles... */
 #define CSUMCOPY_LASTCHUNK(src, dst, sum, off, t0, t1, t2, t3) \
-       ldd     [src - off - 0x08], t0;                         \
-       ldd     [src - off - 0x00], t2;                         \
+       EX(ldd  [src - off - 0x08], t0);                        \
+       EX(ldd  [src - off - 0x00], t2);                        \
        addxcc  t0, sum, sum;                                   \
-       st      t0, [dst - off - 0x08];                         \
+       EX(st   t0, [dst - off - 0x08]);                        \
        addxcc  t1, sum, sum;                                   \
-       st      t1, [dst - off - 0x04];                         \
+       EX(st   t1, [dst - off - 0x04]);                        \
        addxcc  t2, sum, sum;                                   \
-       st      t2, [dst - off - 0x00];                         \
+       EX(st   t2, [dst - off - 0x00]);                        \
        addxcc  t3, sum, sum;                                   \
-       st      t3, [dst - off + 0x04];
+       EX(st   t3, [dst - off + 0x04]);
 
        /* Handle the end cruft code out of band for better cache patterns. */
 cc_end_cruft:
@@ -331,7 +324,6 @@ __csum_partial_copy_sparc_generic:
        CSUMCOPY_BIGCHUNK(%o0,%o1,%g7,0x20,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
        CSUMCOPY_BIGCHUNK(%o0,%o1,%g7,0x40,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
        CSUMCOPY_BIGCHUNK(%o0,%o1,%g7,0x60,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
-10:    EXT(5b, 10b)                    ! note for exception handling
        sub     %g1, 128, %g1           ! detract from length
        addx    %g0, %g7, %g7           ! add in last carry bit
        andcc   %g1, 0xffffff80, %g0    ! more to csum?
@@ -356,8 +348,7 @@ cctbl:      CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x68,%g2,%g3,%g4,%g5)
        CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x28,%g2,%g3,%g4,%g5)
        CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x18,%g2,%g3,%g4,%g5)
        CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x08,%g2,%g3,%g4,%g5)
-12:    EXT(cctbl, 12b)                 ! note for exception table handling
-       addx    %g0, %g7, %g7
+12:    addx    %g0, %g7, %g7
        andcc   %o3, 0xf, %g0           ! check for low bits set
 ccte:  bne     cc_end_cruft            ! something left, handle it out of band
         andcc  %o3, 8, %g0             ! begin checks for that code
@@ -367,7 +358,6 @@ ccdbl:      CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x00,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o
        CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x20,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
        CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x40,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
        CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x60,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
-11:    EXT(ccdbl, 11b)                 ! note for exception table handling
        sub     %g1, 128, %g1           ! detract from length
        addx    %g0, %g7, %g7           ! add in last carry bit
        andcc   %g1, 0xffffff80, %g0    ! more to csum?
index dc72f2b..954572c 100644 (file)
 /* Work around cpp -rob */
 #define ALLOC #alloc
 #define EXECINSTR #execinstr
+
+#define EX_ENTRY(l1, l2)                       \
+       .section __ex_table,ALLOC;              \
+       .align  4;                              \
+       .word   l1, l2;                         \
+       .text;
+
 #define EX(x,y,a,b)                            \
 98:    x,y;                                    \
        .section .fixup,ALLOC,EXECINSTR;        \
        .align  4;                              \
-99:    ba fixupretl;                           \
-        a, b, %g3;                             \
-       .section __ex_table,ALLOC;              \
-       .align  4;                              \
-       .word   98b, 99b;                       \
-       .text;                                  \
-       .align  4
+99:    retl;                                   \
+        a, b, %o0;                             \
+       EX_ENTRY(98b, 99b)
 
 #define EX2(x,y,c,d,e,a,b)                     \
 98:    x,y;                                    \
        .section .fixup,ALLOC,EXECINSTR;        \
        .align  4;                              \
 99:    c, d, e;                                \
-       ba fixupretl;                           \
-        a, b, %g3;                             \
-       .section __ex_table,ALLOC;              \
-       .align  4;                              \
-       .word   98b, 99b;                       \
-       .text;                                  \
-       .align  4
+       retl;                                   \
+        a, b, %o0;                             \
+       EX_ENTRY(98b, 99b)
 
 #define EXO2(x,y)                              \
 98:    x, y;                                   \
-       .section __ex_table,ALLOC;              \
-       .align  4;                              \
-       .word   98b, 97f;                       \
-       .text;                                  \
-       .align  4
+       EX_ENTRY(98b, 97f)
 
-#define EXT(start,end,handler)                 \
-       .section __ex_table,ALLOC;              \
-       .align  4;                              \
-       .word   start, 0, end, handler;         \
-       .text;                                  \
-       .align  4
+#define LD(insn, src, offset, reg, label)      \
+98:    insn [%src + (offset)], %reg;           \
+       .section .fixup,ALLOC,EXECINSTR;        \
+99:    ba      label;                          \
+        mov    offset, %g5;                    \
+       EX_ENTRY(98b, 99b)
 
-/* Please do not change following macros unless you change logic used
- * in .fixup at the end of this file as well
- */
+#define ST(insn, dst, offset, reg, label)      \
+98:    insn %reg, [%dst + (offset)];           \
+       .section .fixup,ALLOC,EXECINSTR;        \
+99:    ba      label;                          \
+        mov    offset, %g5;                    \
+       EX_ENTRY(98b, 99b)
 
 /* Both these macros have to start with exactly the same insn */
+/* left: g7 + (g1 % 128) - offset */
 #define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \
-       ldd     [%src + (offset) + 0x00], %t0; \
-       ldd     [%src + (offset) + 0x08], %t2; \
-       ldd     [%src + (offset) + 0x10], %t4; \
-       ldd     [%src + (offset) + 0x18], %t6; \
-       st      %t0, [%dst + (offset) + 0x00]; \
-       st      %t1, [%dst + (offset) + 0x04]; \
-       st      %t2, [%dst + (offset) + 0x08]; \
-       st      %t3, [%dst + (offset) + 0x0c]; \
-       st      %t4, [%dst + (offset) + 0x10]; \
-       st      %t5, [%dst + (offset) + 0x14]; \
-       st      %t6, [%dst + (offset) + 0x18]; \
-       st      %t7, [%dst + (offset) + 0x1c];
-
+       LD(ldd, src, offset + 0x00, t0, bigchunk_fault) \
+       LD(ldd, src, offset + 0x08, t2, bigchunk_fault) \
+       LD(ldd, src, offset + 0x10, t4, bigchunk_fault) \
+       LD(ldd, src, offset + 0x18, t6, bigchunk_fault) \
+       ST(st, dst, offset + 0x00, t0, bigchunk_fault)  \
+       ST(st, dst, offset + 0x04, t1, bigchunk_fault)  \
+       ST(st, dst, offset + 0x08, t2, bigchunk_fault)  \
+       ST(st, dst, offset + 0x0c, t3, bigchunk_fault)  \
+       ST(st, dst, offset + 0x10, t4, bigchunk_fault)  \
+       ST(st, dst, offset + 0x14, t5, bigchunk_fault)  \
+       ST(st, dst, offset + 0x18, t6, bigchunk_fault)  \
+       ST(st, dst, offset + 0x1c, t7, bigchunk_fault)
+
+/* left: g7 + (g1 % 128) - offset */
 #define MOVE_BIGALIGNCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \
-       ldd     [%src + (offset) + 0x00], %t0; \
-       ldd     [%src + (offset) + 0x08], %t2; \
-       ldd     [%src + (offset) + 0x10], %t4; \
-       ldd     [%src + (offset) + 0x18], %t6; \
-       std     %t0, [%dst + (offset) + 0x00]; \
-       std     %t2, [%dst + (offset) + 0x08]; \
-       std     %t4, [%dst + (offset) + 0x10]; \
-       std     %t6, [%dst + (offset) + 0x18];
+       LD(ldd, src, offset + 0x00, t0, bigchunk_fault) \
+       LD(ldd, src, offset + 0x08, t2, bigchunk_fault) \
+       LD(ldd, src, offset + 0x10, t4, bigchunk_fault) \
+       LD(ldd, src, offset + 0x18, t6, bigchunk_fault) \
+       ST(std, dst, offset + 0x00, t0, bigchunk_fault) \
+       ST(std, dst, offset + 0x08, t2, bigchunk_fault) \
+       ST(std, dst, offset + 0x10, t4, bigchunk_fault) \
+       ST(std, dst, offset + 0x18, t6, bigchunk_fault)
 
+       .section .fixup,#alloc,#execinstr
+bigchunk_fault:
+       sub     %g7, %g5, %o0
+       and     %g1, 127, %g1
+       retl
+        add    %o0, %g1, %o0
+
+/* left: offset + 16 + (g1 % 16) */
 #define MOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3) \
-       ldd     [%src - (offset) - 0x10], %t0; \
-       ldd     [%src - (offset) - 0x08], %t2; \
-       st      %t0, [%dst - (offset) - 0x10]; \
-       st      %t1, [%dst - (offset) - 0x0c]; \
-       st      %t2, [%dst - (offset) - 0x08]; \
-       st      %t3, [%dst - (offset) - 0x04];
+       LD(ldd, src, -(offset + 0x10), t0, lastchunk_fault)     \
+       LD(ldd, src, -(offset + 0x08), t2, lastchunk_fault)     \
+       ST(st, dst, -(offset + 0x10), t0, lastchunk_fault)      \
+       ST(st, dst, -(offset + 0x0c), t1, lastchunk_fault)      \
+       ST(st, dst, -(offset + 0x08), t2, lastchunk_fault)      \
+       ST(st, dst, -(offset + 0x04), t3, lastchunk_fault)
 
-#define MOVE_HALFCHUNK(src, dst, offset, t0, t1, t2, t3) \
-       lduh    [%src + (offset) + 0x00], %t0; \
-       lduh    [%src + (offset) + 0x02], %t1; \
-       lduh    [%src + (offset) + 0x04], %t2; \
-       lduh    [%src + (offset) + 0x06], %t3; \
-       sth     %t0, [%dst + (offset) + 0x00]; \
-       sth     %t1, [%dst + (offset) + 0x02]; \
-       sth     %t2, [%dst + (offset) + 0x04]; \
-       sth     %t3, [%dst + (offset) + 0x06];
+       .section .fixup,#alloc,#execinstr
+lastchunk_fault:
+       and     %g1, 15, %g1
+       retl
+        sub    %g1, %g5, %o0
 
+/* left: o3 + (o2 % 16) - offset */
+#define MOVE_HALFCHUNK(src, dst, offset, t0, t1, t2, t3) \
+       LD(lduh, src, offset + 0x00, t0, halfchunk_fault)       \
+       LD(lduh, src, offset + 0x02, t1, halfchunk_fault)       \
+       LD(lduh, src, offset + 0x04, t2, halfchunk_fault)       \
+       LD(lduh, src, offset + 0x06, t3, halfchunk_fault)       \
+       ST(sth, dst, offset + 0x00, t0, halfchunk_fault)        \
+       ST(sth, dst, offset + 0x02, t1, halfchunk_fault)        \
+       ST(sth, dst, offset + 0x04, t2, halfchunk_fault)        \
+       ST(sth, dst, offset + 0x06, t3, halfchunk_fault)
+
+/* left: o3 + (o2 % 16) + offset + 2 */
 #define MOVE_SHORTCHUNK(src, dst, offset, t0, t1) \
-       ldub    [%src - (offset) - 0x02], %t0; \
-       ldub    [%src - (offset) - 0x01], %t1; \
-       stb     %t0, [%dst - (offset) - 0x02]; \
-       stb     %t1, [%dst - (offset) - 0x01];
+       LD(ldub, src, -(offset + 0x02), t0, halfchunk_fault)    \
+       LD(ldub, src, -(offset + 0x01), t1, halfchunk_fault)    \
+       ST(stb, dst, -(offset + 0x02), t0, halfchunk_fault)     \
+       ST(stb, dst, -(offset + 0x01), t1, halfchunk_fault)
+
+       .section .fixup,#alloc,#execinstr
+halfchunk_fault:
+       and     %o2, 15, %o2
+       sub     %o3, %g5, %o3
+       retl
+        add    %o2, %o3, %o0
+
+/* left: offset + 2 + (o2 % 2) */
+#define MOVE_LAST_SHORTCHUNK(src, dst, offset, t0, t1) \
+       LD(ldub, src, -(offset + 0x02), t0, last_shortchunk_fault)      \
+       LD(ldub, src, -(offset + 0x01), t1, last_shortchunk_fault)      \
+       ST(stb, dst, -(offset + 0x02), t0, last_shortchunk_fault)       \
+       ST(stb, dst, -(offset + 0x01), t1, last_shortchunk_fault)
+
+       .section .fixup,#alloc,#execinstr
+last_shortchunk_fault:
+       and     %o2, 1, %o2
+       retl
+        sub    %o2, %g5, %o0
 
        .text
        .align  4
@@ -182,8 +218,6 @@ __copy_user:        /* %o0=dst %o1=src %o2=len */
        MOVE_BIGCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
        MOVE_BIGCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
        MOVE_BIGCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
-80:
-       EXT(5b, 80b, 50f)
        subcc   %g7, 128, %g7
        add     %o1, 128, %o1
        bne     5b
@@ -201,7 +235,6 @@ __copy_user:        /* %o0=dst %o1=src %o2=len */
        jmpl    %o5 + %lo(copy_user_table_end), %g0
         add    %o0, %g7, %o0
 
-copy_user_table:
        MOVE_LASTCHUNK(o1, o0, 0x60, g2, g3, g4, g5)
        MOVE_LASTCHUNK(o1, o0, 0x50, g2, g3, g4, g5)
        MOVE_LASTCHUNK(o1, o0, 0x40, g2, g3, g4, g5)
@@ -210,7 +243,6 @@ copy_user_table:
        MOVE_LASTCHUNK(o1, o0, 0x10, g2, g3, g4, g5)
        MOVE_LASTCHUNK(o1, o0, 0x00, g2, g3, g4, g5)
 copy_user_table_end:
-       EXT(copy_user_table, copy_user_table_end, 51f)
        be      copy_user_last7
         andcc  %g1, 4, %g0
 
@@ -250,8 +282,6 @@ ldd_std:
        MOVE_BIGALIGNCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
        MOVE_BIGALIGNCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
        MOVE_BIGALIGNCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
-81:
-       EXT(ldd_std, 81b, 52f)
        subcc   %g7, 128, %g7
        add     %o1, 128, %o1
        bne     ldd_std
@@ -290,8 +320,6 @@ cannot_optimize:
 10:
        MOVE_HALFCHUNK(o1, o0, 0x00, g2, g3, g4, g5)
        MOVE_HALFCHUNK(o1, o0, 0x08, g2, g3, g4, g5)
-82:
-       EXT(10b, 82b, 53f)
        subcc   %o3, 0x10, %o3
        add     %o1, 0x10, %o1
        bne     10b
@@ -308,8 +336,6 @@ byte_chunk:
        MOVE_SHORTCHUNK(o1, o0, -0x0c, g2, g3)
        MOVE_SHORTCHUNK(o1, o0, -0x0e, g2, g3)
        MOVE_SHORTCHUNK(o1, o0, -0x10, g2, g3)
-83:
-       EXT(byte_chunk, 83b, 54f)
        subcc   %o3, 0x10, %o3
        add     %o1, 0x10, %o1
        bne     byte_chunk
@@ -325,16 +351,14 @@ short_end:
        add     %o1, %o3, %o1
        jmpl    %o5 + %lo(short_table_end), %g0
         andcc  %o2, 1, %g0
-84:
-       MOVE_SHORTCHUNK(o1, o0, 0x0c, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, 0x0a, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, 0x08, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, 0x06, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, 0x04, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, 0x02, g2, g3)
-       MOVE_SHORTCHUNK(o1, o0, 0x00, g2, g3)
+       MOVE_LAST_SHORTCHUNK(o1, o0, 0x0c, g2, g3)
+       MOVE_LAST_SHORTCHUNK(o1, o0, 0x0a, g2, g3)
+       MOVE_LAST_SHORTCHUNK(o1, o0, 0x08, g2, g3)
+       MOVE_LAST_SHORTCHUNK(o1, o0, 0x06, g2, g3)
+       MOVE_LAST_SHORTCHUNK(o1, o0, 0x04, g2, g3)
+       MOVE_LAST_SHORTCHUNK(o1, o0, 0x02, g2, g3)
+       MOVE_LAST_SHORTCHUNK(o1, o0, 0x00, g2, g3)
 short_table_end:
-       EXT(84b, short_table_end, 55f)
        be      1f
         nop
        EX(ldub [%o1], %g2, add %g0, 1)
@@ -363,123 +387,8 @@ short_aligned_end:
        .section .fixup,#alloc,#execinstr
        .align  4
 97:
-       mov     %o2, %g3
-fixupretl:
        retl
-        mov    %g3, %o0
-
-/* exception routine sets %g2 to (broken_insn - first_insn)>>2 */
-50:
-/* This magic counts how many bytes are left when crash in MOVE_BIGCHUNK
- * happens. This is derived from the amount ldd reads, st stores, etc.
- * x = g2 % 12;
- * g3 = g1 + g7 - ((g2 / 12) * 32 + (x < 4) ? 0 : (x - 4) * 4);
- * o0 += (g2 / 12) * 32;
- */
-       cmp     %g2, 12
-       add     %o0, %g7, %o0
-       bcs     1f
-        cmp    %g2, 24
-       bcs     2f
-        cmp    %g2, 36
-       bcs     3f
-        nop
-       sub     %g2, 12, %g2
-       sub     %g7, 32, %g7
-3:     sub     %g2, 12, %g2
-       sub     %g7, 32, %g7
-2:     sub     %g2, 12, %g2
-       sub     %g7, 32, %g7
-1:     cmp     %g2, 4
-       bcs,a   60f
-        clr    %g2
-       sub     %g2, 4, %g2
-       sll     %g2, 2, %g2
-60:    and     %g1, 0x7f, %g3
-       sub     %o0, %g7, %o0
-       add     %g3, %g7, %g3
-       ba      fixupretl
-        sub    %g3, %g2, %g3
-51:
-/* i = 41 - g2; j = i % 6;
- * g3 = (g1 & 15) + (i / 6) * 16 + (j < 4) ? (j + 1) * 4 : 16;
- * o0 -= (i / 6) * 16 + 16;
- */
-       neg     %g2
-       and     %g1, 0xf, %g1
-       add     %g2, 41, %g2
-       add     %o0, %g1, %o0
-1:     cmp     %g2, 6
-       bcs,a   2f
-        cmp    %g2, 4
-       add     %g1, 16, %g1
-       b       1b
-        sub    %g2, 6, %g2
-2:     bcc,a   2f
-        mov    16, %g2
-       inc     %g2
-       sll     %g2, 2, %g2
-2:     add     %g1, %g2, %g3
-       ba      fixupretl
-        sub    %o0, %g3, %o0
-52:
-/* g3 = g1 + g7 - (g2 / 8) * 32 + (g2 & 4) ? (g2 & 3) * 8 : 0;
-   o0 += (g2 / 8) * 32 */
-       andn    %g2, 7, %g4
-       add     %o0, %g7, %o0
-       andcc   %g2, 4, %g0
-       and     %g2, 3, %g2
-       sll     %g4, 2, %g4
-       sll     %g2, 3, %g2
-       bne     60b
-        sub    %g7, %g4, %g7
-       ba      60b
-        clr    %g2
-53:
-/* g3 = o3 + (o2 & 15) - (g2 & 8) - (g2 & 4) ? (g2 & 3) * 2 : 0;
-   o0 += (g2 & 8) */
-       and     %g2, 3, %g4
-       andcc   %g2, 4, %g0
-       and     %g2, 8, %g2
-       sll     %g4, 1, %g4
-       be      1f
-        add    %o0, %g2, %o0
-       add     %g2, %g4, %g2
-1:     and     %o2, 0xf, %g3
-       add     %g3, %o3, %g3
-       ba      fixupretl
-        sub    %g3, %g2, %g3
-54:
-/* g3 = o3 + (o2 & 15) - (g2 / 4) * 2 - (g2 & 2) ? (g2 & 1) : 0;
-   o0 += (g2 / 4) * 2 */
-       srl     %g2, 2, %o4
-       and     %g2, 1, %o5
-       srl     %g2, 1, %g2
-       add     %o4, %o4, %o4
-       and     %o5, %g2, %o5
-       and     %o2, 0xf, %o2
-       add     %o0, %o4, %o0
-       sub     %o3, %o5, %o3
-       sub     %o2, %o4, %o2
-       ba      fixupretl
-        add    %o2, %o3, %g3
-55:
-/* i = 27 - g2;
-   g3 = (o2 & 1) + i / 4 * 2 + !(i & 3);
-   o0 -= i / 4 * 2 + 1 */
-       neg     %g2
-       and     %o2, 1, %o2
-       add     %g2, 27, %g2
-       srl     %g2, 2, %o5
-       andcc   %g2, 3, %g0
-       mov     1, %g2
-       add     %o5, %o5, %o5
-       be,a    1f
-        clr    %g2
-1:     add     %g2, %o5, %g3
-       sub     %o0, %g3, %o0
-       ba      fixupretl
-        add    %g3, %o2, %g3
+        mov    %o2, %o0
 
        .globl  __copy_user_end
 __copy_user_end:
index f427f34..eaff682 100644 (file)
@@ -19,7 +19,7 @@
 98:    x,y;                                    \
        .section .fixup,ALLOC,EXECINSTR;        \
        .align  4;                              \
-99:    ba 30f;                                 \
+99:    retl;                                   \
         a, b, %o0;                             \
        .section __ex_table,ALLOC;              \
        .align  4;                              \
        .text;                                  \
        .align  4
 
-#define EXT(start,end,handler)                         \
+#define STORE(source, base, offset, n)         \
+98:    std source, [base + offset + n];        \
+       .section .fixup,ALLOC,EXECINSTR;        \
+       .align  4;                              \
+99:    ba 30f;                                 \
+        sub %o3, n - offset, %o3;              \
        .section __ex_table,ALLOC;              \
        .align  4;                              \
-       .word   start, 0, end, handler;         \
+       .word   98b, 99b;                       \
        .text;                                  \
-       .align  4
+       .align  4;
+
+#define STORE_LAST(source, base, offset, n)    \
+       EX(std source, [base - offset - n],     \
+          add %o1, offset + n);
 
 /* Please don't change these macros, unless you change the logic
  * in the .fixup section below as well.
  * Store 64 bytes at (BASE + OFFSET) using value SOURCE. */
-#define ZERO_BIG_BLOCK(base, offset, source)    \
-       std     source, [base + offset + 0x00]; \
-       std     source, [base + offset + 0x08]; \
-       std     source, [base + offset + 0x10]; \
-       std     source, [base + offset + 0x18]; \
-       std     source, [base + offset + 0x20]; \
-       std     source, [base + offset + 0x28]; \
-       std     source, [base + offset + 0x30]; \
-       std     source, [base + offset + 0x38];
+#define ZERO_BIG_BLOCK(base, offset, source)   \
+       STORE(source, base, offset, 0x00);      \
+       STORE(source, base, offset, 0x08);      \
+       STORE(source, base, offset, 0x10);      \
+       STORE(source, base, offset, 0x18);      \
+       STORE(source, base, offset, 0x20);      \
+       STORE(source, base, offset, 0x28);      \
+       STORE(source, base, offset, 0x30);      \
+       STORE(source, base, offset, 0x38);
 
 #define ZERO_LAST_BLOCKS(base, offset, source) \
-       std     source, [base - offset - 0x38]; \
-       std     source, [base - offset - 0x30]; \
-       std     source, [base - offset - 0x28]; \
-       std     source, [base - offset - 0x20]; \
-       std     source, [base - offset - 0x18]; \
-       std     source, [base - offset - 0x10]; \
-       std     source, [base - offset - 0x08]; \
-       std     source, [base - offset - 0x00];
+       STORE_LAST(source, base, offset, 0x38); \
+       STORE_LAST(source, base, offset, 0x30); \
+       STORE_LAST(source, base, offset, 0x28); \
+       STORE_LAST(source, base, offset, 0x20); \
+       STORE_LAST(source, base, offset, 0x18); \
+       STORE_LAST(source, base, offset, 0x10); \
+       STORE_LAST(source, base, offset, 0x08); \
+       STORE_LAST(source, base, offset, 0x00);
 
        .text
        .align 4
@@ -68,8 +77,6 @@ __bzero_begin:
        .globl  memset
        EXPORT_SYMBOL(__bzero)
        EXPORT_SYMBOL(memset)
-       .globl  __memset_start, __memset_end
-__memset_start:
 memset:
        mov     %o0, %g1
        mov     1, %g4
@@ -122,8 +129,6 @@ __bzero:
        ZERO_BIG_BLOCK(%o0, 0x00, %g2)
        subcc   %o3, 128, %o3
        ZERO_BIG_BLOCK(%o0, 0x40, %g2)
-11:
-       EXT(10b, 11b, 20f)
        bne     10b
         add    %o0, 128, %o0
 
@@ -138,11 +143,9 @@ __bzero:
        jmp     %o4
         add    %o0, %o2, %o0
 
-12:
        ZERO_LAST_BLOCKS(%o0, 0x48, %g2)
        ZERO_LAST_BLOCKS(%o0, 0x08, %g2)
 13:
-       EXT(12b, 13b, 21f)
        be      8f
         andcc  %o1, 4, %g0
 
@@ -182,37 +185,13 @@ __bzero:
 5:
        retl
         clr    %o0
-__memset_end:
 
        .section .fixup,#alloc,#execinstr
        .align  4
-20:
-       cmp     %g2, 8
-       bleu    1f
-        and    %o1, 0x7f, %o1
-       sub     %g2, 9, %g2
-       add     %o3, 64, %o3
-1:
-       sll     %g2, 3, %g2
-       add     %o3, %o1, %o0
-       b 30f
-        sub    %o0, %g2, %o0
-21:
-       mov     8, %o0
-       and     %o1, 7, %o1
-       sub     %o0, %g2, %o0
-       sll     %o0, 3, %o0
-       b 30f
-        add    %o0, %o1, %o0
 30:
-/* %o4 is faulting address, %o5 is %pc where fault occurred */
-       save    %sp, -104, %sp
-       mov     %i5, %o0
-       mov     %i7, %o1
-       call    lookup_fault
-        mov    %i4, %o2
-       ret
-        restore
+       and     %o1, 0x7f, %o1
+       retl
+        add    %o3, %o1, %o0
 
        .globl __bzero_end
 __bzero_end:
index 68db1f8..871354a 100644 (file)
@@ -8,7 +8,7 @@ ccflags-y := -Werror
 obj-$(CONFIG_SPARC64)   += ultra.o tlb.o tsb.o
 obj-y                   += fault_$(BITS).o
 obj-y                   += init_$(BITS).o
-obj-$(CONFIG_SPARC32)   += extable.o srmmu.o iommu.o io-unit.o
+obj-$(CONFIG_SPARC32)   += srmmu.o iommu.o io-unit.o
 obj-$(CONFIG_SPARC32)   += srmmu_access.o
 obj-$(CONFIG_SPARC32)   += hypersparc.o viking.o tsunami.o swift.o
 obj-$(CONFIG_SPARC32)   += leon_mm.o
diff --git a/arch/sparc/mm/extable.c b/arch/sparc/mm/extable.c
deleted file mode 100644 (file)
index 241b406..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * linux/arch/sparc/mm/extable.c
- */
-
-#include <linux/module.h>
-#include <linux/extable.h>
-#include <linux/uaccess.h>
-
-void sort_extable(struct exception_table_entry *start,
-                 struct exception_table_entry *finish)
-{
-}
-
-/* Caller knows they are in a range if ret->fixup == 0 */
-const struct exception_table_entry *
-search_extable(const struct exception_table_entry *base,
-              const size_t num,
-              unsigned long value)
-{
-       int i;
-
-       /* Single insn entries are encoded as:
-        *      word 1: insn address
-        *      word 2: fixup code address
-        *
-        * Range entries are encoded as:
-        *      word 1: first insn address
-        *      word 2: 0
-        *      word 3: last insn address + 4 bytes
-        *      word 4: fixup code address
-        *
-        * Deleted entries are encoded as:
-        *      word 1: unused
-        *      word 2: -1
-        *
-        * See asm/uaccess.h for more details.
-        */
-
-       /* 1. Try to find an exact match. */
-       for (i = 0; i < num; i++) {
-               if (base[i].fixup == 0) {
-                       /* A range entry, skip both parts. */
-                       i++;
-                       continue;
-               }
-
-               /* A deleted entry; see trim_init_extable */
-               if (base[i].fixup == -1)
-                       continue;
-
-               if (base[i].insn == value)
-                       return &base[i];
-       }
-
-       /* 2. Try to find a range match. */
-       for (i = 0; i < (num - 1); i++) {
-               if (base[i].fixup)
-                       continue;
-
-               if (base[i].insn <= value && base[i + 1].insn > value)
-                       return &base[i];
-
-               i++;
-       }
-
-        return NULL;
-}
-
-#ifdef CONFIG_MODULES
-/* We could memmove them around; easier to mark the trimmed ones. */
-void trim_init_extable(struct module *m)
-{
-       unsigned int i;
-       bool range;
-
-       for (i = 0; i < m->num_exentries; i += range ? 2 : 1) {
-               range = m->extable[i].fixup == 0;
-
-               if (within_module_init(m->extable[i].insn, m)) {
-                       m->extable[i].fixup = -1;
-                       if (range)
-                               m->extable[i+1].fixup = -1;
-               }
-               if (range)
-                       i++;
-       }
-}
-#endif /* CONFIG_MODULES */
-
-/* Special extable search, which handles ranges.  Returns fixup */
-unsigned long search_extables_range(unsigned long addr, unsigned long *g2)
-{
-       const struct exception_table_entry *entry;
-
-       entry = search_exception_tables(addr);
-       if (!entry)
-               return 0;
-
-       /* Inside range?  Fix g2 and return correct fixup */
-       if (!entry->fixup) {
-               *g2 = (addr - entry->insn) / 4;
-               return (entry + 1)->fixup;
-       }
-
-       return entry->fixup;
-}
index 40ce087..de2031c 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/interrupt.h>
 #include <linux/kdebug.h>
 #include <linux/uaccess.h>
+#include <linux/extable.h>
 
 #include <asm/page.h>
 #include <asm/openprom.h>
@@ -54,54 +55,6 @@ static void __noreturn unhandled_fault(unsigned long address,
        die_if_kernel("Oops", regs);
 }
 
-asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,
-                           unsigned long address)
-{
-       struct pt_regs regs;
-       unsigned long g2;
-       unsigned int insn;
-       int i;
-
-       i = search_extables_range(ret_pc, &g2);
-       switch (i) {
-       case 3:
-               /* load & store will be handled by fixup */
-               return 3;
-
-       case 1:
-               /* store will be handled by fixup, load will bump out */
-               /* for _to_ macros */
-               insn = *((unsigned int *) pc);
-               if ((insn >> 21) & 1)
-                       return 1;
-               break;
-
-       case 2:
-               /* load will be handled by fixup, store will bump out */
-               /* for _from_ macros */
-               insn = *((unsigned int *) pc);
-               if (!((insn >> 21) & 1) || ((insn>>19)&0x3f) == 15)
-                       return 2;
-               break;
-
-       default:
-               break;
-       }
-
-       memset(&regs, 0, sizeof(regs));
-       regs.pc = pc;
-       regs.npc = pc + 4;
-       __asm__ __volatile__(
-               "rd %%psr, %0\n\t"
-               "nop\n\t"
-               "nop\n\t"
-               "nop\n" : "=r" (regs.psr));
-       unhandled_fault(address, current, &regs);
-
-       /* Not reached */
-       return 0;
-}
-
 static inline void
 show_signal_msg(struct pt_regs *regs, int sig, int code,
                unsigned long address, struct task_struct *tsk)
@@ -162,8 +115,6 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
        struct vm_area_struct *vma;
        struct task_struct *tsk = current;
        struct mm_struct *mm = tsk->mm;
-       unsigned int fixup;
-       unsigned long g2;
        int from_user = !(regs->psr & PSR_PS);
        int code;
        vm_fault_t fault;
@@ -281,30 +232,19 @@ bad_area_nosemaphore:
 
        /* Is this in ex_table? */
 no_context:
-       g2 = regs->u_regs[UREG_G2];
        if (!from_user) {
-               fixup = search_extables_range(regs->pc, &g2);
-               /* Values below 10 are reserved for other things */
-               if (fixup > 10) {
-                       extern const unsigned int __memset_start[];
-                       extern const unsigned int __memset_end[];
+               const struct exception_table_entry *entry;
 
+               entry = search_exception_tables(regs->pc);
 #ifdef DEBUG_EXCEPTIONS
-                       printk("Exception: PC<%08lx> faddr<%08lx>\n",
-                              regs->pc, address);
-                       printk("EX_TABLE: insn<%08lx> fixup<%08x> g2<%08lx>\n",
-                               regs->pc, fixup, g2);
+               printk("Exception: PC<%08lx> faddr<%08lx>\n",
+                      regs->pc, address);
+               printk("EX_TABLE: insn<%08lx> fixup<%08x>\n",
+                       regs->pc, entry->fixup);
 #endif
-                       if ((regs->pc >= (unsigned long)__memset_start &&
-                            regs->pc < (unsigned long)__memset_end)) {
-                               regs->u_regs[UREG_I4] = address;
-                               regs->u_regs[UREG_I5] = regs->pc;
-                       }
-                       regs->u_regs[UREG_G2] = g2;
-                       regs->pc = fixup;
-                       regs->npc = regs->pc + 4;
-                       return;
-               }
+               regs->pc = entry->fixup;
+               regs->npc = regs->pc + 4;
+               return;
        }
 
        unhandled_fault(address, tsk, regs);
index ce750a9..ee55f10 100644 (file)
@@ -1,7 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 /* fault_32.c - visible as they are called from assembler */
-asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,
-                            unsigned long address);
 asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
                                unsigned long address);
 
index a2433ae..4efd39a 100644 (file)
@@ -128,7 +128,8 @@ static noinstr bool __do_fast_syscall_32(struct pt_regs *regs)
                regs->ax = -EFAULT;
 
                instrumentation_end();
-               syscall_exit_to_user_mode(regs);
+               local_irq_disable();
+               irqentry_exit_to_user_mode(regs);
                return false;
        }
 
index 541fdaf..0051cf5 100644 (file)
@@ -210,6 +210,8 @@ SYM_CODE_START(entry_SYSCALL_compat)
        /* Switch to the kernel stack */
        movq    PER_CPU_VAR(cpu_current_top_of_stack), %rsp
 
+SYM_INNER_LABEL(entry_SYSCALL_compat_safe_stack, SYM_L_GLOBAL)
+
        /* Construct struct pt_regs on stack */
        pushq   $__USER32_DS            /* pt_regs->ss */
        pushq   %r8                     /* pt_regs->sp */
index 6ddeed3..18df171 100644 (file)
@@ -81,7 +81,11 @@ DEFINE_STATIC_CALL_NULL(x86_pmu_swap_task_ctx, *x86_pmu.swap_task_ctx);
 DEFINE_STATIC_CALL_NULL(x86_pmu_drain_pebs,   *x86_pmu.drain_pebs);
 DEFINE_STATIC_CALL_NULL(x86_pmu_pebs_aliases, *x86_pmu.pebs_aliases);
 
-DEFINE_STATIC_CALL_NULL(x86_pmu_guest_get_msrs,  *x86_pmu.guest_get_msrs);
+/*
+ * This one is magic, it will get called even when PMU init fails (because
+ * there is no PMU), in which case it should simply return NULL.
+ */
+DEFINE_STATIC_CALL_RET0(x86_pmu_guest_get_msrs, *x86_pmu.guest_get_msrs);
 
 u64 __read_mostly hw_cache_event_ids
                                [PERF_COUNT_HW_CACHE_MAX]
@@ -1944,13 +1948,6 @@ static void _x86_pmu_read(struct perf_event *event)
        x86_perf_event_update(event);
 }
 
-static inline struct perf_guest_switch_msr *
-perf_guest_get_msrs_nop(int *nr)
-{
-       *nr = 0;
-       return NULL;
-}
-
 static int __init init_hw_perf_events(void)
 {
        struct x86_pmu_quirk *quirk;
@@ -2025,7 +2022,7 @@ static int __init init_hw_perf_events(void)
                x86_pmu.read = _x86_pmu_read;
 
        if (!x86_pmu.guest_get_msrs)
-               x86_pmu.guest_get_msrs = perf_guest_get_msrs_nop;
+               x86_pmu.guest_get_msrs = (void *)&__static_call_return0;
 
        x86_pmu_static_call_update();
 
index 5bac48d..37ce384 100644 (file)
@@ -3659,11 +3659,16 @@ static int intel_pmu_hw_config(struct perf_event *event)
                return ret;
 
        if (event->attr.precise_ip) {
+               if ((event->attr.config & INTEL_ARCH_EVENT_MASK) == INTEL_FIXED_VLBR_EVENT)
+                       return -EINVAL;
+
                if (!(event->attr.freq || (event->attr.wakeup_events && !event->attr.watermark))) {
                        event->hw.flags |= PERF_X86_EVENT_AUTO_RELOAD;
                        if (!(event->attr.sample_type &
-                             ~intel_pmu_large_pebs_flags(event)))
+                             ~intel_pmu_large_pebs_flags(event))) {
                                event->hw.flags |= PERF_X86_EVENT_LARGE_PEBS;
+                               event->attach_state |= PERF_ATTACH_SCHED_CB;
+                       }
                }
                if (x86_pmu.pebs_aliases)
                        x86_pmu.pebs_aliases(event);
@@ -3676,6 +3681,7 @@ static int intel_pmu_hw_config(struct perf_event *event)
                ret = intel_pmu_setup_lbr_filter(event);
                if (ret)
                        return ret;
+               event->attach_state |= PERF_ATTACH_SCHED_CB;
 
                /*
                 * BTS is set up earlier in this path, so don't account twice
index 7ebae18..d32b302 100644 (file)
@@ -2010,7 +2010,7 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs, struct perf_sample_d
                 */
                if (!pebs_status && cpuc->pebs_enabled &&
                        !(cpuc->pebs_enabled & (cpuc->pebs_enabled-1)))
-                       pebs_status = cpuc->pebs_enabled;
+                       pebs_status = p->status = cpuc->pebs_enabled;
 
                bit = find_first_bit((unsigned long *)&pebs_status,
                                        x86_pmu.max_pebs_events);
index a0f839a..98b4dae 100644 (file)
@@ -23,6 +23,8 @@ unsigned long insn_get_seg_base(struct pt_regs *regs, int seg_reg_idx);
 int insn_get_code_seg_params(struct pt_regs *regs);
 int insn_fetch_from_user(struct pt_regs *regs,
                         unsigned char buf[MAX_INSN_SIZE]);
+int insn_fetch_from_user_inatomic(struct pt_regs *regs,
+                                 unsigned char buf[MAX_INSN_SIZE]);
 bool insn_decode(struct insn *insn, struct pt_regs *regs,
                 unsigned char buf[MAX_INSN_SIZE], int buf_size);
 
index 877a402..3768819 100644 (file)
@@ -884,12 +884,29 @@ struct kvm_hv_syndbg {
        u64 options;
 };
 
+/* Current state of Hyper-V TSC page clocksource */
+enum hv_tsc_page_status {
+       /* TSC page was not set up or disabled */
+       HV_TSC_PAGE_UNSET = 0,
+       /* TSC page MSR was written by the guest, update pending */
+       HV_TSC_PAGE_GUEST_CHANGED,
+       /* TSC page MSR was written by KVM userspace, update pending */
+       HV_TSC_PAGE_HOST_CHANGED,
+       /* TSC page was properly set up and is currently active  */
+       HV_TSC_PAGE_SET,
+       /* TSC page is currently being updated and therefore is inactive */
+       HV_TSC_PAGE_UPDATING,
+       /* TSC page was set up with an inaccessible GPA */
+       HV_TSC_PAGE_BROKEN,
+};
+
 /* Hyper-V emulation context */
 struct kvm_hv {
        struct mutex hv_lock;
        u64 hv_guest_os_id;
        u64 hv_hypercall;
        u64 hv_tsc_page;
+       enum hv_tsc_page_status hv_tsc_page_status;
 
        /* Hyper-v based guest crash (NT kernel bugcheck) parameters */
        u64 hv_crash_param[HV_X64_MSR_CRASH_PARAMS];
@@ -931,6 +948,12 @@ enum kvm_irqchip_mode {
        KVM_IRQCHIP_SPLIT,        /* created with KVM_CAP_SPLIT_IRQCHIP */
 };
 
+struct kvm_x86_msr_filter {
+       u8 count;
+       bool default_allow:1;
+       struct msr_bitmap_range ranges[16];
+};
+
 #define APICV_INHIBIT_REASON_DISABLE    0
 #define APICV_INHIBIT_REASON_HYPERV     1
 #define APICV_INHIBIT_REASON_NESTED     2
@@ -963,7 +986,7 @@ struct kvm_arch {
        struct kvm_pit *vpit;
        atomic_t vapics_in_nmi_mode;
        struct mutex apic_map_lock;
-       struct kvm_apic_map *apic_map;
+       struct kvm_apic_map __rcu *apic_map;
        atomic_t apic_map_dirty;
 
        bool apic_access_page_done;
@@ -1025,18 +1048,13 @@ struct kvm_arch {
        bool guest_can_read_msr_platform_info;
        bool exception_payload_enabled;
 
+       bool bus_lock_detection_enabled;
+
        /* Deflect RDMSR and WRMSR to user space when they trigger a #GP */
        u32 user_space_msr_mask;
+       struct kvm_x86_msr_filter __rcu *msr_filter;
 
-       struct {
-               u8 count;
-               bool default_allow:1;
-               struct msr_bitmap_range ranges[16];
-       } msr_filter;
-
-       bool bus_lock_detection_enabled;
-
-       struct kvm_pmu_event_filter *pmu_event_filter;
+       struct kvm_pmu_event_filter __rcu *pmu_event_filter;
        struct task_struct *nx_lpage_recovery_thread;
 
 #ifdef CONFIG_X86_64
index dc6d149..f1b9ed5 100644 (file)
@@ -551,15 +551,6 @@ static inline void arch_thread_struct_whitelist(unsigned long *offset,
        *size = fpu_kernel_xstate_size;
 }
 
-/*
- * Thread-synchronous status.
- *
- * This is different from the flags in that nobody else
- * ever touches our thread-synchronous status, so we don't
- * have to worry about atomic accesses.
- */
-#define TS_COMPAT              0x0002  /* 32bit syscall active (64BIT)*/
-
 static inline void
 native_load_sp0(unsigned long sp0)
 {
index 2c35f1c..b6a9d51 100644 (file)
@@ -25,6 +25,7 @@ void __end_SYSENTER_singlestep_region(void);
 void entry_SYSENTER_compat(void);
 void __end_entry_SYSENTER_compat(void);
 void entry_SYSCALL_compat(void);
+void entry_SYSCALL_compat_safe_stack(void);
 void entry_INT80_compat(void);
 #ifdef CONFIG_XEN_PV
 void xen_entry_INT80_compat(void);
index d8324a2..409f661 100644 (file)
@@ -94,6 +94,8 @@ struct pt_regs {
 #include <asm/paravirt_types.h>
 #endif
 
+#include <asm/proto.h>
+
 struct cpuinfo_x86;
 struct task_struct;
 
@@ -175,6 +177,19 @@ static inline bool any_64bit_mode(struct pt_regs *regs)
 #ifdef CONFIG_X86_64
 #define current_user_stack_pointer()   current_pt_regs()->sp
 #define compat_user_stack_pointer()    current_pt_regs()->sp
+
+static inline bool ip_within_syscall_gap(struct pt_regs *regs)
+{
+       bool ret = (regs->ip >= (unsigned long)entry_SYSCALL_64 &&
+                   regs->ip <  (unsigned long)entry_SYSCALL_64_safe_stack);
+
+#ifdef CONFIG_IA32_EMULATION
+       ret = ret || (regs->ip >= (unsigned long)entry_SYSCALL_compat &&
+                     regs->ip <  (unsigned long)entry_SYSCALL_compat_safe_stack);
+#endif
+
+       return ret;
+}
 #endif
 
 static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
index 8b58d69..0bc9b08 100644 (file)
@@ -58,9 +58,8 @@ static __always_inline unsigned long smap_save(void)
        unsigned long flags;
 
        asm volatile ("# smap_save\n\t"
-                     ALTERNATIVE("jmp 1f", "", X86_FEATURE_SMAP)
-                     "pushf; pop %0; " __ASM_CLAC "\n\t"
-                     "1:"
+                     ALTERNATIVE("", "pushf; pop %0; " __ASM_CLAC "\n\t",
+                                 X86_FEATURE_SMAP)
                      : "=rm" (flags) : : "memory", "cc");
 
        return flags;
@@ -69,9 +68,8 @@ static __always_inline unsigned long smap_save(void)
 static __always_inline void smap_restore(unsigned long flags)
 {
        asm volatile ("# smap_restore\n\t"
-                     ALTERNATIVE("jmp 1f", "", X86_FEATURE_SMAP)
-                     "push %0; popf\n\t"
-                     "1:"
+                     ALTERNATIVE("", "push %0; popf\n\t",
+                                 X86_FEATURE_SMAP)
                      : : "g" (flags) : "memory", "cc");
 }
 
index 0d751d5..06b740b 100644 (file)
@@ -205,10 +205,23 @@ static inline int arch_within_stack_frames(const void * const stack,
 
 #endif
 
+/*
+ * Thread-synchronous status.
+ *
+ * This is different from the flags in that nobody else
+ * ever touches our thread-synchronous status, so we don't
+ * have to worry about atomic accesses.
+ */
+#define TS_COMPAT              0x0002  /* 32bit syscall active (64BIT)*/
+
+#ifndef __ASSEMBLY__
 #ifdef CONFIG_COMPAT
 #define TS_I386_REGS_POKED     0x0004  /* regs poked by 32-bit ptracer */
+
+#define arch_set_restart_data(restart) \
+       do { restart->arch_data = current_thread_info()->status; } while (0)
+
 #endif
-#ifndef __ASSEMBLY__
 
 #ifdef CONFIG_X86_32
 #define in_ia32_syscall() true
index bda4f2a..4f26700 100644 (file)
@@ -2342,6 +2342,11 @@ static int cpuid_to_apicid[] = {
        [0 ... NR_CPUS - 1] = -1,
 };
 
+bool arch_match_cpu_phys_id(int cpu, u64 phys_id)
+{
+       return phys_id == cpuid_to_apicid[cpu];
+}
+
 #ifdef CONFIG_SMP
 /**
  * apic_id_is_primary_thread - Check whether APIC ID belongs to a primary thread
index c3b60c3..73ff4dd 100644 (file)
@@ -1032,6 +1032,16 @@ static int mp_map_pin_to_irq(u32 gsi, int idx, int ioapic, int pin,
        if (idx >= 0 && test_bit(mp_irqs[idx].srcbus, mp_bus_not_pci)) {
                irq = mp_irqs[idx].srcbusirq;
                legacy = mp_is_legacy_irq(irq);
+               /*
+                * IRQ2 is unusable for historical reasons on systems which
+                * have a legacy PIC. See the comment vs. IRQ2 further down.
+                *
+                * If this gets removed at some point then the related code
+                * in lapic_assign_system_vectors() needs to be adjusted as
+                * well.
+                */
+               if (legacy && irq == PIC_CASCADE_IR)
+                       return -EINVAL;
        }
 
        mutex_lock(&ioapic_mutex);
index 373e5fa..51c7f52 100644 (file)
@@ -12,7 +12,7 @@
 
 #include "common.h"
 
-/* Ftrace callback handler for kprobes -- called under preepmt disabed */
+/* Ftrace callback handler for kprobes -- called under preepmt disabled */
 void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
                           struct ftrace_ops *ops, struct ftrace_regs *fregs)
 {
index 5e78e01..78bb0fa 100644 (file)
@@ -836,28 +836,25 @@ static void kvm_kick_cpu(int cpu)
 
 static void kvm_wait(u8 *ptr, u8 val)
 {
-       unsigned long flags;
-
        if (in_nmi())
                return;
 
-       local_irq_save(flags);
-
-       if (READ_ONCE(*ptr) != val)
-               goto out;
-
        /*
         * halt until it's our turn and kicked. Note that we do safe halt
         * for irq enabled case to avoid hang when lock info is overwritten
         * in irq spinlock slowpath and no spurious interrupt occur to save us.
         */
-       if (arch_irqs_disabled_flags(flags))
-               halt();
-       else
-               safe_halt();
+       if (irqs_disabled()) {
+               if (READ_ONCE(*ptr) == val)
+                       halt();
+       } else {
+               local_irq_disable();
 
-out:
-       local_irq_restore(flags);
+               if (READ_ONCE(*ptr) == val)
+                       safe_halt();
+
+               local_irq_enable();
+       }
 }
 
 #ifdef CONFIG_X86_32
index aa59374..1fc0962 100644 (file)
@@ -268,21 +268,20 @@ static void __init kvmclock_init_mem(void)
 
 static int __init kvm_setup_vsyscall_timeinfo(void)
 {
-#ifdef CONFIG_X86_64
-       u8 flags;
+       kvmclock_init_mem();
 
-       if (!per_cpu(hv_clock_per_cpu, 0) || !kvmclock_vsyscall)
-               return 0;
+#ifdef CONFIG_X86_64
+       if (per_cpu(hv_clock_per_cpu, 0) && kvmclock_vsyscall) {
+               u8 flags;
 
-       flags = pvclock_read_flags(&hv_clock_boot[0].pvti);
-       if (!(flags & PVCLOCK_TSC_STABLE_BIT))
-               return 0;
+               flags = pvclock_read_flags(&hv_clock_boot[0].pvti);
+               if (!(flags & PVCLOCK_TSC_STABLE_BIT))
+                       return 0;
 
-       kvm_clock.vdso_clock_mode = VDSO_CLOCKMODE_PVCLOCK;
+               kvm_clock.vdso_clock_mode = VDSO_CLOCKMODE_PVCLOCK;
+       }
 #endif
 
-       kvmclock_init_mem();
-
        return 0;
 }
 early_initcall(kvm_setup_vsyscall_timeinfo);
index 84c1821..04a780a 100644 (file)
@@ -121,8 +121,18 @@ static void __init setup_vc_stacks(int cpu)
        cea_set_pte((void *)vaddr, pa, PAGE_KERNEL);
 }
 
-static __always_inline bool on_vc_stack(unsigned long sp)
+static __always_inline bool on_vc_stack(struct pt_regs *regs)
 {
+       unsigned long sp = regs->sp;
+
+       /* User-mode RSP is not trusted */
+       if (user_mode(regs))
+               return false;
+
+       /* SYSCALL gap still has user-mode RSP */
+       if (ip_within_syscall_gap(regs))
+               return false;
+
        return ((sp >= __this_cpu_ist_bottom_va(VC)) && (sp < __this_cpu_ist_top_va(VC)));
 }
 
@@ -144,7 +154,7 @@ void noinstr __sev_es_ist_enter(struct pt_regs *regs)
        old_ist = __this_cpu_read(cpu_tss_rw.x86_tss.ist[IST_INDEX_VC]);
 
        /* Make room on the IST stack */
-       if (on_vc_stack(regs->sp))
+       if (on_vc_stack(regs))
                new_ist = ALIGN_DOWN(regs->sp, 8) - sizeof(old_ist);
        else
                new_ist = old_ist - sizeof(old_ist);
@@ -248,7 +258,7 @@ static enum es_result vc_decode_insn(struct es_em_ctxt *ctxt)
        int res;
 
        if (user_mode(ctxt->regs)) {
-               res = insn_fetch_from_user(ctxt->regs, buffer);
+               res = insn_fetch_from_user_inatomic(ctxt->regs, buffer);
                if (!res) {
                        ctxt->fi.vector     = X86_TRAP_PF;
                        ctxt->fi.error_code = X86_PF_INSTR | X86_PF_USER;
@@ -1248,13 +1258,12 @@ static __always_inline bool on_vc_fallback_stack(struct pt_regs *regs)
 DEFINE_IDTENTRY_VC_SAFE_STACK(exc_vmm_communication)
 {
        struct sev_es_runtime_data *data = this_cpu_read(runtime_data);
+       irqentry_state_t irq_state;
        struct ghcb_state state;
        struct es_em_ctxt ctxt;
        enum es_result result;
        struct ghcb *ghcb;
 
-       lockdep_assert_irqs_disabled();
-
        /*
         * Handle #DB before calling into !noinstr code to avoid recursive #DB.
         */
@@ -1263,6 +1272,8 @@ DEFINE_IDTENTRY_VC_SAFE_STACK(exc_vmm_communication)
                return;
        }
 
+       irq_state = irqentry_nmi_enter(regs);
+       lockdep_assert_irqs_disabled();
        instrumentation_begin();
 
        /*
@@ -1325,6 +1336,7 @@ DEFINE_IDTENTRY_VC_SAFE_STACK(exc_vmm_communication)
 
 out:
        instrumentation_end();
+       irqentry_nmi_exit(regs, irq_state);
 
        return;
 
index ea794a0..f306e85 100644 (file)
@@ -766,30 +766,8 @@ handle_signal(struct ksignal *ksig, struct pt_regs *regs)
 
 static inline unsigned long get_nr_restart_syscall(const struct pt_regs *regs)
 {
-       /*
-        * This function is fundamentally broken as currently
-        * implemented.
-        *
-        * The idea is that we want to trigger a call to the
-        * restart_block() syscall and that we want in_ia32_syscall(),
-        * in_x32_syscall(), etc. to match whatever they were in the
-        * syscall being restarted.  We assume that the syscall
-        * instruction at (regs->ip - 2) matches whatever syscall
-        * instruction we used to enter in the first place.
-        *
-        * The problem is that we can get here when ptrace pokes
-        * syscall-like values into regs even if we're not in a syscall
-        * at all.
-        *
-        * For now, we maintain historical behavior and guess based on
-        * stored state.  We could do better by saving the actual
-        * syscall arch in restart_block or (with caveats on x32) by
-        * checking if regs->ip points to 'int $0x80'.  The current
-        * behavior is incorrect if a tracer has a different bitness
-        * than the tracee.
-        */
 #ifdef CONFIG_IA32_EMULATION
-       if (current_thread_info()->status & (TS_COMPAT|TS_I386_REGS_POKED))
+       if (current->restart_block.arch_data & TS_COMPAT)
                return __NR_ia32_restart_syscall;
 #endif
 #ifdef CONFIG_X86_X32_ABI
index 7f5aec7..ac1874a 100644 (file)
@@ -694,8 +694,7 @@ asmlinkage __visible noinstr struct pt_regs *vc_switch_off_ist(struct pt_regs *r
         * In the SYSCALL entry path the RSP value comes from user-space - don't
         * trust it and switch to the current kernel stack
         */
-       if (regs->ip >= (unsigned long)entry_SYSCALL_64 &&
-           regs->ip <  (unsigned long)entry_SYSCALL_64_safe_stack) {
+       if (ip_within_syscall_gap(regs)) {
                sp = this_cpu_read(cpu_current_top_of_stack);
                goto sync;
        }
index 2a1d47f..a120253 100644 (file)
@@ -13,7 +13,7 @@
 
 #define orc_warn_current(args...)                                      \
 ({                                                                     \
-       if (state->task == current)                                     \
+       if (state->task == current && !state->error)                    \
                orc_warn(args);                                         \
 })
 
@@ -367,8 +367,8 @@ static bool deref_stack_regs(struct unwind_state *state, unsigned long addr,
        if (!stack_access_ok(state, addr, sizeof(struct pt_regs)))
                return false;
 
-       *ip = regs->ip;
-       *sp = regs->sp;
+       *ip = READ_ONCE_NOCHECK(regs->ip);
+       *sp = READ_ONCE_NOCHECK(regs->sp);
        return true;
 }
 
@@ -380,8 +380,8 @@ static bool deref_stack_iret_regs(struct unwind_state *state, unsigned long addr
        if (!stack_access_ok(state, addr, IRET_FRAME_SIZE))
                return false;
 
-       *ip = regs->ip;
-       *sp = regs->sp;
+       *ip = READ_ONCE_NOCHECK(regs->ip);
+       *sp = READ_ONCE_NOCHECK(regs->sp);
        return true;
 }
 
@@ -402,12 +402,12 @@ static bool get_reg(struct unwind_state *state, unsigned int reg_off,
                return false;
 
        if (state->full_regs) {
-               *val = ((unsigned long *)state->regs)[reg];
+               *val = READ_ONCE_NOCHECK(((unsigned long *)state->regs)[reg]);
                return true;
        }
 
        if (state->prev_regs) {
-               *val = ((unsigned long *)state->prev_regs)[reg];
+               *val = READ_ONCE_NOCHECK(((unsigned long *)state->prev_regs)[reg]);
                return true;
        }
 
index 58fa8c0..f98370a 100644 (file)
@@ -520,10 +520,10 @@ static u64 get_time_ref_counter(struct kvm *kvm)
        u64 tsc;
 
        /*
-        * The guest has not set up the TSC page or the clock isn't
-        * stable, fall back to get_kvmclock_ns.
+        * Fall back to get_kvmclock_ns() when TSC page hasn't been set up,
+        * is broken, disabled or being updated.
         */
-       if (!hv->tsc_ref.tsc_sequence)
+       if (hv->hv_tsc_page_status != HV_TSC_PAGE_SET)
                return div_u64(get_kvmclock_ns(kvm), 100);
 
        vcpu = kvm_get_vcpu(kvm, 0);
@@ -1077,6 +1077,21 @@ static bool compute_tsc_page_parameters(struct pvclock_vcpu_time_info *hv_clock,
        return true;
 }
 
+/*
+ * Don't touch TSC page values if the guest has opted for TSC emulation after
+ * migration. KVM doesn't fully support reenlightenment notifications and TSC
+ * access emulation and Hyper-V is known to expect the values in TSC page to
+ * stay constant before TSC access emulation is disabled from guest side
+ * (HV_X64_MSR_TSC_EMULATION_STATUS). KVM userspace is expected to preserve TSC
+ * frequency and guest visible TSC value across migration (and prevent it when
+ * TSC scaling is unsupported).
+ */
+static inline bool tsc_page_update_unsafe(struct kvm_hv *hv)
+{
+       return (hv->hv_tsc_page_status != HV_TSC_PAGE_GUEST_CHANGED) &&
+               hv->hv_tsc_emulation_control;
+}
+
 void kvm_hv_setup_tsc_page(struct kvm *kvm,
                           struct pvclock_vcpu_time_info *hv_clock)
 {
@@ -1087,7 +1102,8 @@ void kvm_hv_setup_tsc_page(struct kvm *kvm,
        BUILD_BUG_ON(sizeof(tsc_seq) != sizeof(hv->tsc_ref.tsc_sequence));
        BUILD_BUG_ON(offsetof(struct ms_hyperv_tsc_page, tsc_sequence) != 0);
 
-       if (!(hv->hv_tsc_page & HV_X64_MSR_TSC_REFERENCE_ENABLE))
+       if (hv->hv_tsc_page_status == HV_TSC_PAGE_BROKEN ||
+           hv->hv_tsc_page_status == HV_TSC_PAGE_UNSET)
                return;
 
        mutex_lock(&hv->hv_lock);
@@ -1101,7 +1117,15 @@ void kvm_hv_setup_tsc_page(struct kvm *kvm,
         */
        if (unlikely(kvm_read_guest(kvm, gfn_to_gpa(gfn),
                                    &tsc_seq, sizeof(tsc_seq))))
+               goto out_err;
+
+       if (tsc_seq && tsc_page_update_unsafe(hv)) {
+               if (kvm_read_guest(kvm, gfn_to_gpa(gfn), &hv->tsc_ref, sizeof(hv->tsc_ref)))
+                       goto out_err;
+
+               hv->hv_tsc_page_status = HV_TSC_PAGE_SET;
                goto out_unlock;
+       }
 
        /*
         * While we're computing and writing the parameters, force the
@@ -1110,15 +1134,15 @@ void kvm_hv_setup_tsc_page(struct kvm *kvm,
        hv->tsc_ref.tsc_sequence = 0;
        if (kvm_write_guest(kvm, gfn_to_gpa(gfn),
                            &hv->tsc_ref, sizeof(hv->tsc_ref.tsc_sequence)))
-               goto out_unlock;
+               goto out_err;
 
        if (!compute_tsc_page_parameters(hv_clock, &hv->tsc_ref))
-               goto out_unlock;
+               goto out_err;
 
        /* Ensure sequence is zero before writing the rest of the struct.  */
        smp_wmb();
        if (kvm_write_guest(kvm, gfn_to_gpa(gfn), &hv->tsc_ref, sizeof(hv->tsc_ref)))
-               goto out_unlock;
+               goto out_err;
 
        /*
         * Now switch to the TSC page mechanism by writing the sequence.
@@ -1131,8 +1155,45 @@ void kvm_hv_setup_tsc_page(struct kvm *kvm,
        smp_wmb();
 
        hv->tsc_ref.tsc_sequence = tsc_seq;
-       kvm_write_guest(kvm, gfn_to_gpa(gfn),
-                       &hv->tsc_ref, sizeof(hv->tsc_ref.tsc_sequence));
+       if (kvm_write_guest(kvm, gfn_to_gpa(gfn),
+                           &hv->tsc_ref, sizeof(hv->tsc_ref.tsc_sequence)))
+               goto out_err;
+
+       hv->hv_tsc_page_status = HV_TSC_PAGE_SET;
+       goto out_unlock;
+
+out_err:
+       hv->hv_tsc_page_status = HV_TSC_PAGE_BROKEN;
+out_unlock:
+       mutex_unlock(&hv->hv_lock);
+}
+
+void kvm_hv_invalidate_tsc_page(struct kvm *kvm)
+{
+       struct kvm_hv *hv = to_kvm_hv(kvm);
+       u64 gfn;
+
+       if (hv->hv_tsc_page_status == HV_TSC_PAGE_BROKEN ||
+           hv->hv_tsc_page_status == HV_TSC_PAGE_UNSET ||
+           tsc_page_update_unsafe(hv))
+               return;
+
+       mutex_lock(&hv->hv_lock);
+
+       if (!(hv->hv_tsc_page & HV_X64_MSR_TSC_REFERENCE_ENABLE))
+               goto out_unlock;
+
+       /* Preserve HV_TSC_PAGE_GUEST_CHANGED/HV_TSC_PAGE_HOST_CHANGED states */
+       if (hv->hv_tsc_page_status == HV_TSC_PAGE_SET)
+               hv->hv_tsc_page_status = HV_TSC_PAGE_UPDATING;
+
+       gfn = hv->hv_tsc_page >> HV_X64_MSR_TSC_REFERENCE_ADDRESS_SHIFT;
+
+       hv->tsc_ref.tsc_sequence = 0;
+       if (kvm_write_guest(kvm, gfn_to_gpa(gfn),
+                           &hv->tsc_ref, sizeof(hv->tsc_ref.tsc_sequence)))
+               hv->hv_tsc_page_status = HV_TSC_PAGE_BROKEN;
+
 out_unlock:
        mutex_unlock(&hv->hv_lock);
 }
@@ -1193,8 +1254,15 @@ static int kvm_hv_set_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data,
        }
        case HV_X64_MSR_REFERENCE_TSC:
                hv->hv_tsc_page = data;
-               if (hv->hv_tsc_page & HV_X64_MSR_TSC_REFERENCE_ENABLE)
+               if (hv->hv_tsc_page & HV_X64_MSR_TSC_REFERENCE_ENABLE) {
+                       if (!host)
+                               hv->hv_tsc_page_status = HV_TSC_PAGE_GUEST_CHANGED;
+                       else
+                               hv->hv_tsc_page_status = HV_TSC_PAGE_HOST_CHANGED;
                        kvm_make_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu);
+               } else {
+                       hv->hv_tsc_page_status = HV_TSC_PAGE_UNSET;
+               }
                break;
        case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4:
                return kvm_hv_msr_set_crash_data(kvm,
@@ -1229,6 +1297,9 @@ static int kvm_hv_set_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data,
                hv->hv_tsc_emulation_control = data;
                break;
        case HV_X64_MSR_TSC_EMULATION_STATUS:
+               if (data && !host)
+                       return 1;
+
                hv->hv_tsc_emulation_status = data;
                break;
        case HV_X64_MSR_TIME_REF_COUNT:
index e951af1..60547d5 100644 (file)
@@ -133,6 +133,7 @@ void kvm_hv_process_stimers(struct kvm_vcpu *vcpu);
 
 void kvm_hv_setup_tsc_page(struct kvm *kvm,
                           struct pvclock_vcpu_time_info *hv_clock);
+void kvm_hv_invalidate_tsc_page(struct kvm *kvm);
 
 void kvm_hv_init_vm(struct kvm *kvm);
 void kvm_hv_destroy_vm(struct kvm *kvm);
index 45d40bf..cc369b9 100644 (file)
@@ -1642,7 +1642,16 @@ static void apic_timer_expired(struct kvm_lapic *apic, bool from_timer_fn)
        }
 
        if (kvm_use_posted_timer_interrupt(apic->vcpu)) {
-               kvm_wait_lapic_expire(vcpu);
+               /*
+                * Ensure the guest's timer has truly expired before posting an
+                * interrupt.  Open code the relevant checks to avoid querying
+                * lapic_timer_int_injected(), which will be false since the
+                * interrupt isn't yet injected.  Waiting until after injecting
+                * is not an option since that won't help a posted interrupt.
+                */
+               if (vcpu->arch.apic->lapic_timer.expired_tscdeadline &&
+                   vcpu->arch.apic->lapic_timer.timer_advance_ns)
+                       __kvm_wait_lapic_expire(vcpu);
                kvm_apic_inject_pending_timer_irqs(apic);
                return;
        }
@@ -2595,6 +2604,7 @@ int kvm_apic_set_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s)
 
        apic_update_ppr(apic);
        hrtimer_cancel(&apic->lapic_timer.timer);
+       apic->lapic_timer.expired_tscdeadline = 0;
        apic_update_lvtt(apic);
        apic_manage_nmi_watchdog(apic, kvm_lapic_get_reg(apic, APIC_LVT0));
        update_divide_count(apic);
index ec4fc28..1f6f98c 100644 (file)
@@ -78,6 +78,11 @@ static inline struct kvm_mmu_page *sptep_to_sp(u64 *sptep)
        return to_shadow_page(__pa(sptep));
 }
 
+static inline int kvm_mmu_page_as_id(struct kvm_mmu_page *sp)
+{
+       return sp->role.smm ? 1 : 0;
+}
+
 static inline bool kvm_vcpu_ad_need_write_protect(struct kvm_vcpu *vcpu)
 {
        /*
index e5f1481..b3ed302 100644 (file)
@@ -20,6 +20,21 @@ static gfn_t round_gfn_for_level(gfn_t gfn, int level)
        return gfn & -KVM_PAGES_PER_HPAGE(level);
 }
 
+/*
+ * Return the TDP iterator to the root PT and allow it to continue its
+ * traversal over the paging structure from there.
+ */
+void tdp_iter_restart(struct tdp_iter *iter)
+{
+       iter->yielded_gfn = iter->next_last_level_gfn;
+       iter->level = iter->root_level;
+
+       iter->gfn = round_gfn_for_level(iter->next_last_level_gfn, iter->level);
+       tdp_iter_refresh_sptep(iter);
+
+       iter->valid = true;
+}
+
 /*
  * Sets a TDP iterator to walk a pre-order traversal of the paging structure
  * rooted at root_pt, starting with the walk to translate next_last_level_gfn.
@@ -31,16 +46,12 @@ void tdp_iter_start(struct tdp_iter *iter, u64 *root_pt, int root_level,
        WARN_ON(root_level > PT64_ROOT_MAX_LEVEL);
 
        iter->next_last_level_gfn = next_last_level_gfn;
-       iter->yielded_gfn = iter->next_last_level_gfn;
        iter->root_level = root_level;
        iter->min_level = min_level;
-       iter->level = root_level;
-       iter->pt_path[iter->level - 1] = (tdp_ptep_t)root_pt;
-
-       iter->gfn = round_gfn_for_level(iter->next_last_level_gfn, iter->level);
-       tdp_iter_refresh_sptep(iter);
+       iter->pt_path[iter->root_level - 1] = (tdp_ptep_t)root_pt;
+       iter->as_id = kvm_mmu_page_as_id(sptep_to_sp(root_pt));
 
-       iter->valid = true;
+       tdp_iter_restart(iter);
 }
 
 /*
@@ -159,8 +170,3 @@ void tdp_iter_next(struct tdp_iter *iter)
        iter->valid = false;
 }
 
-tdp_ptep_t tdp_iter_root_pt(struct tdp_iter *iter)
-{
-       return iter->pt_path[iter->root_level - 1];
-}
-
index 4cc177d..b1748b9 100644 (file)
@@ -36,6 +36,8 @@ struct tdp_iter {
        int min_level;
        /* The iterator's current level within the paging structure */
        int level;
+       /* The address space ID, i.e. SMM vs. regular. */
+       int as_id;
        /* A snapshot of the value at sptep */
        u64 old_spte;
        /*
@@ -62,6 +64,6 @@ tdp_ptep_t spte_to_child_pt(u64 pte, int level);
 void tdp_iter_start(struct tdp_iter *iter, u64 *root_pt, int root_level,
                    int min_level, gfn_t next_last_level_gfn);
 void tdp_iter_next(struct tdp_iter *iter);
-tdp_ptep_t tdp_iter_root_pt(struct tdp_iter *iter);
+void tdp_iter_restart(struct tdp_iter *iter);
 
 #endif /* __KVM_X86_MMU_TDP_ITER_H */
index c926c6b..462b1f7 100644 (file)
@@ -203,11 +203,6 @@ static void handle_changed_spte(struct kvm *kvm, int as_id, gfn_t gfn,
                                u64 old_spte, u64 new_spte, int level,
                                bool shared);
 
-static int kvm_mmu_page_as_id(struct kvm_mmu_page *sp)
-{
-       return sp->role.smm ? 1 : 0;
-}
-
 static void handle_changed_spte_acc_track(u64 old_spte, u64 new_spte, int level)
 {
        bool pfn_changed = spte_to_pfn(old_spte) != spte_to_pfn(new_spte);
@@ -301,11 +296,16 @@ static void tdp_mmu_unlink_page(struct kvm *kvm, struct kvm_mmu_page *sp,
  *
  * Given a page table that has been removed from the TDP paging structure,
  * iterates through the page table to clear SPTEs and free child page tables.
+ *
+ * Note that pt is passed in as a tdp_ptep_t, but it does not need RCU
+ * protection. Since this thread removed it from the paging structure,
+ * this thread will be responsible for ensuring the page is freed. Hence the
+ * early rcu_dereferences in the function.
  */
-static void handle_removed_tdp_mmu_page(struct kvm *kvm, u64 *pt,
+static void handle_removed_tdp_mmu_page(struct kvm *kvm, tdp_ptep_t pt,
                                        bool shared)
 {
-       struct kvm_mmu_page *sp = sptep_to_sp(pt);
+       struct kvm_mmu_page *sp = sptep_to_sp(rcu_dereference(pt));
        int level = sp->role.level;
        gfn_t base_gfn = sp->gfn;
        u64 old_child_spte;
@@ -318,7 +318,7 @@ static void handle_removed_tdp_mmu_page(struct kvm *kvm, u64 *pt,
        tdp_mmu_unlink_page(kvm, sp, shared);
 
        for (i = 0; i < PT64_ENT_PER_PAGE; i++) {
-               sptep = pt + i;
+               sptep = rcu_dereference(pt) + i;
                gfn = base_gfn + (i * KVM_PAGES_PER_HPAGE(level - 1));
 
                if (shared) {
@@ -337,7 +337,18 @@ static void handle_removed_tdp_mmu_page(struct kvm *kvm, u64 *pt,
                                cpu_relax();
                        }
                } else {
+                       /*
+                        * If the SPTE is not MMU-present, there is no backing
+                        * page associated with the SPTE and so no side effects
+                        * that need to be recorded, and exclusive ownership of
+                        * mmu_lock ensures the SPTE can't be made present.
+                        * Note, zapping MMIO SPTEs is also unnecessary as they
+                        * are guarded by the memslots generation, not by being
+                        * unreachable.
+                        */
                        old_child_spte = READ_ONCE(*sptep);
+                       if (!is_shadow_present_pte(old_child_spte))
+                               continue;
 
                        /*
                         * Marking the SPTE as a removed SPTE is not
@@ -481,10 +492,6 @@ static inline bool tdp_mmu_set_spte_atomic(struct kvm *kvm,
                                           struct tdp_iter *iter,
                                           u64 new_spte)
 {
-       u64 *root_pt = tdp_iter_root_pt(iter);
-       struct kvm_mmu_page *root = sptep_to_sp(root_pt);
-       int as_id = kvm_mmu_page_as_id(root);
-
        lockdep_assert_held_read(&kvm->mmu_lock);
 
        /*
@@ -498,8 +505,8 @@ static inline bool tdp_mmu_set_spte_atomic(struct kvm *kvm,
                      new_spte) != iter->old_spte)
                return false;
 
-       handle_changed_spte(kvm, as_id, iter->gfn, iter->old_spte, new_spte,
-                           iter->level, true);
+       handle_changed_spte(kvm, iter->as_id, iter->gfn, iter->old_spte,
+                           new_spte, iter->level, true);
 
        return true;
 }
@@ -527,7 +534,7 @@ static inline bool tdp_mmu_zap_spte_atomic(struct kvm *kvm,
         * here since the SPTE is going from non-present
         * to non-present.
         */
-       WRITE_ONCE(*iter->sptep, 0);
+       WRITE_ONCE(*rcu_dereference(iter->sptep), 0);
 
        return true;
 }
@@ -553,10 +560,6 @@ static inline void __tdp_mmu_set_spte(struct kvm *kvm, struct tdp_iter *iter,
                                      u64 new_spte, bool record_acc_track,
                                      bool record_dirty_log)
 {
-       tdp_ptep_t root_pt = tdp_iter_root_pt(iter);
-       struct kvm_mmu_page *root = sptep_to_sp(root_pt);
-       int as_id = kvm_mmu_page_as_id(root);
-
        lockdep_assert_held_write(&kvm->mmu_lock);
 
        /*
@@ -570,13 +573,13 @@ static inline void __tdp_mmu_set_spte(struct kvm *kvm, struct tdp_iter *iter,
 
        WRITE_ONCE(*rcu_dereference(iter->sptep), new_spte);
 
-       __handle_changed_spte(kvm, as_id, iter->gfn, iter->old_spte, new_spte,
-                             iter->level, false);
+       __handle_changed_spte(kvm, iter->as_id, iter->gfn, iter->old_spte,
+                             new_spte, iter->level, false);
        if (record_acc_track)
                handle_changed_spte_acc_track(iter->old_spte, new_spte,
                                              iter->level);
        if (record_dirty_log)
-               handle_changed_spte_dirty_log(kvm, as_id, iter->gfn,
+               handle_changed_spte_dirty_log(kvm, iter->as_id, iter->gfn,
                                              iter->old_spte, new_spte,
                                              iter->level);
 }
@@ -648,9 +651,7 @@ static inline bool tdp_mmu_iter_cond_resched(struct kvm *kvm,
 
                WARN_ON(iter->gfn > iter->next_last_level_gfn);
 
-               tdp_iter_start(iter, iter->pt_path[iter->root_level - 1],
-                              iter->root_level, iter->min_level,
-                              iter->next_last_level_gfn);
+               tdp_iter_restart(iter);
 
                return true;
        }
index baee91c..58a45bb 100644 (file)
@@ -115,13 +115,6 @@ static const struct svm_direct_access_msrs {
        { .index = MSR_INVALID,                         .always = false },
 };
 
-/* enable NPT for AMD64 and X86 with PAE */
-#if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE)
-bool npt_enabled = true;
-#else
-bool npt_enabled;
-#endif
-
 /*
  * These 2 parameters are used to config the controls for Pause-Loop Exiting:
  * pause_filter_count: On processors that support Pause filtering(indicated
@@ -170,9 +163,12 @@ module_param(pause_filter_count_shrink, ushort, 0444);
 static unsigned short pause_filter_count_max = KVM_SVM_DEFAULT_PLE_WINDOW_MAX;
 module_param(pause_filter_count_max, ushort, 0444);
 
-/* allow nested paging (virtualized MMU) for all guests */
-static int npt = true;
-module_param(npt, int, S_IRUGO);
+/*
+ * Use nested page tables by default.  Note, NPT may get forced off by
+ * svm_hardware_setup() if it's unsupported by hardware or the host kernel.
+ */
+bool npt_enabled = true;
+module_param_named(npt, npt_enabled, bool, 0444);
 
 /* allow nested virtualization in KVM/SVM */
 static int nested = true;
@@ -988,10 +984,15 @@ static __init int svm_hardware_setup(void)
                        goto err;
        }
 
-       if (!boot_cpu_has(X86_FEATURE_NPT))
+       /*
+        * KVM's MMU doesn't support using 2-level paging for itself, and thus
+        * NPT isn't supported if the host is using 2-level paging since host
+        * CR4 is unchanged on VMRUN.
+        */
+       if (!IS_ENABLED(CONFIG_X86_64) && !IS_ENABLED(CONFIG_X86_PAE))
                npt_enabled = false;
 
-       if (npt_enabled && !npt)
+       if (!boot_cpu_has(X86_FEATURE_NPT))
                npt_enabled = false;
 
        kvm_configure_mmu(npt_enabled, get_max_npt_level(), PG_LEVEL_1G);
index 50810d4..32cf828 100644 (file)
@@ -6580,8 +6580,8 @@ static void atomic_switch_perf_msrs(struct vcpu_vmx *vmx)
        int i, nr_msrs;
        struct perf_guest_switch_msr *msrs;
 
+       /* Note, nr_msrs may be garbage if perf_guest_get_msrs() returns NULL. */
        msrs = perf_guest_get_msrs(&nr_msrs);
-
        if (!msrs)
                return;
 
index 2a20ce6..fe806e8 100644 (file)
@@ -1526,35 +1526,44 @@ EXPORT_SYMBOL_GPL(kvm_enable_efer_bits);
 
 bool kvm_msr_allowed(struct kvm_vcpu *vcpu, u32 index, u32 type)
 {
+       struct kvm_x86_msr_filter *msr_filter;
+       struct msr_bitmap_range *ranges;
        struct kvm *kvm = vcpu->kvm;
-       struct msr_bitmap_range *ranges = kvm->arch.msr_filter.ranges;
-       u32 count = kvm->arch.msr_filter.count;
-       u32 i;
-       bool r = kvm->arch.msr_filter.default_allow;
+       bool allowed;
        int idx;
+       u32 i;
 
-       /* MSR filtering not set up or x2APIC enabled, allow everything */
-       if (!count || (index >= 0x800 && index <= 0x8ff))
+       /* x2APIC MSRs do not support filtering. */
+       if (index >= 0x800 && index <= 0x8ff)
                return true;
 
-       /* Prevent collision with set_msr_filter */
        idx = srcu_read_lock(&kvm->srcu);
 
-       for (i = 0; i < count; i++) {
+       msr_filter = srcu_dereference(kvm->arch.msr_filter, &kvm->srcu);
+       if (!msr_filter) {
+               allowed = true;
+               goto out;
+       }
+
+       allowed = msr_filter->default_allow;
+       ranges = msr_filter->ranges;
+
+       for (i = 0; i < msr_filter->count; i++) {
                u32 start = ranges[i].base;
                u32 end = start + ranges[i].nmsrs;
                u32 flags = ranges[i].flags;
                unsigned long *bitmap = ranges[i].bitmap;
 
                if ((index >= start) && (index < end) && (flags & type)) {
-                       r = !!test_bit(index - start, bitmap);
+                       allowed = !!test_bit(index - start, bitmap);
                        break;
                }
        }
 
+out:
        srcu_read_unlock(&kvm->srcu, idx);
 
-       return r;
+       return allowed;
 }
 EXPORT_SYMBOL_GPL(kvm_msr_allowed);
 
@@ -2551,6 +2560,8 @@ static void kvm_gen_update_masterclock(struct kvm *kvm)
        struct kvm_vcpu *vcpu;
        struct kvm_arch *ka = &kvm->arch;
 
+       kvm_hv_invalidate_tsc_page(kvm);
+
        spin_lock(&ka->pvclock_gtod_sync_lock);
        kvm_make_mclock_inprogress_request(kvm);
        /* no guest entries from this point */
@@ -5352,25 +5363,34 @@ split_irqchip_unlock:
        return r;
 }
 
-static void kvm_clear_msr_filter(struct kvm *kvm)
+static struct kvm_x86_msr_filter *kvm_alloc_msr_filter(bool default_allow)
+{
+       struct kvm_x86_msr_filter *msr_filter;
+
+       msr_filter = kzalloc(sizeof(*msr_filter), GFP_KERNEL_ACCOUNT);
+       if (!msr_filter)
+               return NULL;
+
+       msr_filter->default_allow = default_allow;
+       return msr_filter;
+}
+
+static void kvm_free_msr_filter(struct kvm_x86_msr_filter *msr_filter)
 {
        u32 i;
-       u32 count = kvm->arch.msr_filter.count;
-       struct msr_bitmap_range ranges[16];
 
-       mutex_lock(&kvm->lock);
-       kvm->arch.msr_filter.count = 0;
-       memcpy(ranges, kvm->arch.msr_filter.ranges, count * sizeof(ranges[0]));
-       mutex_unlock(&kvm->lock);
-       synchronize_srcu(&kvm->srcu);
+       if (!msr_filter)
+               return;
+
+       for (i = 0; i < msr_filter->count; i++)
+               kfree(msr_filter->ranges[i].bitmap);
 
-       for (i = 0; i < count; i++)
-               kfree(ranges[i].bitmap);
+       kfree(msr_filter);
 }
 
-static int kvm_add_msr_filter(struct kvm *kvm, struct kvm_msr_filter_range *user_range)
+static int kvm_add_msr_filter(struct kvm_x86_msr_filter *msr_filter,
+                             struct kvm_msr_filter_range *user_range)
 {
-       struct msr_bitmap_range *ranges = kvm->arch.msr_filter.ranges;
        struct msr_bitmap_range range;
        unsigned long *bitmap = NULL;
        size_t bitmap_size;
@@ -5404,11 +5424,9 @@ static int kvm_add_msr_filter(struct kvm *kvm, struct kvm_msr_filter_range *user
                goto err;
        }
 
-       /* Everything ok, add this range identifier to our global pool */
-       ranges[kvm->arch.msr_filter.count] = range;
-       /* Make sure we filled the array before we tell anyone to walk it */
-       smp_wmb();
-       kvm->arch.msr_filter.count++;
+       /* Everything ok, add this range identifier. */
+       msr_filter->ranges[msr_filter->count] = range;
+       msr_filter->count++;
 
        return 0;
 err:
@@ -5419,10 +5437,11 @@ err:
 static int kvm_vm_ioctl_set_msr_filter(struct kvm *kvm, void __user *argp)
 {
        struct kvm_msr_filter __user *user_msr_filter = argp;
+       struct kvm_x86_msr_filter *new_filter, *old_filter;
        struct kvm_msr_filter filter;
        bool default_allow;
-       int r = 0;
        bool empty = true;
+       int r = 0;
        u32 i;
 
        if (copy_from_user(&filter, user_msr_filter, sizeof(filter)))
@@ -5435,25 +5454,32 @@ static int kvm_vm_ioctl_set_msr_filter(struct kvm *kvm, void __user *argp)
        if (empty && !default_allow)
                return -EINVAL;
 
-       kvm_clear_msr_filter(kvm);
-
-       kvm->arch.msr_filter.default_allow = default_allow;
+       new_filter = kvm_alloc_msr_filter(default_allow);
+       if (!new_filter)
+               return -ENOMEM;
 
-       /*
-        * Protect from concurrent calls to this function that could trigger
-        * a TOCTOU violation on kvm->arch.msr_filter.count.
-        */
-       mutex_lock(&kvm->lock);
        for (i = 0; i < ARRAY_SIZE(filter.ranges); i++) {
-               r = kvm_add_msr_filter(kvm, &filter.ranges[i]);
-               if (r)
-                       break;
+               r = kvm_add_msr_filter(new_filter, &filter.ranges[i]);
+               if (r) {
+                       kvm_free_msr_filter(new_filter);
+                       return r;
+               }
        }
 
+       mutex_lock(&kvm->lock);
+
+       /* The per-VM filter is protected by kvm->lock... */
+       old_filter = srcu_dereference_check(kvm->arch.msr_filter, &kvm->srcu, 1);
+
+       rcu_assign_pointer(kvm->arch.msr_filter, new_filter);
+       synchronize_srcu(&kvm->srcu);
+
+       kvm_free_msr_filter(old_filter);
+
        kvm_make_all_cpus_request(kvm, KVM_REQ_MSR_FILTER_CHANGED);
        mutex_unlock(&kvm->lock);
 
-       return r;
+       return 0;
 }
 
 long kvm_arch_vm_ioctl(struct file *filp,
@@ -6603,7 +6629,7 @@ static int kvm_emulate_wbinvd_noskip(struct kvm_vcpu *vcpu)
                int cpu = get_cpu();
 
                cpumask_set_cpu(cpu, vcpu->arch.wbinvd_dirty_mask);
-               smp_call_function_many(vcpu->arch.wbinvd_dirty_mask,
+               on_each_cpu_mask(vcpu->arch.wbinvd_dirty_mask,
                                wbinvd_ipi, NULL, 1);
                put_cpu();
                cpumask_clear(vcpu->arch.wbinvd_dirty_mask);
@@ -10601,7 +10627,7 @@ void __user * __x86_set_memory_region(struct kvm *kvm, int id, gpa_t gpa,
                        return (void __user *)hva;
        } else {
                if (!slot || !slot->npages)
-                       return 0;
+                       return NULL;
 
                old_npages = slot->npages;
                hva = slot->userspace_addr;
@@ -10634,8 +10660,6 @@ void kvm_arch_pre_destroy_vm(struct kvm *kvm)
 
 void kvm_arch_destroy_vm(struct kvm *kvm)
 {
-       u32 i;
-
        if (current->mm == kvm->mm) {
                /*
                 * Free memory regions allocated on behalf of userspace,
@@ -10651,8 +10675,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
                mutex_unlock(&kvm->slots_lock);
        }
        static_call_cond(kvm_x86_vm_destroy)(kvm);
-       for (i = 0; i < kvm->arch.msr_filter.count; i++)
-               kfree(kvm->arch.msr_filter.ranges[i].bitmap);
+       kvm_free_msr_filter(srcu_dereference_check(kvm->arch.msr_filter, &kvm->srcu, 1));
        kvm_pic_destroy(kvm);
        kvm_ioapic_destroy(kvm);
        kvm_free_vcpus(kvm);
index 4229950..bb0b3fe 100644 (file)
@@ -1415,6 +1415,25 @@ void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs)
        }
 }
 
+static unsigned long insn_get_effective_ip(struct pt_regs *regs)
+{
+       unsigned long seg_base = 0;
+
+       /*
+        * If not in user-space long mode, a custom code segment could be in
+        * use. This is true in protected mode (if the process defined a local
+        * descriptor table), or virtual-8086 mode. In most of the cases
+        * seg_base will be zero as in USER_CS.
+        */
+       if (!user_64bit_mode(regs)) {
+               seg_base = insn_get_seg_base(regs, INAT_SEG_REG_CS);
+               if (seg_base == -1L)
+                       return 0;
+       }
+
+       return seg_base + regs->ip;
+}
+
 /**
  * insn_fetch_from_user() - Copy instruction bytes from user-space memory
  * @regs:      Structure with register values as seen when entering kernel mode
@@ -1431,24 +1450,43 @@ void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs)
  */
 int insn_fetch_from_user(struct pt_regs *regs, unsigned char buf[MAX_INSN_SIZE])
 {
-       unsigned long seg_base = 0;
+       unsigned long ip;
        int not_copied;
 
-       /*
-        * If not in user-space long mode, a custom code segment could be in
-        * use. This is true in protected mode (if the process defined a local
-        * descriptor table), or virtual-8086 mode. In most of the cases
-        * seg_base will be zero as in USER_CS.
-        */
-       if (!user_64bit_mode(regs)) {
-               seg_base = insn_get_seg_base(regs, INAT_SEG_REG_CS);
-               if (seg_base == -1L)
-                       return 0;
-       }
+       ip = insn_get_effective_ip(regs);
+       if (!ip)
+               return 0;
+
+       not_copied = copy_from_user(buf, (void __user *)ip, MAX_INSN_SIZE);
 
+       return MAX_INSN_SIZE - not_copied;
+}
+
+/**
+ * insn_fetch_from_user_inatomic() - Copy instruction bytes from user-space memory
+ *                                   while in atomic code
+ * @regs:      Structure with register values as seen when entering kernel mode
+ * @buf:       Array to store the fetched instruction
+ *
+ * Gets the linear address of the instruction and copies the instruction bytes
+ * to the buf. This function must be used in atomic context.
+ *
+ * Returns:
+ *
+ * Number of instruction bytes copied.
+ *
+ * 0 if nothing was copied.
+ */
+int insn_fetch_from_user_inatomic(struct pt_regs *regs, unsigned char buf[MAX_INSN_SIZE])
+{
+       unsigned long ip;
+       int not_copied;
+
+       ip = insn_get_effective_ip(regs);
+       if (!ip)
+               return 0;
 
-       not_copied = copy_from_user(buf, (void __user *)(seg_base + regs->ip),
-                                   MAX_INSN_SIZE);
+       not_copied = __copy_from_user_inatomic(buf, (void __user *)ip, MAX_INSN_SIZE);
 
        return MAX_INSN_SIZE - not_copied;
 }
index 79e7a0e..6926d0c 100644 (file)
@@ -1349,6 +1349,7 @@ st:                       if (is_imm8(insn->off))
                            insn->imm == (BPF_XOR | BPF_FETCH)) {
                                u8 *branch_target;
                                bool is64 = BPF_SIZE(insn->code) == BPF_DW;
+                               u32 real_src_reg = src_reg;
 
                                /*
                                 * Can't be implemented with a single x86 insn.
@@ -1357,6 +1358,9 @@ st:                       if (is_imm8(insn->off))
 
                                /* Will need RAX as a CMPXCHG operand so save R0 */
                                emit_mov_reg(&prog, true, BPF_REG_AX, BPF_REG_0);
+                               if (src_reg == BPF_REG_0)
+                                       real_src_reg = BPF_REG_AX;
+
                                branch_target = prog;
                                /* Load old value */
                                emit_ldx(&prog, BPF_SIZE(insn->code),
@@ -1366,9 +1370,9 @@ st:                       if (is_imm8(insn->off))
                                 * put the result in the AUX_REG.
                                 */
                                emit_mov_reg(&prog, is64, AUX_REG, BPF_REG_0);
-                               maybe_emit_mod(&prog, AUX_REG, src_reg, is64);
+                               maybe_emit_mod(&prog, AUX_REG, real_src_reg, is64);
                                EMIT2(simple_alu_opcodes[BPF_OP(insn->imm)],
-                                     add_2reg(0xC0, AUX_REG, src_reg));
+                                     add_2reg(0xC0, AUX_REG, real_src_reg));
                                /* Attempt to swap in new value */
                                err = emit_atomic(&prog, BPF_CMPXCHG,
                                                  dst_reg, AUX_REG, insn->off,
@@ -1381,7 +1385,7 @@ st:                       if (is_imm8(insn->off))
                                 */
                                EMIT2(X86_JNE, -(prog - branch_target) - 2);
                                /* Return the pre-modification value */
-                               emit_mov_reg(&prog, is64, src_reg, BPF_REG_0);
+                               emit_mov_reg(&prog, is64, real_src_reg, BPF_REG_0);
                                /* Restore R0 after clobbering RAX */
                                emit_mov_reg(&prog, true, BPF_REG_0, BPF_REG_AX);
                                break;
index 1ac8578..b42bfda 100644 (file)
@@ -27,7 +27,6 @@
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Sébastien Hinderer <Sebastien.Hinderer@ens-lyon.org>");
 MODULE_DESCRIPTION("A power_off handler for Iris devices from EuroBraille");
-MODULE_SUPPORTED_DEVICE("Eurobraille/Iris");
 
 static bool force;
 
index a3cc330..17d80f7 100644 (file)
@@ -741,7 +741,7 @@ int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops,
                map_ops[i].status = GNTST_general_error;
                unmap[0].host_addr = map_ops[i].host_addr,
                unmap[0].handle = map_ops[i].handle;
-               map_ops[i].handle = ~0;
+               map_ops[i].handle = INVALID_GRANT_HANDLE;
                if (map_ops[i].flags & GNTMAP_device_map)
                        unmap[0].dev_bus_addr = map_ops[i].dev_bus_addr;
                else
@@ -751,7 +751,7 @@ int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops,
                        kmap_ops[i].status = GNTST_general_error;
                        unmap[1].host_addr = kmap_ops[i].host_addr,
                        unmap[1].handle = kmap_ops[i].handle;
-                       kmap_ops[i].handle = ~0;
+                       kmap_ops[i].handle = INVALID_GRANT_HANDLE;
                        if (kmap_ops[i].flags & GNTMAP_device_map)
                                unmap[1].dev_bus_addr = kmap_ops[i].dev_bus_addr;
                        else
@@ -776,7 +776,6 @@ int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops,
 out:
        return ret;
 }
-EXPORT_SYMBOL_GPL(set_foreign_p2m_mapping);
 
 int clear_foreign_p2m_mapping(struct gnttab_unmap_grant_ref *unmap_ops,
                              struct gnttab_unmap_grant_ref *kunmap_ops,
@@ -802,7 +801,6 @@ int clear_foreign_p2m_mapping(struct gnttab_unmap_grant_ref *unmap_ops,
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(clear_foreign_p2m_mapping);
 
 #ifdef CONFIG_XEN_DEBUG_FS
 #include <linux/debugfs.h>
index a1c4d29..26b7f72 100644 (file)
@@ -33,7 +33,7 @@ static struct biovec_slab {
        { .nr_vecs = 16, .name = "biovec-16" },
        { .nr_vecs = 64, .name = "biovec-64" },
        { .nr_vecs = 128, .name = "biovec-128" },
-       { .nr_vecs = BIO_MAX_PAGES, .name = "biovec-max" },
+       { .nr_vecs = BIO_MAX_VECS, .name = "biovec-max" },
 };
 
 static struct biovec_slab *biovec_slab(unsigned short nr_vecs)
@@ -46,7 +46,7 @@ static struct biovec_slab *biovec_slab(unsigned short nr_vecs)
                return &bvec_slabs[1];
        case 65 ... 128:
                return &bvec_slabs[2];
-       case 129 ... BIO_MAX_PAGES:
+       case 129 ... BIO_MAX_VECS:
                return &bvec_slabs[3];
        default:
                BUG();
@@ -151,9 +151,9 @@ out:
 
 void bvec_free(mempool_t *pool, struct bio_vec *bv, unsigned short nr_vecs)
 {
-       BIO_BUG_ON(nr_vecs > BIO_MAX_PAGES);
+       BIO_BUG_ON(nr_vecs > BIO_MAX_VECS);
 
-       if (nr_vecs == BIO_MAX_PAGES)
+       if (nr_vecs == BIO_MAX_VECS)
                mempool_free(bv, pool);
        else if (nr_vecs > BIO_INLINE_VECS)
                kmem_cache_free(biovec_slab(nr_vecs)->slab, bv);
@@ -186,15 +186,15 @@ struct bio_vec *bvec_alloc(mempool_t *pool, unsigned short *nr_vecs,
        /*
         * Try a slab allocation first for all smaller allocations.  If that
         * fails and __GFP_DIRECT_RECLAIM is set retry with the mempool.
-        * The mempool is sized to handle up to BIO_MAX_PAGES entries.
+        * The mempool is sized to handle up to BIO_MAX_VECS entries.
         */
-       if (*nr_vecs < BIO_MAX_PAGES) {
+       if (*nr_vecs < BIO_MAX_VECS) {
                struct bio_vec *bvl;
 
                bvl = kmem_cache_alloc(bvs->slab, bvec_alloc_gfp(gfp_mask));
                if (likely(bvl) || !(gfp_mask & __GFP_DIRECT_RECLAIM))
                        return bvl;
-               *nr_vecs = BIO_MAX_PAGES;
+               *nr_vecs = BIO_MAX_VECS;
        }
 
        return mempool_alloc(pool, gfp_mask);
index 85d5790..3304e84 100644 (file)
@@ -109,6 +109,7 @@ void blkg_rwstat_recursive_sum(struct blkcg_gq *blkg, struct blkcg_policy *pol,
 
        lockdep_assert_held(&blkg->q->queue_lock);
 
+       memset(sum, 0, sizeof(*sum));
        rcu_read_lock();
        blkg_for_each_descendant_pre(pos_blkg, pos_css, blkg) {
                struct blkg_rwstat *rwstat;
@@ -122,7 +123,7 @@ void blkg_rwstat_recursive_sum(struct blkcg_gq *blkg, struct blkcg_policy *pol,
                        rwstat = (void *)pos_blkg + off;
 
                for (i = 0; i < BLKG_RWSTAT_NR; i++)
-                       sum->cnt[i] = blkg_rwstat_read_counter(rwstat, i);
+                       sum->cnt[i] += blkg_rwstat_read_counter(rwstat, i);
        }
        rcu_read_unlock();
 }
index c176b7a..c322176 100644 (file)
@@ -219,7 +219,7 @@ static bool blk_crypto_split_bio_if_needed(struct bio **bio_ptr)
 
        bio_for_each_segment(bv, bio, iter) {
                num_sectors += bv.bv_len >> SECTOR_SHIFT;
-               if (++i == BIO_MAX_PAGES)
+               if (++i == BIO_MAX_VECS)
                        break;
        }
        if (num_sectors < bio_sectors(bio)) {
index 752f9c7..7b25613 100644 (file)
@@ -296,7 +296,7 @@ static unsigned int __blkdev_sectors_to_bio_pages(sector_t nr_sects)
 {
        sector_t pages = DIV_ROUND_UP_SECTOR_T(nr_sects, PAGE_SIZE / 512);
 
-       return min(pages, (sector_t)BIO_MAX_PAGES);
+       return min(pages, (sector_t)BIO_MAX_VECS);
 }
 
 static int __blkdev_issue_zero_pages(struct block_device *bdev,
index 369e204..1ffef78 100644 (file)
@@ -249,7 +249,7 @@ static int bio_map_user_iov(struct request *rq, struct iov_iter *iter,
        if (!iov_iter_count(iter))
                return -EINVAL;
 
-       bio = bio_kmalloc(gfp_mask, iov_iter_npages(iter, BIO_MAX_PAGES));
+       bio = bio_kmalloc(gfp_mask, iov_iter_npages(iter, BIO_MAX_VECS));
        if (!bio)
                return -ENOMEM;
        bio->bi_opf |= req_op(rq);
index 833978c..c0276b4 100644 (file)
@@ -240,7 +240,7 @@ int blkdev_zone_mgmt(struct block_device *bdev, enum req_opf op,
                 */
                if (op == REQ_OP_ZONE_RESET &&
                    blkdev_allow_reset_all_zones(bdev, sector, nr_sectors)) {
-                       bio->bi_opf = REQ_OP_ZONE_RESET_ALL;
+                       bio->bi_opf = REQ_OP_ZONE_RESET_ALL | REQ_SYNC;
                        break;
                }
 
@@ -318,6 +318,22 @@ int blkdev_report_zones_ioctl(struct block_device *bdev, fmode_t mode,
        return 0;
 }
 
+static int blkdev_truncate_zone_range(struct block_device *bdev, fmode_t mode,
+                                     const struct blk_zone_range *zrange)
+{
+       loff_t start, end;
+
+       if (zrange->sector + zrange->nr_sectors <= zrange->sector ||
+           zrange->sector + zrange->nr_sectors > get_capacity(bdev->bd_disk))
+               /* Out of range */
+               return -EINVAL;
+
+       start = zrange->sector << SECTOR_SHIFT;
+       end = ((zrange->sector + zrange->nr_sectors) << SECTOR_SHIFT) - 1;
+
+       return truncate_bdev_range(bdev, mode, start, end);
+}
+
 /*
  * BLKRESETZONE, BLKOPENZONE, BLKCLOSEZONE and BLKFINISHZONE ioctl processing.
  * Called from blkdev_ioctl.
@@ -329,6 +345,7 @@ int blkdev_zone_mgmt_ioctl(struct block_device *bdev, fmode_t mode,
        struct request_queue *q;
        struct blk_zone_range zrange;
        enum req_opf op;
+       int ret;
 
        if (!argp)
                return -EINVAL;
@@ -352,6 +369,11 @@ int blkdev_zone_mgmt_ioctl(struct block_device *bdev, fmode_t mode,
        switch (cmd) {
        case BLKRESETZONE:
                op = REQ_OP_ZONE_RESET;
+
+               /* Invalidate the page cache, including dirty pages. */
+               ret = blkdev_truncate_zone_range(bdev, mode, &zrange);
+               if (ret)
+                       return ret;
                break;
        case BLKOPENZONE:
                op = REQ_OP_ZONE_OPEN;
@@ -366,8 +388,20 @@ int blkdev_zone_mgmt_ioctl(struct block_device *bdev, fmode_t mode,
                return -ENOTTY;
        }
 
-       return blkdev_zone_mgmt(bdev, op, zrange.sector, zrange.nr_sectors,
-                               GFP_KERNEL);
+       ret = blkdev_zone_mgmt(bdev, op, zrange.sector, zrange.nr_sectors,
+                              GFP_KERNEL);
+
+       /*
+        * Invalidate the page cache again for zone reset: writes can only be
+        * direct for zoned devices so concurrent writes would not add any page
+        * to the page cache after/during reset. The page cache may be filled
+        * again due to concurrent reads though and dropping the pages for
+        * these is fine.
+        */
+       if (!ret && cmd == BLKRESETZONE)
+               ret = blkdev_truncate_zone_range(bdev, mode, &zrange);
+
+       return ret;
 }
 
 static inline unsigned long *blk_alloc_zone_bitmap(int node,
index 87983a3..6c441f4 100644 (file)
@@ -229,10 +229,10 @@ static struct bio *bounce_clone_bio(struct bio *bio_src)
         *  - The point of cloning the biovec is to produce a bio with a biovec
         *    the caller can modify: bi_idx and bi_bvec_done should be 0.
         *
-        *  - The original bio could've had more than BIO_MAX_PAGES biovecs; if
+        *  - The original bio could've had more than BIO_MAX_VECS biovecs; if
         *    we tried to clone the whole thing bio_alloc_bioset() would fail.
         *    But the clone should succeed as long as the number of biovecs we
-        *    actually need to allocate is fewer than BIO_MAX_PAGES.
+        *    actually need to allocate is fewer than BIO_MAX_VECS.
         *
         *  - Lastly, bi_vcnt should not be looked at or relied upon by code
         *    that does not own the bio - reason being drivers don't use it for
@@ -299,7 +299,7 @@ static void __blk_queue_bounce(struct request_queue *q, struct bio **bio_orig,
        int sectors = 0;
 
        bio_for_each_segment(from, *bio_orig, iter) {
-               if (i++ < BIO_MAX_PAGES)
+               if (i++ < BIO_MAX_VECS)
                        sectors += from.bv_len >> 9;
                if (page_to_pfn(from.bv_page) > q->limits.bounce_pfn)
                        bounce = true;
index c55e8f0..8c8f543 100644 (file)
@@ -534,10 +534,8 @@ static void register_disk(struct device *parent, struct gendisk *disk,
                kobject_create_and_add("holders", &ddev->kobj);
        disk->slave_dir = kobject_create_and_add("slaves", &ddev->kobj);
 
-       if (disk->flags & GENHD_FL_HIDDEN) {
-               dev_set_uevent_suppress(ddev, 0);
+       if (disk->flags & GENHD_FL_HIDDEN)
                return;
-       }
 
        disk_scan_partitions(disk);
 
index 15c9c28..5809cc1 100644 (file)
@@ -767,7 +767,7 @@ config CRYPTO_POLY1305_X86_64
 
 config CRYPTO_POLY1305_MIPS
        tristate "Poly1305 authenticator algorithm (MIPS optimized)"
-       depends on CPU_MIPS32 || (CPU_MIPS64 && 64BIT)
+       depends on MIPS
        select CRYPTO_ARCH_HAVE_LIB_POLY1305
 
 config CRYPTO_MD4
index 316a994..b574cce 100644 (file)
@@ -2260,7 +2260,8 @@ out:
        return rc;
 
 err_eni_release:
-       eni_do_release(dev);
+       dev->phy = NULL;
+       iounmap(ENI_DEV(dev)->ioaddr);
 err_unregister:
        atm_dev_deregister(dev);
 err_free_consistent:
index 9a70bee..495fd0a 100644 (file)
@@ -100,8 +100,6 @@ static LIST_HEAD(fore200e_boards);
 
 MODULE_AUTHOR("Christophe Lizzi - credits to Uwe Dannowski and Heikki Vatiainen");
 MODULE_DESCRIPTION("FORE Systems 200E-series ATM driver - version " FORE200E_VERSION);
-MODULE_SUPPORTED_DEVICE("PCA-200E, SBA-200E");
-
 
 static const int fore200e_rx_buf_nbr[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ] = {
     { BUFFER_S1_NBR, BUFFER_L1_NBR },
index 3c081b6..bfca7b8 100644 (file)
@@ -262,7 +262,7 @@ static int idt77105_start(struct atm_dev *dev)
 {
        unsigned long flags;
 
-       if (!(dev->dev_data = kmalloc(sizeof(struct idt77105_priv),GFP_KERNEL)))
+       if (!(dev->phy_data = kmalloc(sizeof(struct idt77105_priv),GFP_KERNEL)))
                return -ENOMEM;
        PRIV(dev)->dev = dev;
        spin_lock_irqsave(&idt77105_priv_lock, flags);
@@ -337,7 +337,7 @@ static int idt77105_stop(struct atm_dev *dev)
                 else
                     idt77105_all = walk->next;
                dev->phy = NULL;
-                dev->dev_data = NULL;
+                dev->phy_data = NULL;
                 kfree(walk);
                 break;
             }
index d7277c2..32d7aa1 100644 (file)
@@ -2233,6 +2233,7 @@ static int lanai_dev_open(struct atm_dev *atmdev)
        conf1_write(lanai);
 #endif
        iounmap(lanai->base);
+       lanai->base = NULL;
     error_pci:
        pci_disable_device(lanai->pci);
     error:
@@ -2245,6 +2246,8 @@ static int lanai_dev_open(struct atm_dev *atmdev)
 static void lanai_dev_close(struct atm_dev *atmdev)
 {
        struct lanai_dev *lanai = (struct lanai_dev *) atmdev->dev_data;
+       if (lanai->base==NULL)
+               return;
        printk(KERN_INFO DEV_LABEL "(itf %d): shutting down interface\n",
            lanai->number);
        lanai_timed_poll_stop(lanai);
@@ -2552,7 +2555,7 @@ static int lanai_init_one(struct pci_dev *pci,
        struct atm_dev *atmdev;
        int result;
 
-       lanai = kmalloc(sizeof(*lanai), GFP_KERNEL);
+       lanai = kzalloc(sizeof(*lanai), GFP_KERNEL);
        if (lanai == NULL) {
                printk(KERN_ERR DEV_LABEL
                       ": couldn't allocate dev_data structure!\n");
index 7850758..239852d 100644 (file)
@@ -211,7 +211,7 @@ static void uPD98402_int(struct atm_dev *dev)
 static int uPD98402_start(struct atm_dev *dev)
 {
        DPRINTK("phy_start\n");
-       if (!(dev->dev_data = kmalloc(sizeof(struct uPD98402_priv),GFP_KERNEL)))
+       if (!(dev->phy_data = kmalloc(sizeof(struct uPD98402_priv),GFP_KERNEL)))
                return -ENOMEM;
        spin_lock_init(&PRIV(dev)->lock);
        memset(&PRIV(dev)->sonet_stats,0,sizeof(struct k_sonet_stats));
index 18b8242..a46a7e3 100644 (file)
@@ -325,22 +325,22 @@ static void rpm_put_suppliers(struct device *dev)
 static int __rpm_callback(int (*cb)(struct device *), struct device *dev)
        __releases(&dev->power.lock) __acquires(&dev->power.lock)
 {
-       bool use_links = dev->power.links_count > 0;
-       bool get = false;
        int retval, idx;
-       bool put;
+       bool use_links = dev->power.links_count > 0;
 
        if (dev->power.irq_safe) {
                spin_unlock(&dev->power.lock);
-       } else if (!use_links) {
-               spin_unlock_irq(&dev->power.lock);
        } else {
-               get = dev->power.runtime_status == RPM_RESUMING;
-
                spin_unlock_irq(&dev->power.lock);
 
-               /* Resume suppliers if necessary. */
-               if (get) {
+               /*
+                * Resume suppliers if necessary.
+                *
+                * The device's runtime PM status cannot change until this
+                * routine returns, so it is safe to read the status outside of
+                * the lock.
+                */
+               if (use_links && dev->power.runtime_status == RPM_RESUMING) {
                        idx = device_links_read_lock();
 
                        retval = rpm_get_suppliers(dev);
@@ -355,36 +355,24 @@ static int __rpm_callback(int (*cb)(struct device *), struct device *dev)
 
        if (dev->power.irq_safe) {
                spin_lock(&dev->power.lock);
-               return retval;
-       }
-
-       spin_lock_irq(&dev->power.lock);
-
-       if (!use_links)
-               return retval;
-
-       /*
-        * If the device is suspending and the callback has returned success,
-        * drop the usage counters of the suppliers that have been reference
-        * counted on its resume.
-        *
-        * Do that if the resume fails too.
-        */
-       put = dev->power.runtime_status == RPM_SUSPENDING && !retval;
-       if (put)
-               __update_runtime_status(dev, RPM_SUSPENDED);
-       else
-               put = get && retval;
-
-       if (put) {
-               spin_unlock_irq(&dev->power.lock);
-
-               idx = device_links_read_lock();
+       } else {
+               /*
+                * If the device is suspending and the callback has returned
+                * success, drop the usage counters of the suppliers that have
+                * been reference counted on its resume.
+                *
+                * Do that if resume fails too.
+                */
+               if (use_links
+                   && ((dev->power.runtime_status == RPM_SUSPENDING && !retval)
+                   || (dev->power.runtime_status == RPM_RESUMING && retval))) {
+                       idx = device_links_read_lock();
 
-fail:
-               rpm_put_suppliers(dev);
+ fail:
+                       rpm_put_suppliers(dev);
 
-               device_links_read_unlock(idx);
+                       device_links_read_unlock(idx);
+               }
 
                spin_lock_irq(&dev->power.lock);
        }
index 37179a8..fa3719e 100644 (file)
@@ -938,6 +938,9 @@ int software_node_register(const struct software_node *node)
        if (software_node_to_swnode(node))
                return -EEXIST;
 
+       if (node->parent && !parent)
+               return -EINVAL;
+
        return PTR_ERR_OR_ZERO(swnode_register(node, parent, 0));
 }
 EXPORT_SYMBOL_GPL(software_node_register);
@@ -1002,25 +1005,33 @@ EXPORT_SYMBOL_GPL(fwnode_remove_software_node);
 /**
  * device_add_software_node - Assign software node to a device
  * @dev: The device the software node is meant for.
- * @swnode: The software node.
+ * @node: The software node.
  *
- * This function will register @swnode and make it the secondary firmware node
- * pointer of @dev. If @dev has no primary node, then @swnode will become the primary
- * node.
+ * This function will make @node the secondary firmware node pointer of @dev. If
+ * @dev has no primary node, then @node will become the primary node. The
+ * function will register @node automatically if it wasn't already registered.
  */
-int device_add_software_node(struct device *dev, const struct software_node *swnode)
+int device_add_software_node(struct device *dev, const struct software_node *node)
 {
+       struct swnode *swnode;
        int ret;
 
        /* Only one software node per device. */
        if (dev_to_swnode(dev))
                return -EBUSY;
 
-       ret = software_node_register(swnode);
-       if (ret)
-               return ret;
+       swnode = software_node_to_swnode(node);
+       if (swnode) {
+               kobject_get(&swnode->kobj);
+       } else {
+               ret = software_node_register(node);
+               if (ret)
+                       return ret;
+
+               swnode = software_node_to_swnode(node);
+       }
 
-       set_secondary_fwnode(dev, software_node_fwnode(swnode));
+       set_secondary_fwnode(dev, &swnode->fwnode);
 
        return 0;
 }
index 7d9cc43..5d91813 100644 (file)
@@ -1324,7 +1324,7 @@ struct bm_extent {
  * A followup commit may allow even bigger BIO sizes,
  * once we thought that through. */
 #define DRBD_MAX_BIO_SIZE (1U << 20)
-#if DRBD_MAX_BIO_SIZE > (BIO_MAX_PAGES << PAGE_SHIFT)
+#if DRBD_MAX_BIO_SIZE > (BIO_MAX_VECS << PAGE_SHIFT)
 #error Architecture not supported: DRBD_MAX_BIO_SIZE > BIO_MAX_SIZE
 #endif
 #define DRBD_MAX_BIO_SIZE_SAFE (1U << 12)       /* Works always = 4k */
index 0b71292..4aa9683 100644 (file)
@@ -5091,7 +5091,6 @@ module_param(floppy, charp, 0);
 module_param(FLOPPY_IRQ, int, 0);
 module_param(FLOPPY_DMA, int, 0);
 MODULE_AUTHOR("Alain L. Knaff");
-MODULE_SUPPORTED_DEVICE("fd");
 MODULE_LICENSE("GPL");
 
 /* This doesn't actually get used other than for module information */
index 5ac1881..227e1be 100644 (file)
@@ -871,6 +871,7 @@ static int rsxx_pci_probe(struct pci_dev *dev,
        card->event_wq = create_singlethread_workqueue(DRIVER_NAME"_event");
        if (!card->event_wq) {
                dev_err(CARD_TO_DEV(card), "Failed card event setup.\n");
+               st = -ENOMEM;
                goto failed_event_handler;
        }
 
index 982732d..664280f 100644 (file)
@@ -877,6 +877,7 @@ static int mm_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
        if (card->mm_pages[0].desc == NULL ||
            card->mm_pages[1].desc == NULL) {
                dev_printk(KERN_ERR, &card->dev->dev, "alloc failed\n");
+               ret = -ENOMEM;
                goto failed_alloc;
        }
        reset_page(&card->mm_pages[0]);
@@ -888,8 +889,10 @@ static int mm_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
        spin_lock_init(&card->lock);
 
        card->queue = blk_alloc_queue(NUMA_NO_NODE);
-       if (!card->queue)
+       if (!card->queue) {
+               ret = -ENOMEM;
                goto failed_alloc;
+       }
 
        tasklet_init(&card->tasklet, process_page, (unsigned long)card);
 
index a711a2e..cf8deec 100644 (file)
@@ -627,7 +627,7 @@ static ssize_t writeback_store(struct device *dev,
        struct bio_vec bio_vec;
        struct page *page;
        ssize_t ret = len;
-       int mode;
+       int mode, err;
        unsigned long blk_idx = 0;
 
        if (sysfs_streq(buf, "idle"))
@@ -638,8 +638,8 @@ static ssize_t writeback_store(struct device *dev,
                if (strncmp(buf, PAGE_WB_SIG, sizeof(PAGE_WB_SIG) - 1))
                        return -EINVAL;
 
-               ret = kstrtol(buf + sizeof(PAGE_WB_SIG) - 1, 10, &index);
-               if (ret || index >= nr_pages)
+               if (kstrtol(buf + sizeof(PAGE_WB_SIG) - 1, 10, &index) ||
+                               index >= nr_pages)
                        return -EINVAL;
 
                nr_pages = 1;
@@ -663,7 +663,7 @@ static ssize_t writeback_store(struct device *dev,
                goto release_init_lock;
        }
 
-       while (nr_pages--) {
+       for (; nr_pages != 0; index++, nr_pages--) {
                struct bio_vec bvec;
 
                bvec.bv_page = page;
@@ -728,12 +728,17 @@ static ssize_t writeback_store(struct device *dev,
                 * XXX: A single page IO would be inefficient for write
                 * but it would be not bad as starter.
                 */
-               ret = submit_bio_wait(&bio);
-               if (ret) {
+               err = submit_bio_wait(&bio);
+               if (err) {
                        zram_slot_lock(zram, index);
                        zram_clear_flag(zram, index, ZRAM_UNDER_WB);
                        zram_clear_flag(zram, index, ZRAM_IDLE);
                        zram_slot_unlock(zram, index);
+                       /*
+                        * Return last IO error unless every IO were
+                        * not suceeded.
+                        */
+                       ret = err;
                        continue;
                }
 
index 3951f7b..bea1595 100644 (file)
@@ -194,5 +194,4 @@ module_init(rsi_91x_bt_module_init);
 module_exit(rsi_91x_bt_module_exit);
 MODULE_AUTHOR("Redpine Signals Inc");
 MODULE_DESCRIPTION("RSI BT driver");
-MODULE_SUPPORTED_DEVICE("RSI-BT");
 MODULE_LICENSE("Dual BSD/GPL");
index 14b2d80..45ac7ab 100644 (file)
@@ -81,9 +81,6 @@ MODULE_DESCRIPTION("Driver for Applicom Profibus card");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_MISCDEV(AC_MINOR);
 
-MODULE_SUPPORTED_DEVICE("ac");
-
-
 static struct applicom_board {
        unsigned long PhysIO;
        void __iomem *RamIO;
index 8038a8a..f4949b6 100644 (file)
@@ -54,10 +54,9 @@ static int pseries_rng_probe(struct vio_dev *dev,
        return hwrng_register(&pseries_rng);
 }
 
-static int pseries_rng_remove(struct vio_dev *dev)
+static void pseries_rng_remove(struct vio_dev *dev)
 {
        hwrng_unregister(&pseries_rng);
-       return 0;
 }
 
 static const struct vio_device_id pseries_rng_driver_ids[] = {
index aff0a8e..776abbf 100644 (file)
@@ -64,7 +64,6 @@
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Jonathan Buzzard <jonathan@buzzard.org.uk>");
 MODULE_DESCRIPTION("Toshiba laptop SMM driver");
-MODULE_SUPPORTED_DEVICE("toshiba");
 
 static DEFINE_MUTEX(tosh_mutex);
 static int tosh_fn;
index 994385b..9036047 100644 (file)
@@ -343,7 +343,7 @@ static int ibmvtpm_crq_send_init_complete(struct ibmvtpm_dev *ibmvtpm)
  *
  * Return: Always 0.
  */
-static int tpm_ibmvtpm_remove(struct vio_dev *vdev)
+static void tpm_ibmvtpm_remove(struct vio_dev *vdev)
 {
        struct tpm_chip *chip = dev_get_drvdata(&vdev->dev);
        struct ibmvtpm_dev *ibmvtpm = dev_get_drvdata(&chip->dev);
@@ -372,8 +372,6 @@ static int tpm_ibmvtpm_remove(struct vio_dev *vdev)
        kfree(ibmvtpm);
        /* For tpm_ibmvtpm_get_desired_dma */
        dev_set_drvdata(&vdev->dev, NULL);
-
-       return 0;
 }
 
 /**
index 17d90e0..d9e70e5 100644 (file)
@@ -13,6 +13,8 @@
 #include <linux/regmap.h>
 
 /* clk control registers */
+/* BD71815 */
+#define BD71815_REG_OUT32K     0x1d
 /* BD70528 */
 #define BD70528_REG_OUT32K     0x2c
 /* BD71828 */
@@ -118,6 +120,10 @@ static int bd71837_clk_probe(struct platform_device *pdev)
                c->reg = BD70528_REG_OUT32K;
                c->mask = CLK_OUT_EN_MASK;
                break;
+       case ROHM_CHIP_TYPE_BD71815:
+               c->reg = BD71815_REG_OUT32K;
+               c->mask = CLK_OUT_EN_MASK;
+               break;
        default:
                dev_err(&pdev->dev, "Unknown clk chip\n");
                return -EINVAL;
@@ -146,6 +152,7 @@ static const struct platform_device_id bd718x7_clk_id[] = {
        { "bd71847-clk", ROHM_CHIP_TYPE_BD71847 },
        { "bd70528-clk", ROHM_CHIP_TYPE_BD70528 },
        { "bd71828-clk", ROHM_CHIP_TYPE_BD71828 },
+       { "bd71815-clk", ROHM_CHIP_TYPE_BD71815 },
        { },
 };
 MODULE_DEVICE_TABLE(platform, bd718x7_clk_id);
@@ -161,6 +168,6 @@ static struct platform_driver bd71837_clk = {
 module_platform_driver(bd71837_clk);
 
 MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
-MODULE_DESCRIPTION("BD71837/BD71847/BD70528 chip clk driver");
+MODULE_DESCRIPTION("BD718(15/18/28/37/47/50) and BD70528 chip clk driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:bd718xx-clk");
index ef2a974..75bc401 100644 (file)
@@ -31,7 +31,7 @@ struct stm32_timer_cnt {
        struct counter_device counter;
        struct regmap *regmap;
        struct clk *clk;
-       u32 ceiling;
+       u32 max_arr;
        bool enabled;
        struct stm32_timer_regs bak;
 };
@@ -44,13 +44,14 @@ struct stm32_timer_cnt {
  * @STM32_COUNT_ENCODER_MODE_3: counts on both TI1FP1 and TI2FP2 edges
  */
 enum stm32_count_function {
-       STM32_COUNT_SLAVE_MODE_DISABLED = -1,
+       STM32_COUNT_SLAVE_MODE_DISABLED,
        STM32_COUNT_ENCODER_MODE_1,
        STM32_COUNT_ENCODER_MODE_2,
        STM32_COUNT_ENCODER_MODE_3,
 };
 
 static enum counter_count_function stm32_count_functions[] = {
+       [STM32_COUNT_SLAVE_MODE_DISABLED] = COUNTER_COUNT_FUNCTION_INCREASE,
        [STM32_COUNT_ENCODER_MODE_1] = COUNTER_COUNT_FUNCTION_QUADRATURE_X2_A,
        [STM32_COUNT_ENCODER_MODE_2] = COUNTER_COUNT_FUNCTION_QUADRATURE_X2_B,
        [STM32_COUNT_ENCODER_MODE_3] = COUNTER_COUNT_FUNCTION_QUADRATURE_X4,
@@ -73,8 +74,10 @@ static int stm32_count_write(struct counter_device *counter,
                             const unsigned long val)
 {
        struct stm32_timer_cnt *const priv = counter->priv;
+       u32 ceiling;
 
-       if (val > priv->ceiling)
+       regmap_read(priv->regmap, TIM_ARR, &ceiling);
+       if (val > ceiling)
                return -EINVAL;
 
        return regmap_write(priv->regmap, TIM_CNT, val);
@@ -90,6 +93,9 @@ static int stm32_count_function_get(struct counter_device *counter,
        regmap_read(priv->regmap, TIM_SMCR, &smcr);
 
        switch (smcr & TIM_SMCR_SMS) {
+       case 0:
+               *function = STM32_COUNT_SLAVE_MODE_DISABLED;
+               return 0;
        case 1:
                *function = STM32_COUNT_ENCODER_MODE_1;
                return 0;
@@ -99,9 +105,9 @@ static int stm32_count_function_get(struct counter_device *counter,
        case 3:
                *function = STM32_COUNT_ENCODER_MODE_3;
                return 0;
+       default:
+               return -EINVAL;
        }
-
-       return -EINVAL;
 }
 
 static int stm32_count_function_set(struct counter_device *counter,
@@ -112,6 +118,9 @@ static int stm32_count_function_set(struct counter_device *counter,
        u32 cr1, sms;
 
        switch (function) {
+       case STM32_COUNT_SLAVE_MODE_DISABLED:
+               sms = 0;
+               break;
        case STM32_COUNT_ENCODER_MODE_1:
                sms = 1;
                break;
@@ -122,8 +131,7 @@ static int stm32_count_function_set(struct counter_device *counter,
                sms = 3;
                break;
        default:
-               sms = 0;
-               break;
+               return -EINVAL;
        }
 
        /* Store enable status */
@@ -131,10 +139,6 @@ static int stm32_count_function_set(struct counter_device *counter,
 
        regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
 
-       /* TIMx_ARR register shouldn't be buffered (ARPE=0) */
-       regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, 0);
-       regmap_write(priv->regmap, TIM_ARR, priv->ceiling);
-
        regmap_update_bits(priv->regmap, TIM_SMCR, TIM_SMCR_SMS, sms);
 
        /* Make sure that registers are updated */
@@ -185,11 +189,13 @@ static ssize_t stm32_count_ceiling_write(struct counter_device *counter,
        if (ret)
                return ret;
 
+       if (ceiling > priv->max_arr)
+               return -ERANGE;
+
        /* TIMx_ARR register shouldn't be buffered (ARPE=0) */
        regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, 0);
        regmap_write(priv->regmap, TIM_ARR, ceiling);
 
-       priv->ceiling = ceiling;
        return len;
 }
 
@@ -274,31 +280,36 @@ static int stm32_action_get(struct counter_device *counter,
        size_t function;
        int err;
 
-       /* Default action mode (e.g. STM32_COUNT_SLAVE_MODE_DISABLED) */
-       *action = STM32_SYNAPSE_ACTION_NONE;
-
        err = stm32_count_function_get(counter, count, &function);
        if (err)
-               return 0;
+               return err;
 
        switch (function) {
+       case STM32_COUNT_SLAVE_MODE_DISABLED:
+               /* counts on internal clock when CEN=1 */
+               *action = STM32_SYNAPSE_ACTION_NONE;
+               return 0;
        case STM32_COUNT_ENCODER_MODE_1:
                /* counts up/down on TI1FP1 edge depending on TI2FP2 level */
                if (synapse->signal->id == count->synapses[0].signal->id)
                        *action = STM32_SYNAPSE_ACTION_BOTH_EDGES;
-               break;
+               else
+                       *action = STM32_SYNAPSE_ACTION_NONE;
+               return 0;
        case STM32_COUNT_ENCODER_MODE_2:
                /* counts up/down on TI2FP2 edge depending on TI1FP1 level */
                if (synapse->signal->id == count->synapses[1].signal->id)
                        *action = STM32_SYNAPSE_ACTION_BOTH_EDGES;
-               break;
+               else
+                       *action = STM32_SYNAPSE_ACTION_NONE;
+               return 0;
        case STM32_COUNT_ENCODER_MODE_3:
                /* counts up/down on both TI1FP1 and TI2FP2 edges */
                *action = STM32_SYNAPSE_ACTION_BOTH_EDGES;
-               break;
+               return 0;
+       default:
+               return -EINVAL;
        }
-
-       return 0;
 }
 
 static const struct counter_ops stm32_timer_cnt_ops = {
@@ -359,7 +370,7 @@ static int stm32_timer_cnt_probe(struct platform_device *pdev)
 
        priv->regmap = ddata->regmap;
        priv->clk = ddata->clk;
-       priv->ceiling = ddata->max_arr;
+       priv->max_arr = ddata->max_arr;
 
        priv->counter.name = dev_name(dev);
        priv->counter.parent = dev;
index 3ba2f71..5e07065 100644 (file)
@@ -103,6 +103,8 @@ static const struct of_device_id whitelist[] __initconst = {
 static const struct of_device_id blacklist[] __initconst = {
        { .compatible = "allwinner,sun50i-h6", },
 
+       { .compatible = "arm,vexpress", },
+
        { .compatible = "calxeda,highbank", },
        { .compatible = "calxeda,ecx-2000", },
 
index d3c2344..f86859b 100644 (file)
@@ -317,9 +317,9 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
        }
 
        base = ioremap(res->start, resource_size(res));
-       if (IS_ERR(base)) {
+       if (!base) {
                dev_err(dev, "failed to map resource %pR\n", res);
-               ret = PTR_ERR(base);
+               ret = -ENOMEM;
                goto release_region;
        }
 
@@ -374,7 +374,7 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
 error:
        kfree(data);
 unmap_base:
-       iounmap(data->base);
+       iounmap(base);
 release_region:
        release_mem_region(res->start, resource_size(res));
        return ret;
index 2de5e36..cc8dd30 100644 (file)
@@ -1042,7 +1042,7 @@ error:
        return ret;
 }
 
-static int nx842_remove(struct vio_dev *viodev)
+static void nx842_remove(struct vio_dev *viodev)
 {
        struct nx842_devdata *old_devdata;
        unsigned long flags;
@@ -1063,8 +1063,6 @@ static int nx842_remove(struct vio_dev *viodev)
        if (old_devdata)
                kfree(old_devdata->counters);
        kfree(old_devdata);
-
-       return 0;
 }
 
 static const struct vio_device_id nx842_vio_driver_ids[] = {
index 0d2dc5b..1d0e8a1 100644 (file)
@@ -783,7 +783,7 @@ static int nx_probe(struct vio_dev *viodev, const struct vio_device_id *id)
        return nx_register_algs();
 }
 
-static int nx_remove(struct vio_dev *viodev)
+static void nx_remove(struct vio_dev *viodev)
 {
        dev_dbg(&viodev->dev, "entering nx_remove for UA 0x%x\n",
                viodev->unit_address);
@@ -811,8 +811,6 @@ static int nx_remove(struct vio_dev *viodev)
                nx_unregister_skcipher(&nx_ecb_aes_alg, NX_FC_AES,
                                       NX_MODE_AES_ECB);
        }
-
-       return 0;
 }
 
 
index af58ebc..e3db936 100644 (file)
@@ -21,14 +21,6 @@ config EXTCON_ADC_JACK
        help
          Say Y here to enable extcon device driver based on ADC values.
 
-config EXTCON_ARIZONA
-       tristate "Wolfson Arizona EXTCON support"
-       depends on MFD_ARIZONA && INPUT && SND_SOC
-       help
-         Say Y here to enable support for external accessory detection
-         with Wolfson Arizona devices. These are audio CODECs with
-         advanced audio accessory detection support.
-
 config EXTCON_AXP288
        tristate "X-Power AXP288 EXTCON support"
        depends on MFD_AXP20X && USB_SUPPORT && X86 && ACPI
index fe10a1b..1b390d9 100644 (file)
@@ -6,7 +6,6 @@
 obj-$(CONFIG_EXTCON)           += extcon-core.o
 extcon-core-objs               += extcon.o devres.o
 obj-$(CONFIG_EXTCON_ADC_JACK)  += extcon-adc-jack.o
-obj-$(CONFIG_EXTCON_ARIZONA)   += extcon-arizona.o
 obj-$(CONFIG_EXTCON_AXP288)    += extcon-axp288.o
 obj-$(CONFIG_EXTCON_FSA9480)   += extcon-fsa9480.o
 obj-$(CONFIG_EXTCON_GPIO)      += extcon-gpio.o
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
deleted file mode 100644 (file)
index aae82db..0000000
+++ /dev/null
@@ -1,1816 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * extcon-arizona.c - Extcon driver Wolfson Arizona devices
- *
- *  Copyright (C) 2012-2014 Wolfson Microelectronics plc
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/err.h>
-#include <linux/gpio/consumer.h>
-#include <linux/gpio.h>
-#include <linux/input.h>
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
-#include <linux/property.h>
-#include <linux/regulator/consumer.h>
-#include <linux/extcon-provider.h>
-
-#include <sound/soc.h>
-
-#include <linux/mfd/arizona/core.h>
-#include <linux/mfd/arizona/pdata.h>
-#include <linux/mfd/arizona/registers.h>
-#include <dt-bindings/mfd/arizona.h>
-
-#define ARIZONA_MAX_MICD_RANGE 8
-
-#define ARIZONA_MICD_CLAMP_MODE_JDL      0x4
-#define ARIZONA_MICD_CLAMP_MODE_JDH      0x5
-#define ARIZONA_MICD_CLAMP_MODE_JDL_GP5H 0x9
-#define ARIZONA_MICD_CLAMP_MODE_JDH_GP5H 0xb
-
-#define ARIZONA_TST_CAP_DEFAULT 0x3
-#define ARIZONA_TST_CAP_CLAMP   0x1
-
-#define ARIZONA_HPDET_MAX 10000
-
-#define HPDET_DEBOUNCE 500
-#define DEFAULT_MICD_TIMEOUT 2000
-
-#define ARIZONA_HPDET_WAIT_COUNT 15
-#define ARIZONA_HPDET_WAIT_DELAY_MS 20
-
-#define QUICK_HEADPHONE_MAX_OHM 3
-#define MICROPHONE_MIN_OHM      1257
-#define MICROPHONE_MAX_OHM      30000
-
-#define MICD_DBTIME_TWO_READINGS 2
-#define MICD_DBTIME_FOUR_READINGS 4
-
-#define MICD_LVL_1_TO_7 (ARIZONA_MICD_LVL_1 | ARIZONA_MICD_LVL_2 | \
-                        ARIZONA_MICD_LVL_3 | ARIZONA_MICD_LVL_4 | \
-                        ARIZONA_MICD_LVL_5 | ARIZONA_MICD_LVL_6 | \
-                        ARIZONA_MICD_LVL_7)
-
-#define MICD_LVL_0_TO_7 (ARIZONA_MICD_LVL_0 | MICD_LVL_1_TO_7)
-
-#define MICD_LVL_0_TO_8 (MICD_LVL_0_TO_7 | ARIZONA_MICD_LVL_8)
-
-struct arizona_extcon_info {
-       struct device *dev;
-       struct arizona *arizona;
-       struct mutex lock;
-       struct regulator *micvdd;
-       struct input_dev *input;
-
-       u16 last_jackdet;
-
-       int micd_mode;
-       const struct arizona_micd_config *micd_modes;
-       int micd_num_modes;
-
-       const struct arizona_micd_range *micd_ranges;
-       int num_micd_ranges;
-
-       bool micd_reva;
-       bool micd_clamp;
-
-       struct delayed_work hpdet_work;
-       struct delayed_work micd_detect_work;
-       struct delayed_work micd_timeout_work;
-
-       bool hpdet_active;
-       bool hpdet_done;
-       bool hpdet_retried;
-
-       int num_hpdet_res;
-       unsigned int hpdet_res[3];
-
-       bool mic;
-       bool detecting;
-       int jack_flips;
-
-       int hpdet_ip_version;
-
-       struct extcon_dev *edev;
-
-       struct gpio_desc *micd_pol_gpio;
-};
-
-static const struct arizona_micd_config micd_default_modes[] = {
-       { ARIZONA_ACCDET_SRC, 1, 0 },
-       { 0,                  2, 1 },
-};
-
-static const struct arizona_micd_range micd_default_ranges[] = {
-       { .max =  11, .key = BTN_0 },
-       { .max =  28, .key = BTN_1 },
-       { .max =  54, .key = BTN_2 },
-       { .max = 100, .key = BTN_3 },
-       { .max = 186, .key = BTN_4 },
-       { .max = 430, .key = BTN_5 },
-};
-
-/* The number of levels in arizona_micd_levels valid for button thresholds */
-#define ARIZONA_NUM_MICD_BUTTON_LEVELS 64
-
-static const int arizona_micd_levels[] = {
-       3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 34, 36, 39, 41, 44, 46,
-       49, 52, 54, 57, 60, 62, 65, 67, 70, 73, 75, 78, 81, 83, 89, 94, 100,
-       105, 111, 116, 122, 127, 139, 150, 161, 173, 186, 196, 209, 220, 245,
-       270, 295, 321, 348, 375, 402, 430, 489, 550, 614, 681, 752, 903, 1071,
-       1257, 30000,
-};
-
-static const unsigned int arizona_cable[] = {
-       EXTCON_MECHANICAL,
-       EXTCON_JACK_MICROPHONE,
-       EXTCON_JACK_HEADPHONE,
-       EXTCON_JACK_LINE_OUT,
-       EXTCON_NONE,
-};
-
-static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info);
-
-static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info,
-                                   bool clamp)
-{
-       struct arizona *arizona = info->arizona;
-       unsigned int mask = 0, val = 0;
-       unsigned int cap_sel = 0;
-       int ret;
-
-       switch (arizona->type) {
-       case WM8998:
-       case WM1814:
-               mask = 0;
-               break;
-       case WM5110:
-       case WM8280:
-               mask = ARIZONA_HP1L_SHRTO | ARIZONA_HP1L_FLWR |
-                      ARIZONA_HP1L_SHRTI;
-               if (clamp) {
-                       val = ARIZONA_HP1L_SHRTO;
-                       cap_sel = ARIZONA_TST_CAP_CLAMP;
-               } else {
-                       val = ARIZONA_HP1L_FLWR | ARIZONA_HP1L_SHRTI;
-                       cap_sel = ARIZONA_TST_CAP_DEFAULT;
-               }
-
-               ret = regmap_update_bits(arizona->regmap,
-                                        ARIZONA_HP_TEST_CTRL_1,
-                                        ARIZONA_HP1_TST_CAP_SEL_MASK,
-                                        cap_sel);
-               if (ret != 0)
-                       dev_warn(arizona->dev,
-                                "Failed to set TST_CAP_SEL: %d\n", ret);
-               break;
-       default:
-               mask = ARIZONA_RMV_SHRT_HP1L;
-               if (clamp)
-                       val = ARIZONA_RMV_SHRT_HP1L;
-               break;
-       }
-
-       snd_soc_dapm_mutex_lock(arizona->dapm);
-
-       arizona->hpdet_clamp = clamp;
-
-       /* Keep the HP output stages disabled while doing the clamp */
-       if (clamp) {
-               ret = regmap_update_bits(arizona->regmap,
-                                        ARIZONA_OUTPUT_ENABLES_1,
-                                        ARIZONA_OUT1L_ENA |
-                                        ARIZONA_OUT1R_ENA, 0);
-               if (ret != 0)
-                       dev_warn(arizona->dev,
-                               "Failed to disable headphone outputs: %d\n",
-                                ret);
-       }
-
-       if (mask) {
-               ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1L,
-                                        mask, val);
-               if (ret != 0)
-                       dev_warn(arizona->dev, "Failed to do clamp: %d\n",
-                                ret);
-
-               ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1R,
-                                        mask, val);
-               if (ret != 0)
-                       dev_warn(arizona->dev, "Failed to do clamp: %d\n",
-                                ret);
-       }
-
-       /* Restore the desired state while not doing the clamp */
-       if (!clamp) {
-               ret = regmap_update_bits(arizona->regmap,
-                                        ARIZONA_OUTPUT_ENABLES_1,
-                                        ARIZONA_OUT1L_ENA |
-                                        ARIZONA_OUT1R_ENA, arizona->hp_ena);
-               if (ret != 0)
-                       dev_warn(arizona->dev,
-                                "Failed to restore headphone outputs: %d\n",
-                                ret);
-       }
-
-       snd_soc_dapm_mutex_unlock(arizona->dapm);
-}
-
-static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
-{
-       struct arizona *arizona = info->arizona;
-
-       mode %= info->micd_num_modes;
-
-       gpiod_set_value_cansleep(info->micd_pol_gpio,
-                                info->micd_modes[mode].gpio);
-
-       regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
-                          ARIZONA_MICD_BIAS_SRC_MASK,
-                          info->micd_modes[mode].bias <<
-                          ARIZONA_MICD_BIAS_SRC_SHIFT);
-       regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
-                          ARIZONA_ACCDET_SRC, info->micd_modes[mode].src);
-
-       info->micd_mode = mode;
-
-       dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
-}
-
-static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info)
-{
-       switch (info->micd_modes[0].bias) {
-       case 1:
-               return "MICBIAS1";
-       case 2:
-               return "MICBIAS2";
-       case 3:
-               return "MICBIAS3";
-       default:
-               return "MICVDD";
-       }
-}
-
-static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
-{
-       struct arizona *arizona = info->arizona;
-       const char *widget = arizona_extcon_get_micbias(info);
-       struct snd_soc_dapm_context *dapm = arizona->dapm;
-       struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
-       int ret;
-
-       ret = snd_soc_component_force_enable_pin(component, widget);
-       if (ret != 0)
-               dev_warn(arizona->dev, "Failed to enable %s: %d\n",
-                        widget, ret);
-
-       snd_soc_dapm_sync(dapm);
-
-       if (!arizona->pdata.micd_force_micbias) {
-               ret = snd_soc_component_disable_pin(component, widget);
-               if (ret != 0)
-                       dev_warn(arizona->dev, "Failed to disable %s: %d\n",
-                                widget, ret);
-
-               snd_soc_dapm_sync(dapm);
-       }
-}
-
-static void arizona_start_mic(struct arizona_extcon_info *info)
-{
-       struct arizona *arizona = info->arizona;
-       bool change;
-       int ret;
-       unsigned int mode;
-
-       /* Microphone detection can't use idle mode */
-       pm_runtime_get(info->dev);
-
-       if (info->detecting) {
-               ret = regulator_allow_bypass(info->micvdd, false);
-               if (ret != 0) {
-                       dev_err(arizona->dev,
-                               "Failed to regulate MICVDD: %d\n",
-                               ret);
-               }
-       }
-
-       ret = regulator_enable(info->micvdd);
-       if (ret != 0) {
-               dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
-                       ret);
-       }
-
-       if (info->micd_reva) {
-               const struct reg_sequence reva[] = {
-                       { 0x80,  0x3 },
-                       { 0x294, 0x0 },
-                       { 0x80,  0x0 },
-               };
-
-               regmap_multi_reg_write(arizona->regmap, reva, ARRAY_SIZE(reva));
-       }
-
-       if (info->detecting && arizona->pdata.micd_software_compare)
-               mode = ARIZONA_ACCDET_MODE_ADC;
-       else
-               mode = ARIZONA_ACCDET_MODE_MIC;
-
-       regmap_update_bits(arizona->regmap,
-                          ARIZONA_ACCESSORY_DETECT_MODE_1,
-                          ARIZONA_ACCDET_MODE_MASK, mode);
-
-       arizona_extcon_pulse_micbias(info);
-
-       ret = regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
-                                      ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
-                                      &change);
-       if (ret < 0) {
-               dev_err(arizona->dev, "Failed to enable micd: %d\n", ret);
-       } else if (!change) {
-               regulator_disable(info->micvdd);
-               pm_runtime_put_autosuspend(info->dev);
-       }
-}
-
-static void arizona_stop_mic(struct arizona_extcon_info *info)
-{
-       struct arizona *arizona = info->arizona;
-       const char *widget = arizona_extcon_get_micbias(info);
-       struct snd_soc_dapm_context *dapm = arizona->dapm;
-       struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
-       bool change = false;
-       int ret;
-
-       ret = regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
-                                      ARIZONA_MICD_ENA, 0,
-                                      &change);
-       if (ret < 0)
-               dev_err(arizona->dev, "Failed to disable micd: %d\n", ret);
-
-       ret = snd_soc_component_disable_pin(component, widget);
-       if (ret != 0)
-               dev_warn(arizona->dev,
-                        "Failed to disable %s: %d\n",
-                        widget, ret);
-
-       snd_soc_dapm_sync(dapm);
-
-       if (info->micd_reva) {
-               const struct reg_sequence reva[] = {
-                       { 0x80,  0x3 },
-                       { 0x294, 0x2 },
-                       { 0x80,  0x0 },
-               };
-
-               regmap_multi_reg_write(arizona->regmap, reva, ARRAY_SIZE(reva));
-       }
-
-       ret = regulator_allow_bypass(info->micvdd, true);
-       if (ret != 0) {
-               dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
-                       ret);
-       }
-
-       if (change) {
-               regulator_disable(info->micvdd);
-               pm_runtime_mark_last_busy(info->dev);
-               pm_runtime_put_autosuspend(info->dev);
-       }
-}
-
-static struct {
-       unsigned int threshold;
-       unsigned int factor_a;
-       unsigned int factor_b;
-} arizona_hpdet_b_ranges[] = {
-       { 100,  5528,   362464 },
-       { 169, 11084,  6186851 },
-       { 169, 11065, 65460395 },
-};
-
-#define ARIZONA_HPDET_B_RANGE_MAX 0x3fb
-
-static struct {
-       int min;
-       int max;
-} arizona_hpdet_c_ranges[] = {
-       { 0,       30 },
-       { 8,      100 },
-       { 100,   1000 },
-       { 1000, 10000 },
-};
-
-static int arizona_hpdet_read(struct arizona_extcon_info *info)
-{
-       struct arizona *arizona = info->arizona;
-       unsigned int val, range;
-       int ret;
-
-       ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
-       if (ret != 0) {
-               dev_err(arizona->dev, "Failed to read HPDET status: %d\n",
-                       ret);
-               return ret;
-       }
-
-       switch (info->hpdet_ip_version) {
-       case 0:
-               if (!(val & ARIZONA_HP_DONE)) {
-                       dev_err(arizona->dev, "HPDET did not complete: %x\n",
-                               val);
-                       return -EAGAIN;
-               }
-
-               val &= ARIZONA_HP_LVL_MASK;
-               break;
-
-       case 1:
-               if (!(val & ARIZONA_HP_DONE_B)) {
-                       dev_err(arizona->dev, "HPDET did not complete: %x\n",
-                               val);
-                       return -EAGAIN;
-               }
-
-               ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
-               if (ret != 0) {
-                       dev_err(arizona->dev, "Failed to read HP value: %d\n",
-                               ret);
-                       return -EAGAIN;
-               }
-
-               regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
-                           &range);
-               range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
-                          >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
-
-               if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
-                   (val < arizona_hpdet_b_ranges[range].threshold ||
-                    val >= ARIZONA_HPDET_B_RANGE_MAX)) {
-                       range++;
-                       dev_dbg(arizona->dev, "Moving to HPDET range %d\n",
-                               range);
-                       regmap_update_bits(arizona->regmap,
-                                          ARIZONA_HEADPHONE_DETECT_1,
-                                          ARIZONA_HP_IMPEDANCE_RANGE_MASK,
-                                          range <<
-                                          ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
-                       return -EAGAIN;
-               }
-
-               /* If we go out of range report top of range */
-               if (val < arizona_hpdet_b_ranges[range].threshold ||
-                   val >= ARIZONA_HPDET_B_RANGE_MAX) {
-                       dev_dbg(arizona->dev, "Measurement out of range\n");
-                       return ARIZONA_HPDET_MAX;
-               }
-
-               dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
-                       val, range);
-
-               val = arizona_hpdet_b_ranges[range].factor_b
-                       / ((val * 100) -
-                          arizona_hpdet_b_ranges[range].factor_a);
-               break;
-
-       case 2:
-               if (!(val & ARIZONA_HP_DONE_B)) {
-                       dev_err(arizona->dev, "HPDET did not complete: %x\n",
-                               val);
-                       return -EAGAIN;
-               }
-
-               val &= ARIZONA_HP_LVL_B_MASK;
-               /* Convert to ohms, the value is in 0.5 ohm increments */
-               val /= 2;
-
-               regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
-                           &range);
-               range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
-                          >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
-
-               /* Skip up a range, or report? */
-               if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
-                   (val >= arizona_hpdet_c_ranges[range].max)) {
-                       range++;
-                       dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
-                               arizona_hpdet_c_ranges[range].min,
-                               arizona_hpdet_c_ranges[range].max);
-                       regmap_update_bits(arizona->regmap,
-                                          ARIZONA_HEADPHONE_DETECT_1,
-                                          ARIZONA_HP_IMPEDANCE_RANGE_MASK,
-                                          range <<
-                                          ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
-                       return -EAGAIN;
-               }
-
-               if (range && (val < arizona_hpdet_c_ranges[range].min)) {
-                       dev_dbg(arizona->dev, "Reporting range boundary %d\n",
-                               arizona_hpdet_c_ranges[range].min);
-                       val = arizona_hpdet_c_ranges[range].min;
-               }
-               break;
-
-       default:
-               dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
-                        info->hpdet_ip_version);
-               return -EINVAL;
-       }
-
-       dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
-       return val;
-}
-
-static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
-                              bool *mic)
-{
-       struct arizona *arizona = info->arizona;
-       int id_gpio = arizona->pdata.hpdet_id_gpio;
-
-       if (!arizona->pdata.hpdet_acc_id)
-               return 0;
-
-       /*
-        * If we're using HPDET for accessory identification we need
-        * to take multiple measurements, step through them in sequence.
-        */
-       info->hpdet_res[info->num_hpdet_res++] = *reading;
-
-       /* Only check the mic directly if we didn't already ID it */
-       if (id_gpio && info->num_hpdet_res == 1) {
-               dev_dbg(arizona->dev, "Measuring mic\n");
-
-               regmap_update_bits(arizona->regmap,
-                                  ARIZONA_ACCESSORY_DETECT_MODE_1,
-                                  ARIZONA_ACCDET_MODE_MASK |
-                                  ARIZONA_ACCDET_SRC,
-                                  ARIZONA_ACCDET_MODE_HPR |
-                                  info->micd_modes[0].src);
-
-               gpio_set_value_cansleep(id_gpio, 1);
-
-               regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
-                                  ARIZONA_HP_POLL, ARIZONA_HP_POLL);
-               return -EAGAIN;
-       }
-
-       /* OK, got both.  Now, compare... */
-       dev_dbg(arizona->dev, "HPDET measured %d %d\n",
-               info->hpdet_res[0], info->hpdet_res[1]);
-
-       /* Take the headphone impedance for the main report */
-       *reading = info->hpdet_res[0];
-
-       /* Sometimes we get false readings due to slow insert */
-       if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
-               dev_dbg(arizona->dev, "Retrying high impedance\n");
-               info->num_hpdet_res = 0;
-               info->hpdet_retried = true;
-               arizona_start_hpdet_acc_id(info);
-               pm_runtime_put(info->dev);
-               return -EAGAIN;
-       }
-
-       /*
-        * If we measure the mic as high impedance
-        */
-       if (!id_gpio || info->hpdet_res[1] > 50) {
-               dev_dbg(arizona->dev, "Detected mic\n");
-               *mic = true;
-               info->detecting = true;
-       } else {
-               dev_dbg(arizona->dev, "Detected headphone\n");
-       }
-
-       /* Make sure everything is reset back to the real polarity */
-       regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
-                          ARIZONA_ACCDET_SRC, info->micd_modes[0].src);
-
-       return 0;
-}
-
-static irqreturn_t arizona_hpdet_irq(int irq, void *data)
-{
-       struct arizona_extcon_info *info = data;
-       struct arizona *arizona = info->arizona;
-       int id_gpio = arizona->pdata.hpdet_id_gpio;
-       unsigned int report = EXTCON_JACK_HEADPHONE;
-       int ret, reading;
-       bool mic = false;
-
-       mutex_lock(&info->lock);
-
-       /* If we got a spurious IRQ for some reason then ignore it */
-       if (!info->hpdet_active) {
-               dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
-               mutex_unlock(&info->lock);
-               return IRQ_NONE;
-       }
-
-       /* If the cable was removed while measuring ignore the result */
-       ret = extcon_get_state(info->edev, EXTCON_MECHANICAL);
-       if (ret < 0) {
-               dev_err(arizona->dev, "Failed to check cable state: %d\n",
-                       ret);
-               goto out;
-       } else if (!ret) {
-               dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
-               goto done;
-       }
-
-       ret = arizona_hpdet_read(info);
-       if (ret == -EAGAIN)
-               goto out;
-       else if (ret < 0)
-               goto done;
-       reading = ret;
-
-       /* Reset back to starting range */
-       regmap_update_bits(arizona->regmap,
-                          ARIZONA_HEADPHONE_DETECT_1,
-                          ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
-                          0);
-
-       ret = arizona_hpdet_do_id(info, &reading, &mic);
-       if (ret == -EAGAIN)
-               goto out;
-       else if (ret < 0)
-               goto done;
-
-       /* Report high impedence cables as line outputs */
-       if (reading >= 5000)
-               report = EXTCON_JACK_LINE_OUT;
-       else
-               report = EXTCON_JACK_HEADPHONE;
-
-       ret = extcon_set_state_sync(info->edev, report, true);
-       if (ret != 0)
-               dev_err(arizona->dev, "Failed to report HP/line: %d\n",
-                       ret);
-
-done:
-       /* Reset back to starting range */
-       regmap_update_bits(arizona->regmap,
-                          ARIZONA_HEADPHONE_DETECT_1,
-                          ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
-                          0);
-
-       arizona_extcon_hp_clamp(info, false);
-
-       if (id_gpio)
-               gpio_set_value_cansleep(id_gpio, 0);
-
-       /* If we have a mic then reenable MICDET */
-       if (mic || info->mic)
-               arizona_start_mic(info);
-
-       if (info->hpdet_active) {
-               pm_runtime_put_autosuspend(info->dev);
-               info->hpdet_active = false;
-       }
-
-       info->hpdet_done = true;
-
-out:
-       mutex_unlock(&info->lock);
-
-       return IRQ_HANDLED;
-}
-
-static void arizona_identify_headphone(struct arizona_extcon_info *info)
-{
-       struct arizona *arizona = info->arizona;
-       int ret;
-
-       if (info->hpdet_done)
-               return;
-
-       dev_dbg(arizona->dev, "Starting HPDET\n");
-
-       /* Make sure we keep the device enabled during the measurement */
-       pm_runtime_get(info->dev);
-
-       info->hpdet_active = true;
-
-       arizona_stop_mic(info);
-
-       arizona_extcon_hp_clamp(info, true);
-
-       ret = regmap_update_bits(arizona->regmap,
-                                ARIZONA_ACCESSORY_DETECT_MODE_1,
-                                ARIZONA_ACCDET_MODE_MASK,
-                                arizona->pdata.hpdet_channel);
-       if (ret != 0) {
-               dev_err(arizona->dev, "Failed to set HPDET mode: %d\n", ret);
-               goto err;
-       }
-
-       ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
-                                ARIZONA_HP_POLL, ARIZONA_HP_POLL);
-       if (ret != 0) {
-               dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
-                       ret);
-               goto err;
-       }
-
-       return;
-
-err:
-       arizona_extcon_hp_clamp(info, false);
-       pm_runtime_put_autosuspend(info->dev);
-
-       /* Just report headphone */
-       ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true);
-       if (ret != 0)
-               dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
-
-       if (info->mic)
-               arizona_start_mic(info);
-
-       info->hpdet_active = false;
-}
-
-static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
-{
-       struct arizona *arizona = info->arizona;
-       int hp_reading = 32;
-       bool mic;
-       int ret;
-
-       dev_dbg(arizona->dev, "Starting identification via HPDET\n");
-
-       /* Make sure we keep the device enabled during the measurement */
-       pm_runtime_get_sync(info->dev);
-
-       info->hpdet_active = true;
-
-       arizona_extcon_hp_clamp(info, true);
-
-       ret = regmap_update_bits(arizona->regmap,
-                                ARIZONA_ACCESSORY_DETECT_MODE_1,
-                                ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
-                                info->micd_modes[0].src |
-                                arizona->pdata.hpdet_channel);
-       if (ret != 0) {
-               dev_err(arizona->dev, "Failed to set HPDET mode: %d\n", ret);
-               goto err;
-       }
-
-       if (arizona->pdata.hpdet_acc_id_line) {
-               ret = regmap_update_bits(arizona->regmap,
-                                        ARIZONA_HEADPHONE_DETECT_1,
-                                        ARIZONA_HP_POLL, ARIZONA_HP_POLL);
-               if (ret != 0) {
-                       dev_err(arizona->dev,
-                               "Can't start HPDETL measurement: %d\n",
-                               ret);
-                       goto err;
-               }
-       } else {
-               arizona_hpdet_do_id(info, &hp_reading, &mic);
-       }
-
-       return;
-
-err:
-       /* Just report headphone */
-       ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true);
-       if (ret != 0)
-               dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
-
-       info->hpdet_active = false;
-}
-
-static void arizona_micd_timeout_work(struct work_struct *work)
-{
-       struct arizona_extcon_info *info = container_of(work,
-                                               struct arizona_extcon_info,
-                                               micd_timeout_work.work);
-
-       mutex_lock(&info->lock);
-
-       dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
-
-       info->detecting = false;
-
-       arizona_identify_headphone(info);
-
-       mutex_unlock(&info->lock);
-}
-
-static int arizona_micd_adc_read(struct arizona_extcon_info *info)
-{
-       struct arizona *arizona = info->arizona;
-       unsigned int val;
-       int ret;
-
-       /* Must disable MICD before we read the ADCVAL */
-       regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
-                          ARIZONA_MICD_ENA, 0);
-
-       ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_4, &val);
-       if (ret != 0) {
-               dev_err(arizona->dev,
-                       "Failed to read MICDET_ADCVAL: %d\n", ret);
-               return ret;
-       }
-
-       dev_dbg(arizona->dev, "MICDET_ADCVAL: %x\n", val);
-
-       val &= ARIZONA_MICDET_ADCVAL_MASK;
-       if (val < ARRAY_SIZE(arizona_micd_levels))
-               val = arizona_micd_levels[val];
-       else
-               val = INT_MAX;
-
-       if (val <= QUICK_HEADPHONE_MAX_OHM)
-               val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_0;
-       else if (val <= MICROPHONE_MIN_OHM)
-               val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_1;
-       else if (val <= MICROPHONE_MAX_OHM)
-               val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_8;
-       else
-               val = ARIZONA_MICD_LVL_8;
-
-       return val;
-}
-
-static int arizona_micd_read(struct arizona_extcon_info *info)
-{
-       struct arizona *arizona = info->arizona;
-       unsigned int val = 0;
-       int ret, i;
-
-       for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
-               ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
-               if (ret != 0) {
-                       dev_err(arizona->dev,
-                               "Failed to read MICDET: %d\n", ret);
-                       return ret;
-               }
-
-               dev_dbg(arizona->dev, "MICDET: %x\n", val);
-
-               if (!(val & ARIZONA_MICD_VALID)) {
-                       dev_warn(arizona->dev,
-                                "Microphone detection state invalid\n");
-                       return -EINVAL;
-               }
-       }
-
-       if (i == 10 && !(val & MICD_LVL_0_TO_8)) {
-               dev_err(arizona->dev, "Failed to get valid MICDET value\n");
-               return -EINVAL;
-       }
-
-       return val;
-}
-
-static int arizona_micdet_reading(void *priv)
-{
-       struct arizona_extcon_info *info = priv;
-       struct arizona *arizona = info->arizona;
-       int ret, val;
-
-       if (info->detecting && arizona->pdata.micd_software_compare)
-               ret = arizona_micd_adc_read(info);
-       else
-               ret = arizona_micd_read(info);
-       if (ret < 0)
-               return ret;
-
-       val = ret;
-
-       /* Due to jack detect this should never happen */
-       if (!(val & ARIZONA_MICD_STS)) {
-               dev_warn(arizona->dev, "Detected open circuit\n");
-               info->mic = false;
-               info->detecting = false;
-               arizona_identify_headphone(info);
-               return 0;
-       }
-
-       /* If we got a high impedence we should have a headset, report it. */
-       if (val & ARIZONA_MICD_LVL_8) {
-               info->mic = true;
-               info->detecting = false;
-
-               arizona_identify_headphone(info);
-
-               ret = extcon_set_state_sync(info->edev,
-                                             EXTCON_JACK_MICROPHONE, true);
-               if (ret != 0)
-                       dev_err(arizona->dev, "Headset report failed: %d\n",
-                               ret);
-
-               /* Don't need to regulate for button detection */
-               ret = regulator_allow_bypass(info->micvdd, true);
-               if (ret != 0) {
-                       dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
-                               ret);
-               }
-
-               return 0;
-       }
-
-       /* If we detected a lower impedence during initial startup
-        * then we probably have the wrong polarity, flip it.  Don't
-        * do this for the lowest impedences to speed up detection of
-        * plain headphones.  If both polarities report a low
-        * impedence then give up and report headphones.
-        */
-       if (val & MICD_LVL_1_TO_7) {
-               if (info->jack_flips >= info->micd_num_modes * 10) {
-                       dev_dbg(arizona->dev, "Detected HP/line\n");
-
-                       info->detecting = false;
-
-                       arizona_identify_headphone(info);
-               } else {
-                       info->micd_mode++;
-                       if (info->micd_mode == info->micd_num_modes)
-                               info->micd_mode = 0;
-                       arizona_extcon_set_mode(info, info->micd_mode);
-
-                       info->jack_flips++;
-
-                       if (arizona->pdata.micd_software_compare)
-                               regmap_update_bits(arizona->regmap,
-                                                  ARIZONA_MIC_DETECT_1,
-                                                  ARIZONA_MICD_ENA,
-                                                  ARIZONA_MICD_ENA);
-
-                       queue_delayed_work(system_power_efficient_wq,
-                                          &info->micd_timeout_work,
-                                          msecs_to_jiffies(arizona->pdata.micd_timeout));
-               }
-
-               return 0;
-       }
-
-       /*
-        * If we're still detecting and we detect a short then we've
-        * got a headphone.
-        */
-       dev_dbg(arizona->dev, "Headphone detected\n");
-       info->detecting = false;
-
-       arizona_identify_headphone(info);
-
-       return 0;
-}
-
-static int arizona_button_reading(void *priv)
-{
-       struct arizona_extcon_info *info = priv;
-       struct arizona *arizona = info->arizona;
-       int val, key, lvl, i;
-
-       val = arizona_micd_read(info);
-       if (val < 0)
-               return val;
-
-       /*
-        * If we're still detecting and we detect a short then we've
-        * got a headphone.  Otherwise it's a button press.
-        */
-       if (val & MICD_LVL_0_TO_7) {
-               if (info->mic) {
-                       dev_dbg(arizona->dev, "Mic button detected\n");
-
-                       lvl = val & ARIZONA_MICD_LVL_MASK;
-                       lvl >>= ARIZONA_MICD_LVL_SHIFT;
-
-                       for (i = 0; i < info->num_micd_ranges; i++)
-                               input_report_key(info->input,
-                                                info->micd_ranges[i].key, 0);
-
-                       if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
-                               key = info->micd_ranges[ffs(lvl) - 1].key;
-                               input_report_key(info->input, key, 1);
-                               input_sync(info->input);
-                       } else {
-                               dev_err(arizona->dev, "Button out of range\n");
-                       }
-               } else {
-                       dev_warn(arizona->dev, "Button with no mic: %x\n",
-                                val);
-               }
-       } else {
-               dev_dbg(arizona->dev, "Mic button released\n");
-               for (i = 0; i < info->num_micd_ranges; i++)
-                       input_report_key(info->input,
-                                        info->micd_ranges[i].key, 0);
-               input_sync(info->input);
-               arizona_extcon_pulse_micbias(info);
-       }
-
-       return 0;
-}
-
-static void arizona_micd_detect(struct work_struct *work)
-{
-       struct arizona_extcon_info *info = container_of(work,
-                                               struct arizona_extcon_info,
-                                               micd_detect_work.work);
-       struct arizona *arizona = info->arizona;
-       int ret;
-
-       cancel_delayed_work_sync(&info->micd_timeout_work);
-
-       mutex_lock(&info->lock);
-
-       /* If the cable was removed while measuring ignore the result */
-       ret = extcon_get_state(info->edev, EXTCON_MECHANICAL);
-       if (ret < 0) {
-               dev_err(arizona->dev, "Failed to check cable state: %d\n",
-                               ret);
-               mutex_unlock(&info->lock);
-               return;
-       } else if (!ret) {
-               dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n");
-               mutex_unlock(&info->lock);
-               return;
-       }
-
-       if (info->detecting)
-               arizona_micdet_reading(info);
-       else
-               arizona_button_reading(info);
-
-       pm_runtime_mark_last_busy(info->dev);
-       mutex_unlock(&info->lock);
-}
-
-static irqreturn_t arizona_micdet(int irq, void *data)
-{
-       struct arizona_extcon_info *info = data;
-       struct arizona *arizona = info->arizona;
-       int debounce = arizona->pdata.micd_detect_debounce;
-
-       cancel_delayed_work_sync(&info->micd_detect_work);
-       cancel_delayed_work_sync(&info->micd_timeout_work);
-
-       mutex_lock(&info->lock);
-       if (!info->detecting)
-               debounce = 0;
-       mutex_unlock(&info->lock);
-
-       if (debounce)
-               queue_delayed_work(system_power_efficient_wq,
-                                  &info->micd_detect_work,
-                                  msecs_to_jiffies(debounce));
-       else
-               arizona_micd_detect(&info->micd_detect_work.work);
-
-       return IRQ_HANDLED;
-}
-
-static void arizona_hpdet_work(struct work_struct *work)
-{
-       struct arizona_extcon_info *info = container_of(work,
-                                               struct arizona_extcon_info,
-                                               hpdet_work.work);
-
-       mutex_lock(&info->lock);
-       arizona_start_hpdet_acc_id(info);
-       mutex_unlock(&info->lock);
-}
-
-static int arizona_hpdet_wait(struct arizona_extcon_info *info)
-{
-       struct arizona *arizona = info->arizona;
-       unsigned int val;
-       int i, ret;
-
-       for (i = 0; i < ARIZONA_HPDET_WAIT_COUNT; i++) {
-               ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2,
-                               &val);
-               if (ret) {
-                       dev_err(arizona->dev,
-                               "Failed to read HPDET state: %d\n", ret);
-                       return ret;
-               }
-
-               switch (info->hpdet_ip_version) {
-               case 0:
-                       if (val & ARIZONA_HP_DONE)
-                               return 0;
-                       break;
-               default:
-                       if (val & ARIZONA_HP_DONE_B)
-                               return 0;
-                       break;
-               }
-
-               msleep(ARIZONA_HPDET_WAIT_DELAY_MS);
-       }
-
-       dev_warn(arizona->dev, "HPDET did not appear to complete\n");
-
-       return -ETIMEDOUT;
-}
-
-static irqreturn_t arizona_jackdet(int irq, void *data)
-{
-       struct arizona_extcon_info *info = data;
-       struct arizona *arizona = info->arizona;
-       unsigned int val, present, mask;
-       bool cancelled_hp, cancelled_mic;
-       int ret, i;
-
-       cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
-       cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
-
-       pm_runtime_get_sync(info->dev);
-
-       mutex_lock(&info->lock);
-
-       if (info->micd_clamp) {
-               mask = ARIZONA_MICD_CLAMP_STS;
-               present = 0;
-       } else {
-               mask = ARIZONA_JD1_STS;
-               if (arizona->pdata.jd_invert)
-                       present = 0;
-               else
-                       present = ARIZONA_JD1_STS;
-       }
-
-       ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
-       if (ret != 0) {
-               dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
-                       ret);
-               mutex_unlock(&info->lock);
-               pm_runtime_put_autosuspend(info->dev);
-               return IRQ_NONE;
-       }
-
-       val &= mask;
-       if (val == info->last_jackdet) {
-               dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
-               if (cancelled_hp)
-                       queue_delayed_work(system_power_efficient_wq,
-                                          &info->hpdet_work,
-                                          msecs_to_jiffies(HPDET_DEBOUNCE));
-
-               if (cancelled_mic) {
-                       int micd_timeout = arizona->pdata.micd_timeout;
-
-                       queue_delayed_work(system_power_efficient_wq,
-                                          &info->micd_timeout_work,
-                                          msecs_to_jiffies(micd_timeout));
-               }
-
-               goto out;
-       }
-       info->last_jackdet = val;
-
-       if (info->last_jackdet == present) {
-               dev_dbg(arizona->dev, "Detected jack\n");
-               ret = extcon_set_state_sync(info->edev,
-                                             EXTCON_MECHANICAL, true);
-
-               if (ret != 0)
-                       dev_err(arizona->dev, "Mechanical report failed: %d\n",
-                               ret);
-
-               info->detecting = true;
-               info->mic = false;
-               info->jack_flips = 0;
-
-               if (!arizona->pdata.hpdet_acc_id) {
-                       arizona_start_mic(info);
-               } else {
-                       queue_delayed_work(system_power_efficient_wq,
-                                          &info->hpdet_work,
-                                          msecs_to_jiffies(HPDET_DEBOUNCE));
-               }
-
-               if (info->micd_clamp || !arizona->pdata.jd_invert)
-                       regmap_update_bits(arizona->regmap,
-                                          ARIZONA_JACK_DETECT_DEBOUNCE,
-                                          ARIZONA_MICD_CLAMP_DB |
-                                          ARIZONA_JD1_DB, 0);
-       } else {
-               dev_dbg(arizona->dev, "Detected jack removal\n");
-
-               arizona_stop_mic(info);
-
-               info->num_hpdet_res = 0;
-               for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
-                       info->hpdet_res[i] = 0;
-               info->mic = false;
-               info->hpdet_done = false;
-               info->hpdet_retried = false;
-
-               for (i = 0; i < info->num_micd_ranges; i++)
-                       input_report_key(info->input,
-                                        info->micd_ranges[i].key, 0);
-               input_sync(info->input);
-
-               for (i = 0; i < ARRAY_SIZE(arizona_cable) - 1; i++) {
-                       ret = extcon_set_state_sync(info->edev,
-                                       arizona_cable[i], false);
-                       if (ret != 0)
-                               dev_err(arizona->dev,
-                                       "Removal report failed: %d\n", ret);
-               }
-
-               /*
-                * If the jack was removed during a headphone detection we
-                * need to wait for the headphone detection to finish, as
-                * it can not be aborted. We don't want to be able to start
-                * a new headphone detection from a fresh insert until this
-                * one is finished.
-                */
-               arizona_hpdet_wait(info);
-
-               regmap_update_bits(arizona->regmap,
-                                  ARIZONA_JACK_DETECT_DEBOUNCE,
-                                  ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
-                                  ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
-       }
-
-out:
-       /* Clear trig_sts to make sure DCVDD is not forced up */
-       regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
-                    ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
-                    ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
-                    ARIZONA_JD1_FALL_TRIG_STS |
-                    ARIZONA_JD1_RISE_TRIG_STS);
-
-       mutex_unlock(&info->lock);
-
-       pm_runtime_mark_last_busy(info->dev);
-       pm_runtime_put_autosuspend(info->dev);
-
-       return IRQ_HANDLED;
-}
-
-/* Map a level onto a slot in the register bank */
-static void arizona_micd_set_level(struct arizona *arizona, int index,
-                                  unsigned int level)
-{
-       int reg;
-       unsigned int mask;
-
-       reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
-
-       if (!(index % 2)) {
-               mask = 0x3f00;
-               level <<= 8;
-       } else {
-               mask = 0x3f;
-       }
-
-       /* Program the level itself */
-       regmap_update_bits(arizona->regmap, reg, mask, level);
-}
-
-static int arizona_extcon_get_micd_configs(struct device *dev,
-                                          struct arizona *arizona)
-{
-       const char * const prop = "wlf,micd-configs";
-       const int entries_per_config = 3;
-       struct arizona_micd_config *micd_configs;
-       int nconfs, ret;
-       int i, j;
-       u32 *vals;
-
-       nconfs = device_property_count_u32(arizona->dev, prop);
-       if (nconfs <= 0)
-               return 0;
-
-       vals = kcalloc(nconfs, sizeof(u32), GFP_KERNEL);
-       if (!vals)
-               return -ENOMEM;
-
-       ret = device_property_read_u32_array(arizona->dev, prop, vals, nconfs);
-       if (ret < 0)
-               goto out;
-
-       nconfs /= entries_per_config;
-       micd_configs = devm_kcalloc(dev, nconfs, sizeof(*micd_configs),
-                                   GFP_KERNEL);
-       if (!micd_configs) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       for (i = 0, j = 0; i < nconfs; ++i) {
-               micd_configs[i].src = vals[j++] ? ARIZONA_ACCDET_SRC : 0;
-               micd_configs[i].bias = vals[j++];
-               micd_configs[i].gpio = vals[j++];
-       }
-
-       arizona->pdata.micd_configs = micd_configs;
-       arizona->pdata.num_micd_configs = nconfs;
-
-out:
-       kfree(vals);
-       return ret;
-}
-
-static int arizona_extcon_device_get_pdata(struct device *dev,
-                                          struct arizona *arizona)
-{
-       struct arizona_pdata *pdata = &arizona->pdata;
-       unsigned int val = ARIZONA_ACCDET_MODE_HPL;
-       int ret;
-
-       device_property_read_u32(arizona->dev, "wlf,hpdet-channel", &val);
-       switch (val) {
-       case ARIZONA_ACCDET_MODE_HPL:
-       case ARIZONA_ACCDET_MODE_HPR:
-               pdata->hpdet_channel = val;
-               break;
-       default:
-               dev_err(arizona->dev,
-                       "Wrong wlf,hpdet-channel DT value %d\n", val);
-               pdata->hpdet_channel = ARIZONA_ACCDET_MODE_HPL;
-       }
-
-       device_property_read_u32(arizona->dev, "wlf,micd-detect-debounce",
-                                &pdata->micd_detect_debounce);
-
-       device_property_read_u32(arizona->dev, "wlf,micd-bias-start-time",
-                                &pdata->micd_bias_start_time);
-
-       device_property_read_u32(arizona->dev, "wlf,micd-rate",
-                                &pdata->micd_rate);
-
-       device_property_read_u32(arizona->dev, "wlf,micd-dbtime",
-                                &pdata->micd_dbtime);
-
-       device_property_read_u32(arizona->dev, "wlf,micd-timeout-ms",
-                                &pdata->micd_timeout);
-
-       pdata->micd_force_micbias = device_property_read_bool(arizona->dev,
-                                               "wlf,micd-force-micbias");
-
-       pdata->micd_software_compare = device_property_read_bool(arizona->dev,
-                                               "wlf,micd-software-compare");
-
-       pdata->jd_invert = device_property_read_bool(arizona->dev,
-                                                    "wlf,jd-invert");
-
-       device_property_read_u32(arizona->dev, "wlf,gpsw", &pdata->gpsw);
-
-       pdata->jd_gpio5 = device_property_read_bool(arizona->dev,
-                                                   "wlf,use-jd2");
-       pdata->jd_gpio5_nopull = device_property_read_bool(arizona->dev,
-                                               "wlf,use-jd2-nopull");
-
-       ret = arizona_extcon_get_micd_configs(dev, arizona);
-       if (ret < 0)
-               dev_err(arizona->dev, "Failed to read micd configs: %d\n", ret);
-
-       return 0;
-}
-
-static int arizona_extcon_probe(struct platform_device *pdev)
-{
-       struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
-       struct arizona_pdata *pdata = &arizona->pdata;
-       struct arizona_extcon_info *info;
-       unsigned int val;
-       unsigned int clamp_mode;
-       int jack_irq_fall, jack_irq_rise;
-       int ret, mode, i, j;
-
-       if (!arizona->dapm || !arizona->dapm->card)
-               return -EPROBE_DEFER;
-
-       info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
-       if (!info)
-               return -ENOMEM;
-
-       if (!dev_get_platdata(arizona->dev))
-               arizona_extcon_device_get_pdata(&pdev->dev, arizona);
-
-       info->micvdd = devm_regulator_get(&pdev->dev, "MICVDD");
-       if (IS_ERR(info->micvdd)) {
-               ret = PTR_ERR(info->micvdd);
-               dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
-               return ret;
-       }
-
-       mutex_init(&info->lock);
-       info->arizona = arizona;
-       info->dev = &pdev->dev;
-       info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
-       INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
-       INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
-       INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
-       platform_set_drvdata(pdev, info);
-
-       switch (arizona->type) {
-       case WM5102:
-               switch (arizona->rev) {
-               case 0:
-                       info->micd_reva = true;
-                       break;
-               default:
-                       info->micd_clamp = true;
-                       info->hpdet_ip_version = 1;
-                       break;
-               }
-               break;
-       case WM5110:
-       case WM8280:
-               switch (arizona->rev) {
-               case 0 ... 2:
-                       break;
-               default:
-                       info->micd_clamp = true;
-                       info->hpdet_ip_version = 2;
-                       break;
-               }
-               break;
-       case WM8998:
-       case WM1814:
-               info->micd_clamp = true;
-               info->hpdet_ip_version = 2;
-               break;
-       default:
-               break;
-       }
-
-       info->edev = devm_extcon_dev_allocate(&pdev->dev, arizona_cable);
-       if (IS_ERR(info->edev)) {
-               dev_err(&pdev->dev, "failed to allocate extcon device\n");
-               return -ENOMEM;
-       }
-
-       ret = devm_extcon_dev_register(&pdev->dev, info->edev);
-       if (ret < 0) {
-               dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
-                       ret);
-               return ret;
-       }
-
-       info->input = devm_input_allocate_device(&pdev->dev);
-       if (!info->input) {
-               dev_err(arizona->dev, "Can't allocate input dev\n");
-               ret = -ENOMEM;
-               return ret;
-       }
-
-       info->input->name = "Headset";
-       info->input->phys = "arizona/extcon";
-
-       if (!pdata->micd_timeout)
-               pdata->micd_timeout = DEFAULT_MICD_TIMEOUT;
-
-       if (pdata->num_micd_configs) {
-               info->micd_modes = pdata->micd_configs;
-               info->micd_num_modes = pdata->num_micd_configs;
-       } else {
-               info->micd_modes = micd_default_modes;
-               info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
-       }
-
-       if (arizona->pdata.gpsw > 0)
-               regmap_update_bits(arizona->regmap, ARIZONA_GP_SWITCH_1,
-                               ARIZONA_SW1_MODE_MASK, arizona->pdata.gpsw);
-
-       if (pdata->micd_pol_gpio > 0) {
-               if (info->micd_modes[0].gpio)
-                       mode = GPIOF_OUT_INIT_HIGH;
-               else
-                       mode = GPIOF_OUT_INIT_LOW;
-
-               ret = devm_gpio_request_one(&pdev->dev, pdata->micd_pol_gpio,
-                                           mode, "MICD polarity");
-               if (ret != 0) {
-                       dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
-                               pdata->micd_pol_gpio, ret);
-                       return ret;
-               }
-
-               info->micd_pol_gpio = gpio_to_desc(pdata->micd_pol_gpio);
-       } else {
-               if (info->micd_modes[0].gpio)
-                       mode = GPIOD_OUT_HIGH;
-               else
-                       mode = GPIOD_OUT_LOW;
-
-               /* We can't use devm here because we need to do the get
-                * against the MFD device, as that is where the of_node
-                * will reside, but if we devm against that the GPIO
-                * will not be freed if the extcon driver is unloaded.
-                */
-               info->micd_pol_gpio = gpiod_get_optional(arizona->dev,
-                                                        "wlf,micd-pol",
-                                                        GPIOD_OUT_LOW);
-               if (IS_ERR(info->micd_pol_gpio)) {
-                       ret = PTR_ERR(info->micd_pol_gpio);
-                       dev_err(arizona->dev,
-                               "Failed to get microphone polarity GPIO: %d\n",
-                               ret);
-                       return ret;
-               }
-       }
-
-       if (arizona->pdata.hpdet_id_gpio > 0) {
-               ret = devm_gpio_request_one(&pdev->dev,
-                                           arizona->pdata.hpdet_id_gpio,
-                                           GPIOF_OUT_INIT_LOW,
-                                           "HPDET");
-               if (ret != 0) {
-                       dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
-                               arizona->pdata.hpdet_id_gpio, ret);
-                       goto err_gpio;
-               }
-       }
-
-       if (arizona->pdata.micd_bias_start_time)
-               regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
-                                  ARIZONA_MICD_BIAS_STARTTIME_MASK,
-                                  arizona->pdata.micd_bias_start_time
-                                  << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
-
-       if (arizona->pdata.micd_rate)
-               regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
-                                  ARIZONA_MICD_RATE_MASK,
-                                  arizona->pdata.micd_rate
-                                  << ARIZONA_MICD_RATE_SHIFT);
-
-       switch (arizona->pdata.micd_dbtime) {
-       case MICD_DBTIME_FOUR_READINGS:
-               regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
-                                  ARIZONA_MICD_DBTIME_MASK,
-                                  ARIZONA_MICD_DBTIME);
-               break;
-       case MICD_DBTIME_TWO_READINGS:
-               regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
-                                  ARIZONA_MICD_DBTIME_MASK, 0);
-               break;
-       default:
-               break;
-       }
-
-       BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) <
-                    ARIZONA_NUM_MICD_BUTTON_LEVELS);
-
-       if (arizona->pdata.num_micd_ranges) {
-               info->micd_ranges = pdata->micd_ranges;
-               info->num_micd_ranges = pdata->num_micd_ranges;
-       } else {
-               info->micd_ranges = micd_default_ranges;
-               info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
-       }
-
-       if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
-               dev_err(arizona->dev, "Too many MICD ranges: %d\n",
-                       arizona->pdata.num_micd_ranges);
-       }
-
-       if (info->num_micd_ranges > 1) {
-               for (i = 1; i < info->num_micd_ranges; i++) {
-                       if (info->micd_ranges[i - 1].max >
-                           info->micd_ranges[i].max) {
-                               dev_err(arizona->dev,
-                                       "MICD ranges must be sorted\n");
-                               ret = -EINVAL;
-                               goto err_gpio;
-                       }
-               }
-       }
-
-       /* Disable all buttons by default */
-       regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
-                          ARIZONA_MICD_LVL_SEL_MASK, 0x81);
-
-       /* Set up all the buttons the user specified */
-       for (i = 0; i < info->num_micd_ranges; i++) {
-               for (j = 0; j < ARIZONA_NUM_MICD_BUTTON_LEVELS; j++)
-                       if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
-                               break;
-
-               if (j == ARIZONA_NUM_MICD_BUTTON_LEVELS) {
-                       dev_err(arizona->dev, "Unsupported MICD level %d\n",
-                               info->micd_ranges[i].max);
-                       ret = -EINVAL;
-                       goto err_gpio;
-               }
-
-               dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
-                       arizona_micd_levels[j], i);
-
-               arizona_micd_set_level(arizona, i, j);
-               input_set_capability(info->input, EV_KEY,
-                                    info->micd_ranges[i].key);
-
-               /* Enable reporting of that range */
-               regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
-                                  1 << i, 1 << i);
-       }
-
-       /* Set all the remaining keys to a maximum */
-       for (; i < ARIZONA_MAX_MICD_RANGE; i++)
-               arizona_micd_set_level(arizona, i, 0x3f);
-
-       /*
-        * If we have a clamp use it, activating in conjunction with
-        * GPIO5 if that is connected for jack detect operation.
-        */
-       if (info->micd_clamp) {
-               if (arizona->pdata.jd_gpio5) {
-                       /* Put the GPIO into input mode with optional pull */
-                       val = 0xc101;
-                       if (arizona->pdata.jd_gpio5_nopull)
-                               val &= ~ARIZONA_GPN_PU;
-
-                       regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
-                                    val);
-
-                       if (arizona->pdata.jd_invert)
-                               clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH_GP5H;
-                       else
-                               clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL_GP5H;
-               } else {
-                       if (arizona->pdata.jd_invert)
-                               clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH;
-                       else
-                               clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL;
-               }
-
-               regmap_update_bits(arizona->regmap,
-                                  ARIZONA_MICD_CLAMP_CONTROL,
-                                  ARIZONA_MICD_CLAMP_MODE_MASK, clamp_mode);
-
-               regmap_update_bits(arizona->regmap,
-                                  ARIZONA_JACK_DETECT_DEBOUNCE,
-                                  ARIZONA_MICD_CLAMP_DB,
-                                  ARIZONA_MICD_CLAMP_DB);
-       }
-
-       arizona_extcon_set_mode(info, 0);
-
-       pm_runtime_enable(&pdev->dev);
-       pm_runtime_idle(&pdev->dev);
-       pm_runtime_get_sync(&pdev->dev);
-
-       if (info->micd_clamp) {
-               jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
-               jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
-       } else {
-               jack_irq_rise = ARIZONA_IRQ_JD_RISE;
-               jack_irq_fall = ARIZONA_IRQ_JD_FALL;
-       }
-
-       ret = arizona_request_irq(arizona, jack_irq_rise,
-                                 "JACKDET rise", arizona_jackdet, info);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
-                       ret);
-               goto err_pm;
-       }
-
-       ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
-                       ret);
-               goto err_rise;
-       }
-
-       ret = arizona_request_irq(arizona, jack_irq_fall,
-                                 "JACKDET fall", arizona_jackdet, info);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
-               goto err_rise_wake;
-       }
-
-       ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
-                       ret);
-               goto err_fall;
-       }
-
-       ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
-                                 "MICDET", arizona_micdet, info);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
-               goto err_fall_wake;
-       }
-
-       ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
-                                 "HPDET", arizona_hpdet_irq, info);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
-               goto err_micdet;
-       }
-
-       arizona_clk32k_enable(arizona);
-       regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
-                          ARIZONA_JD1_DB, ARIZONA_JD1_DB);
-       regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
-                          ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
-
-       ret = regulator_allow_bypass(info->micvdd, true);
-       if (ret != 0)
-               dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
-                        ret);
-
-       ret = input_register_device(info->input);
-       if (ret) {
-               dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
-               goto err_hpdet;
-       }
-
-       pm_runtime_put(&pdev->dev);
-
-       return 0;
-
-err_hpdet:
-       arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
-err_micdet:
-       arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
-err_fall_wake:
-       arizona_set_irq_wake(arizona, jack_irq_fall, 0);
-err_fall:
-       arizona_free_irq(arizona, jack_irq_fall, info);
-err_rise_wake:
-       arizona_set_irq_wake(arizona, jack_irq_rise, 0);
-err_rise:
-       arizona_free_irq(arizona, jack_irq_rise, info);
-err_pm:
-       pm_runtime_put(&pdev->dev);
-       pm_runtime_disable(&pdev->dev);
-err_gpio:
-       gpiod_put(info->micd_pol_gpio);
-       return ret;
-}
-
-static int arizona_extcon_remove(struct platform_device *pdev)
-{
-       struct arizona_extcon_info *info = platform_get_drvdata(pdev);
-       struct arizona *arizona = info->arizona;
-       int jack_irq_rise, jack_irq_fall;
-       bool change;
-       int ret;
-
-       ret = regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
-                                      ARIZONA_MICD_ENA, 0,
-                                      &change);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "Failed to disable micd on remove: %d\n",
-                       ret);
-       } else if (change) {
-               regulator_disable(info->micvdd);
-               pm_runtime_put(info->dev);
-       }
-
-       gpiod_put(info->micd_pol_gpio);
-
-       pm_runtime_disable(&pdev->dev);
-
-       regmap_update_bits(arizona->regmap,
-                          ARIZONA_MICD_CLAMP_CONTROL,
-                          ARIZONA_MICD_CLAMP_MODE_MASK, 0);
-
-       if (info->micd_clamp) {
-               jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
-               jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
-       } else {
-               jack_irq_rise = ARIZONA_IRQ_JD_RISE;
-               jack_irq_fall = ARIZONA_IRQ_JD_FALL;
-       }
-
-       arizona_set_irq_wake(arizona, jack_irq_rise, 0);
-       arizona_set_irq_wake(arizona, jack_irq_fall, 0);
-       arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
-       arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
-       arizona_free_irq(arizona, jack_irq_rise, info);
-       arizona_free_irq(arizona, jack_irq_fall, info);
-       cancel_delayed_work_sync(&info->hpdet_work);
-       regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
-                          ARIZONA_JD1_ENA, 0);
-       arizona_clk32k_disable(arizona);
-
-       return 0;
-}
-
-static struct platform_driver arizona_extcon_driver = {
-       .driver         = {
-               .name   = "arizona-extcon",
-       },
-       .probe          = arizona_extcon_probe,
-       .remove         = arizona_extcon_remove,
-};
-
-module_platform_driver(arizona_extcon_driver);
-
-MODULE_DESCRIPTION("Arizona Extcon driver");
-MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:extcon-arizona");
index df3f9bc..4b7ee3f 100644 (file)
@@ -927,7 +927,7 @@ int __ref efi_mem_reserve_persistent(phys_addr_t addr, u64 size)
        }
 
        /* first try to find a slot in an existing linked list entry */
-       for (prsv = efi_memreserve_root->next; prsv; prsv = rsv->next) {
+       for (prsv = efi_memreserve_root->next; prsv; ) {
                rsv = memremap(prsv, sizeof(*rsv), MEMREMAP_WB);
                index = atomic_fetch_add_unless(&rsv->count, 1, rsv->size);
                if (index < rsv->size) {
@@ -937,6 +937,7 @@ int __ref efi_mem_reserve_persistent(phys_addr_t addr, u64 size)
                        memunmap(rsv);
                        return efi_mem_reserve_iomem(addr, size);
                }
+               prsv = rsv->next;
                memunmap(rsv);
        }
 
index b69d631..7bf0a7a 100644 (file)
@@ -24,7 +24,7 @@ efi_status_t check_platform_features(void)
                return EFI_SUCCESS;
 
        tg = (read_cpuid(ID_AA64MMFR0_EL1) >> ID_AA64MMFR0_TGRAN_SHIFT) & 0xf;
-       if (tg != ID_AA64MMFR0_TGRAN_SUPPORTED) {
+       if (tg < ID_AA64MMFR0_TGRAN_SUPPORTED_MIN || tg > ID_AA64MMFR0_TGRAN_SUPPORTED_MAX) {
                if (IS_ENABLED(CONFIG_ARM64_64K_PAGES))
                        efi_err("This 64 KB granular kernel is not supported by your CPU\n");
                else
index ec2f398..26e6978 100644 (file)
@@ -96,6 +96,18 @@ static void install_memreserve_table(void)
                efi_err("Failed to install memreserve config table!\n");
 }
 
+static u32 get_supported_rt_services(void)
+{
+       const efi_rt_properties_table_t *rt_prop_table;
+       u32 supported = EFI_RT_SUPPORTED_ALL;
+
+       rt_prop_table = get_efi_config_table(EFI_RT_PROPERTIES_TABLE_GUID);
+       if (rt_prop_table)
+               supported &= rt_prop_table->runtime_services_supported;
+
+       return supported;
+}
+
 /*
  * EFI entry point for the arm/arm64 EFI stubs.  This is the entrypoint
  * that is described in the PE/COFF header.  Most of the code is the same
@@ -250,6 +262,10 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
                          (prop_tbl->memory_protection_attribute &
                           EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA);
 
+       /* force efi_novamap if SetVirtualAddressMap() is unsupported */
+       efi_novamap |= !(get_supported_rt_services() &
+                        EFI_RT_SUPPORTED_SET_VIRTUAL_ADDRESS_MAP);
+
        /* hibernation expects the runtime regions to stay in the same place */
        if (!IS_ENABLED(CONFIG_HIBERNATION) && !efi_nokaslr && !flat_va_mapping) {
                /*
index 41c1d00..abdc8a6 100644 (file)
@@ -484,6 +484,10 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),
                                }
                        }
 
+                       break;
+               case EFI_UNSUPPORTED:
+                       err = -EOPNOTSUPP;
+                       status = EFI_NOT_FOUND;
                        break;
                case EFI_NOT_FOUND:
                        break;
index e3607ec..d3b3de5 100644 (file)
@@ -1105,6 +1105,16 @@ config GPIO_BD70528
          This driver can also be built as a module. If so, the module
          will be called gpio-bd70528.
 
+config GPIO_BD71815
+       tristate "ROHM BD71815 PMIC GPIO support"
+       depends on MFD_ROHM_BD71828
+       help
+         Support for GPO(s) on ROHM BD71815 PMIC. There are two GPOs
+         available on the ROHM PMIC.
+
+         This driver can also be built as a module. If so, the module
+         will be called gpio-bd71815.
+
 config GPIO_BD71828
        tristate "ROHM BD71828 GPIO support"
        depends on MFD_ROHM_BD71828
index c58a90a..4c12f31 100644 (file)
@@ -39,6 +39,7 @@ obj-$(CONFIG_GPIO_ATH79)              += gpio-ath79.o
 obj-$(CONFIG_GPIO_BCM_KONA)            += gpio-bcm-kona.o
 obj-$(CONFIG_GPIO_BCM_XGS_IPROC)       += gpio-xgs-iproc.o
 obj-$(CONFIG_GPIO_BD70528)             += gpio-bd70528.o
+obj-$(CONFIG_GPIO_BD71815)             += gpio-bd71815.o
 obj-$(CONFIG_GPIO_BD71828)             += gpio-bd71828.o
 obj-$(CONFIG_GPIO_BD9571MWV)           += gpio-bd9571mwv.o
 obj-$(CONFIG_GPIO_BRCMSTB)             += gpio-brcmstb.o
diff --git a/drivers/gpio/gpio-bd71815.c b/drivers/gpio/gpio-bd71815.c
new file mode 100644 (file)
index 0000000..08ff285
--- /dev/null
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Support to GPOs on ROHM BD71815
+ * Copyright 2021 ROHM Semiconductors.
+ * Author: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
+ *
+ * Copyright 2014 Embest Technology Co. Ltd. Inc.
+ * Author: yanglsh@embest-tech.com
+ */
+
+#include <linux/gpio/driver.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+/* For the BD71815 register definitions */
+#include <linux/mfd/rohm-bd71815.h>
+
+struct bd71815_gpio {
+       /* chip.parent points the MFD which provides DT node and regmap */
+       struct gpio_chip chip;
+       /* dev points to the platform device for devm and prints */
+       struct device *dev;
+       struct regmap *regmap;
+};
+
+static int bd71815gpo_get(struct gpio_chip *chip, unsigned int offset)
+{
+       struct bd71815_gpio *bd71815 = gpiochip_get_data(chip);
+       int ret, val;
+
+       ret = regmap_read(bd71815->regmap, BD71815_REG_GPO, &val);
+       if (ret)
+               return ret;
+
+       return (val >> offset) & 1;
+}
+
+static void bd71815gpo_set(struct gpio_chip *chip, unsigned int offset,
+                          int value)
+{
+       struct bd71815_gpio *bd71815 = gpiochip_get_data(chip);
+       int ret, bit;
+
+       bit = BIT(offset);
+
+       if (value)
+               ret = regmap_set_bits(bd71815->regmap, BD71815_REG_GPO, bit);
+       else
+               ret = regmap_clear_bits(bd71815->regmap, BD71815_REG_GPO, bit);
+
+       if (ret)
+               dev_warn(bd71815->dev, "failed to toggle GPO\n");
+}
+
+static int bd71815_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
+                                  unsigned long config)
+{
+       struct bd71815_gpio *bdgpio = gpiochip_get_data(chip);
+
+       switch (pinconf_to_config_param(config)) {
+       case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+               return regmap_update_bits(bdgpio->regmap,
+                                         BD71815_REG_GPO,
+                                         BD71815_GPIO_DRIVE_MASK << offset,
+                                         BD71815_GPIO_OPEN_DRAIN << offset);
+       case PIN_CONFIG_DRIVE_PUSH_PULL:
+               return regmap_update_bits(bdgpio->regmap,
+                                         BD71815_REG_GPO,
+                                         BD71815_GPIO_DRIVE_MASK << offset,
+                                         BD71815_GPIO_CMOS << offset);
+       default:
+               break;
+       }
+       return -ENOTSUPP;
+}
+
+/* BD71815 GPIO is actually GPO */
+static int bd71815gpo_direction_get(struct gpio_chip *gc, unsigned int offset)
+{
+       return GPIO_LINE_DIRECTION_OUT;
+}
+
+/* Template for GPIO chip */
+static const struct gpio_chip bd71815gpo_chip = {
+       .label                  = "bd71815",
+       .owner                  = THIS_MODULE,
+       .get                    = bd71815gpo_get,
+       .get_direction          = bd71815gpo_direction_get,
+       .set                    = bd71815gpo_set,
+       .set_config             = bd71815_gpio_set_config,
+       .can_sleep              = true,
+};
+
+#define BD71815_TWO_GPIOS      GENMASK(1, 0)
+#define BD71815_ONE_GPIO       BIT(0)
+
+/*
+ * Sigh. The BD71815 and BD71817 were originally designed to support two GPO
+ * pins. At some point it was noticed the second GPO pin which is the E5 pin
+ * located at the center of IC is hard to use on PCB (due to the location). It
+ * was decided to not promote this second GPO and the pin is marked as GND in
+ * the datasheet. The functionality is still there though! I guess driving a GPO
+ * connected to the ground is a bad idea. Thus we do not support it by default.
+ * OTOH - the original driver written by colleagues at Embest did support
+ * controlling this second GPO. It is thus possible this is used in some of the
+ * products.
+ *
+ * This driver does not by default support configuring this second GPO
+ * but allows using it by providing the DT property
+ * "rohm,enable-hidden-gpo".
+ */
+static int bd71815_init_valid_mask(struct gpio_chip *gc,
+                                  unsigned long *valid_mask,
+                                  unsigned int ngpios)
+{
+       if (ngpios != 2)
+               return 0;
+
+       if (gc->parent && device_property_present(gc->parent,
+                                                 "rohm,enable-hidden-gpo"))
+               *valid_mask = BD71815_TWO_GPIOS;
+       else
+               *valid_mask = BD71815_ONE_GPIO;
+
+       return 0;
+}
+
+static int gpo_bd71815_probe(struct platform_device *pdev)
+{
+       struct bd71815_gpio *g;
+       struct device *parent, *dev;
+
+       /*
+        * Bind devm lifetime to this platform device => use dev for devm.
+        * also the prints should originate from this device.
+        */
+       dev = &pdev->dev;
+       /* The device-tree and regmap come from MFD => use parent for that */
+       parent = dev->parent;
+
+       g = devm_kzalloc(dev, sizeof(*g), GFP_KERNEL);
+       if (!g)
+               return -ENOMEM;
+
+       g->chip = bd71815gpo_chip;
+
+       /*
+        * FIXME: As writing of this the sysfs interface for GPIO control does
+        * not respect the valid_mask. Do not trust it but rather set the ngpios
+        * to 1 if "rohm,enable-hidden-gpo" is not given.
+        *
+        * This check can be removed later if the sysfs export is fixed and
+        * if the fix is backported.
+        *
+        * For now it is safest to just set the ngpios though.
+        */
+       if (device_property_present(parent, "rohm,enable-hidden-gpo"))
+               g->chip.ngpio = 2;
+       else
+               g->chip.ngpio = 1;
+
+       g->chip.init_valid_mask = bd71815_init_valid_mask;
+       g->chip.base = -1;
+       g->chip.parent = parent;
+       g->regmap = dev_get_regmap(parent, NULL);
+       g->dev = dev;
+
+       return devm_gpiochip_add_data(dev, &g->chip, g);
+}
+
+static struct platform_driver gpo_bd71815_driver = {
+       .driver = {
+               .name   = "bd71815-gpo",
+       },
+       .probe          = gpo_bd71815_probe,
+};
+module_platform_driver(gpo_bd71815_driver);
+
+MODULE_ALIAS("platform:bd71815-gpo");
+MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
+MODULE_AUTHOR("Peter Yang <yanglsh@embest-tech.com>");
+MODULE_DESCRIPTION("GPO interface for BD71815");
+MODULE_LICENSE("GPL");
index 5ea09fd..c91d056 100644 (file)
@@ -113,8 +113,29 @@ MODULE_DEVICE_TABLE(i2c, pca953x_id);
 #ifdef CONFIG_GPIO_PCA953X_IRQ
 
 #include <linux/dmi.h>
-#include <linux/gpio.h>
-#include <linux/list.h>
+
+static const struct acpi_gpio_params pca953x_irq_gpios = { 0, 0, true };
+
+static const struct acpi_gpio_mapping pca953x_acpi_irq_gpios[] = {
+       { "irq-gpios", &pca953x_irq_gpios, 1, ACPI_GPIO_QUIRK_ABSOLUTE_NUMBER },
+       { }
+};
+
+static int pca953x_acpi_get_irq(struct device *dev)
+{
+       int ret;
+
+       ret = devm_acpi_dev_add_driver_gpios(dev, pca953x_acpi_irq_gpios);
+       if (ret)
+               dev_warn(dev, "can't add GPIO ACPI mapping\n");
+
+       ret = acpi_dev_gpio_irq_get_by(ACPI_COMPANION(dev), "irq-gpios", 0);
+       if (ret < 0)
+               return ret;
+
+       dev_info(dev, "ACPI interrupt quirk (IRQ %d)\n", ret);
+       return ret;
+}
 
 static const struct dmi_system_id pca953x_dmi_acpi_irq_info[] = {
        {
@@ -133,59 +154,6 @@ static const struct dmi_system_id pca953x_dmi_acpi_irq_info[] = {
        },
        {}
 };
-
-#ifdef CONFIG_ACPI
-static int pca953x_acpi_get_pin(struct acpi_resource *ares, void *data)
-{
-       struct acpi_resource_gpio *agpio;
-       int *pin = data;
-
-       if (acpi_gpio_get_irq_resource(ares, &agpio))
-               *pin = agpio->pin_table[0];
-       return 1;
-}
-
-static int pca953x_acpi_find_pin(struct device *dev)
-{
-       struct acpi_device *adev = ACPI_COMPANION(dev);
-       int pin = -ENOENT, ret;
-       LIST_HEAD(r);
-
-       ret = acpi_dev_get_resources(adev, &r, pca953x_acpi_get_pin, &pin);
-       acpi_dev_free_resource_list(&r);
-       if (ret < 0)
-               return ret;
-
-       return pin;
-}
-#else
-static inline int pca953x_acpi_find_pin(struct device *dev) { return -ENXIO; }
-#endif
-
-static int pca953x_acpi_get_irq(struct device *dev)
-{
-       int pin, ret;
-
-       pin = pca953x_acpi_find_pin(dev);
-       if (pin < 0)
-               return pin;
-
-       dev_info(dev, "Applying ACPI interrupt quirk (GPIO %d)\n", pin);
-
-       if (!gpio_is_valid(pin))
-               return -EINVAL;
-
-       ret = gpio_request(pin, "pca953x interrupt");
-       if (ret)
-               return ret;
-
-       ret = gpio_to_irq(pin);
-
-       /* When pin is used as an IRQ, no need to keep it requested */
-       gpio_free(pin);
-
-       return ret;
-}
 #endif
 
 static const struct acpi_device_id pca953x_acpi_ids[] = {
index e37a57d..1aacd2a 100644 (file)
@@ -174,7 +174,7 @@ static void acpi_gpiochip_request_irq(struct acpi_gpio_chip *acpi_gpio,
        int ret, value;
 
        ret = request_threaded_irq(event->irq, NULL, event->handler,
-                                  event->irqflags, "ACPI:Event", event);
+                                  event->irqflags | IRQF_ONESHOT, "ACPI:Event", event);
        if (ret) {
                dev_err(acpi_gpio->chip->parent,
                        "Failed to setup interrupt handler for %d\n",
@@ -677,6 +677,7 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data)
        if (!lookup->desc) {
                const struct acpi_resource_gpio *agpio = &ares->data.gpio;
                bool gpioint = agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT;
+               struct gpio_desc *desc;
                u16 pin_index;
 
                if (lookup->info.quirks & ACPI_GPIO_QUIRK_ONLY_GPIOIO && gpioint)
@@ -689,8 +690,12 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data)
                if (pin_index >= agpio->pin_table_length)
                        return 1;
 
-               lookup->desc = acpi_get_gpiod(agpio->resource_source.string_ptr,
+               if (lookup->info.quirks & ACPI_GPIO_QUIRK_ABSOLUTE_NUMBER)
+                       desc = gpio_to_desc(agpio->pin_table[pin_index]);
+               else
+                       desc = acpi_get_gpiod(agpio->resource_source.string_ptr,
                                              agpio->pin_table[pin_index]);
+               lookup->desc = desc;
                lookup->info.pin_config = agpio->pin_config;
                lookup->info.debounce = agpio->debounce_timeout;
                lookup->info.gpioint = gpioint;
@@ -940,8 +945,9 @@ struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
 }
 
 /**
- * acpi_dev_gpio_irq_get() - Find GpioInt and translate it to Linux IRQ number
+ * acpi_dev_gpio_irq_get_by() - Find GpioInt and translate it to Linux IRQ number
  * @adev: pointer to a ACPI device to get IRQ from
+ * @name: optional name of GpioInt resource
  * @index: index of GpioInt resource (starting from %0)
  *
  * If the device has one or more GpioInt resources, this function can be
@@ -951,9 +957,12 @@ struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
  * The function is idempotent, though each time it runs it will configure GPIO
  * pin direction according to the flags in GpioInt resource.
  *
+ * The function takes optional @name parameter. If the resource has a property
+ * name, then only those will be taken into account.
+ *
  * Return: Linux IRQ number (> %0) on success, negative errno on failure.
  */
-int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
+int acpi_dev_gpio_irq_get_by(struct acpi_device *adev, const char *name, int index)
 {
        int idx, i;
        unsigned int irq_flags;
@@ -963,7 +972,7 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
                struct acpi_gpio_info info;
                struct gpio_desc *desc;
 
-               desc = acpi_get_gpiod_by_index(adev, NULL, i, &info);
+               desc = acpi_get_gpiod_by_index(adev, name, i, &info);
 
                /* Ignore -EPROBE_DEFER, it only matters if idx matches */
                if (IS_ERR(desc) && PTR_ERR(desc) != -EPROBE_DEFER)
@@ -1008,7 +1017,7 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
        }
        return -ENOENT;
 }
-EXPORT_SYMBOL_GPL(acpi_dev_gpio_irq_get);
+EXPORT_SYMBOL_GPL(acpi_dev_gpio_irq_get_by);
 
 static acpi_status
 acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
index adf55db..6367646 100644 (file)
@@ -367,22 +367,18 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc)
  *
  * Looks for device property "gpio-line-names" and if it exists assigns
  * GPIO line names for the chip. The memory allocated for the assigned
- * names belong to the underlying software node and should not be released
+ * names belong to the underlying firmware node and should not be released
  * by the caller.
  */
 static int devprop_gpiochip_set_names(struct gpio_chip *chip)
 {
        struct gpio_device *gdev = chip->gpiodev;
-       struct device *dev = chip->parent;
+       struct fwnode_handle *fwnode = dev_fwnode(&gdev->dev);
        const char **names;
        int ret, i;
        int count;
 
-       /* GPIO chip may not have a parent device whose properties we inspect. */
-       if (!dev)
-               return 0;
-
-       count = device_property_string_array_count(dev, "gpio-line-names");
+       count = fwnode_property_string_array_count(fwnode, "gpio-line-names");
        if (count < 0)
                return 0;
 
@@ -396,7 +392,7 @@ static int devprop_gpiochip_set_names(struct gpio_chip *chip)
        if (!names)
                return -ENOMEM;
 
-       ret = device_property_read_string_array(dev, "gpio-line-names",
+       ret = fwnode_property_read_string_array(fwnode, "gpio-line-names",
                                                names, count);
        if (ret < 0) {
                dev_warn(&gdev->dev, "failed to read GPIO line names\n");
@@ -474,9 +470,13 @@ EXPORT_SYMBOL_GPL(gpiochip_line_is_valid);
 
 static void gpiodevice_release(struct device *dev)
 {
-       struct gpio_device *gdev = dev_get_drvdata(dev);
+       struct gpio_device *gdev = container_of(dev, struct gpio_device, dev);
+       unsigned long flags;
 
+       spin_lock_irqsave(&gpio_lock, flags);
        list_del(&gdev->list);
+       spin_unlock_irqrestore(&gpio_lock, flags);
+
        ida_free(&gpio_ida, gdev->id);
        kfree_const(gdev->label);
        kfree(gdev->descs);
@@ -571,6 +571,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
                               struct lock_class_key *lock_key,
                               struct lock_class_key *request_key)
 {
+       struct fwnode_handle *fwnode = gc->parent ? dev_fwnode(gc->parent) : NULL;
        unsigned long   flags;
        int             ret = 0;
        unsigned        i;
@@ -594,6 +595,12 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
 
        of_gpio_dev_init(gc, gdev);
 
+       /*
+        * Assign fwnode depending on the result of the previous calls,
+        * if none of them succeed, assign it to the parent's one.
+        */
+       gdev->dev.fwnode = dev_fwnode(&gdev->dev) ?: fwnode;
+
        gdev->id = ida_alloc(&gpio_ida, GFP_KERNEL);
        if (gdev->id < 0) {
                ret = gdev->id;
@@ -605,7 +612,6 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
                goto err_free_ida;
 
        device_initialize(&gdev->dev);
-       dev_set_drvdata(&gdev->dev, gdev);
        if (gc->parent && gc->parent->driver)
                gdev->owner = gc->parent->driver->owner;
        else if (gc->owner)
@@ -4257,7 +4263,8 @@ static int __init gpiolib_dev_init(void)
                return ret;
        }
 
-       if (driver_register(&gpio_stub_drv) < 0) {
+       ret = driver_register(&gpio_stub_drv);
+       if (ret < 0) {
                pr_err("gpiolib: could not register GPIO stub driver\n");
                bus_unregister(&gpio_bus_type);
                return ret;
index e392a90..85b79a7 100644 (file)
@@ -228,6 +228,7 @@ source "drivers/gpu/drm/arm/Kconfig"
 config DRM_RADEON
        tristate "ATI Radeon"
        depends on DRM && PCI && MMU
+       depends on AGP || !AGP
        select FW_LOADER
         select DRM_KMS_HELPER
         select DRM_TTM
index b6879d9..49267eb 100644 (file)
@@ -180,6 +180,7 @@ extern uint amdgpu_smu_memory_pool_size;
 extern uint amdgpu_dc_feature_mask;
 extern uint amdgpu_dc_debug_mask;
 extern uint amdgpu_dm_abm_level;
+extern int amdgpu_backlight;
 extern struct amdgpu_mgpu_info mgpu_info;
 extern int amdgpu_ras_enable;
 extern uint amdgpu_ras_mask;
index 36a741d..2e9b16f 100644 (file)
@@ -903,7 +903,7 @@ void amdgpu_acpi_fini(struct amdgpu_device *adev)
  */
 bool amdgpu_acpi_is_s0ix_supported(struct amdgpu_device *adev)
 {
-#if defined(CONFIG_AMD_PMC)
+#if defined(CONFIG_AMD_PMC) || defined(CONFIG_AMD_PMC_MODULE)
        if (acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0) {
                if (adev->flags & AMD_IS_APU)
                        return true;
index 4575192..b26e2fd 100644 (file)
@@ -781,6 +781,10 @@ uint amdgpu_dm_abm_level;
 MODULE_PARM_DESC(abmlevel, "ABM level (0 = off (default), 1-4 = backlight reduction level) ");
 module_param_named(abmlevel, amdgpu_dm_abm_level, uint, 0444);
 
+int amdgpu_backlight = -1;
+MODULE_PARM_DESC(backlight, "Backlight control (0 = pwm, 1 = aux, -1 auto (default))");
+module_param_named(backlight, amdgpu_backlight, bint, 0444);
+
 /**
  * DOC: tmz (int)
  * Trusted Memory Zone (TMZ) is a method to protect data being written
index 51cd49c..24010ca 100644 (file)
@@ -146,7 +146,7 @@ static int amdgpufb_create_pinned_object(struct amdgpu_fbdev *rfbdev,
        size = mode_cmd->pitches[0] * height;
        aligned_size = ALIGN(size, PAGE_SIZE);
        ret = amdgpu_gem_object_create(adev, aligned_size, 0, domain, flags,
-                                      ttm_bo_type_kernel, NULL, &gobj);
+                                      ttm_bo_type_device, NULL, &gobj);
        if (ret) {
                pr_err("failed to allocate framebuffer (%d)\n", aligned_size);
                return -ENOMEM;
index 3e1fd1e..573cf17 100644 (file)
@@ -2267,6 +2267,11 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector)
            caps->ext_caps->bits.hdr_aux_backlight_control == 1)
                caps->aux_support = true;
 
+       if (amdgpu_backlight == 0)
+               caps->aux_support = false;
+       else if (amdgpu_backlight == 1)
+               caps->aux_support = true;
+
        /* From the specification (CTA-861-G), for calculating the maximum
         * luminance we need to use:
         *      Luminance = 50*2**(CV/32)
@@ -3185,19 +3190,6 @@ static void amdgpu_dm_update_backlight_caps(struct amdgpu_display_manager *dm)
 #endif
 }
 
-static int set_backlight_via_aux(struct dc_link *link, uint32_t brightness)
-{
-       bool rc;
-
-       if (!link)
-               return 1;
-
-       rc = dc_link_set_backlight_level_nits(link, true, brightness,
-                                             AUX_BL_DEFAULT_TRANSITION_TIME_MS);
-
-       return rc ? 0 : 1;
-}
-
 static int get_brightness_range(const struct amdgpu_dm_backlight_caps *caps,
                                unsigned *min, unsigned *max)
 {
@@ -3260,9 +3252,10 @@ static int amdgpu_dm_backlight_update_status(struct backlight_device *bd)
        brightness = convert_brightness_from_user(&caps, bd->props.brightness);
        // Change brightness based on AUX property
        if (caps.aux_support)
-               return set_backlight_via_aux(link, brightness);
-
-       rc = dc_link_set_backlight_level(dm->backlight_link, brightness, 0);
+               rc = dc_link_set_backlight_level_nits(link, true, brightness,
+                                                     AUX_BL_DEFAULT_TRANSITION_TIME_MS);
+       else
+               rc = dc_link_set_backlight_level(dm->backlight_link, brightness, 0);
 
        return rc ? 0 : 1;
 }
@@ -3270,11 +3263,27 @@ static int amdgpu_dm_backlight_update_status(struct backlight_device *bd)
 static int amdgpu_dm_backlight_get_brightness(struct backlight_device *bd)
 {
        struct amdgpu_display_manager *dm = bl_get_data(bd);
-       int ret = dc_link_get_backlight_level(dm->backlight_link);
+       struct amdgpu_dm_backlight_caps caps;
+
+       amdgpu_dm_update_backlight_caps(dm);
+       caps = dm->backlight_caps;
+
+       if (caps.aux_support) {
+               struct dc_link *link = (struct dc_link *)dm->backlight_link;
+               u32 avg, peak;
+               bool rc;
 
-       if (ret == DC_ERROR_UNEXPECTED)
-               return bd->props.brightness;
-       return convert_brightness_to_user(&dm->backlight_caps, ret);
+               rc = dc_link_get_backlight_level_nits(link, &avg, &peak);
+               if (!rc)
+                       return bd->props.brightness;
+               return convert_brightness_to_user(&caps, avg);
+       } else {
+               int ret = dc_link_get_backlight_level(dm->backlight_link);
+
+               if (ret == DC_ERROR_UNEXPECTED)
+                       return bd->props.brightness;
+               return convert_brightness_to_user(&caps, ret);
+       }
 }
 
 static const struct backlight_ops amdgpu_dm_backlight_ops = {
@@ -4716,6 +4725,7 @@ static int fill_dc_plane_attributes(struct amdgpu_device *adev,
        dc_plane_state->global_alpha_value = plane_info.global_alpha_value;
        dc_plane_state->dcc = plane_info.dcc;
        dc_plane_state->layer_index = plane_info.layer_index; // Always returns 0
+       dc_plane_state->flip_int_enabled = true;
 
        /*
         * Always set input transfer function, since plane state is refreshed
index fa5059f..bd01010 100644 (file)
@@ -2602,7 +2602,6 @@ bool dc_link_set_backlight_level(const struct dc_link *link,
                        if (pipe_ctx->plane_state == NULL)
                                frame_ramp = 0;
                } else {
-                       ASSERT(false);
                        return false;
                }
 
index 4eee3a5..18ed0d3 100644 (file)
@@ -887,6 +887,7 @@ struct dc_plane_state {
        int layer_index;
 
        union surface_update_flags update_flags;
+       bool flip_int_enabled;
        /* private to DC core */
        struct dc_plane_status status;
        struct dc_context *ctx;
index 9e796df..714c71a 100644 (file)
@@ -1257,6 +1257,16 @@ void hubp1_soft_reset(struct hubp *hubp, bool reset)
        REG_UPDATE(DCHUBP_CNTL, HUBP_DISABLE, reset ? 1 : 0);
 }
 
+void hubp1_set_flip_int(struct hubp *hubp)
+{
+       struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp);
+
+       REG_UPDATE(DCSURF_SURFACE_FLIP_INTERRUPT,
+               SURFACE_FLIP_INT_MASK, 1);
+
+       return;
+}
+
 void hubp1_init(struct hubp *hubp)
 {
        //do nothing
@@ -1290,6 +1300,7 @@ static const struct hubp_funcs dcn10_hubp_funcs = {
        .dmdata_load = NULL,
        .hubp_soft_reset = hubp1_soft_reset,
        .hubp_in_blank = hubp1_in_blank,
+       .hubp_set_flip_int = hubp1_set_flip_int,
 };
 
 /*****************************************/
index a9a6ed7..e2f2f69 100644 (file)
@@ -74,6 +74,7 @@
        SRI(DCSURF_SURFACE_EARLIEST_INUSE_C, HUBPREQ, id),\
        SRI(DCSURF_SURFACE_EARLIEST_INUSE_HIGH_C, HUBPREQ, id),\
        SRI(DCSURF_SURFACE_CONTROL, HUBPREQ, id),\
+       SRI(DCSURF_SURFACE_FLIP_INTERRUPT, HUBPREQ, id),\
        SRI(HUBPRET_CONTROL, HUBPRET, id),\
        SRI(DCN_EXPANSION_MODE, HUBPREQ, id),\
        SRI(DCHUBP_REQ_SIZE_CONFIG, HUBP, id),\
        uint32_t DCSURF_SURFACE_EARLIEST_INUSE_C; \
        uint32_t DCSURF_SURFACE_EARLIEST_INUSE_HIGH_C; \
        uint32_t DCSURF_SURFACE_CONTROL; \
+       uint32_t DCSURF_SURFACE_FLIP_INTERRUPT; \
        uint32_t HUBPRET_CONTROL; \
        uint32_t DCN_EXPANSION_MODE; \
        uint32_t DCHUBP_REQ_SIZE_CONFIG; \
        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(HUBPREQ0_DCSURF_SURFACE_FLIP_INTERRUPT, SURFACE_FLIP_INT_MASK, 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 PRIMARY_SURFACE_DCC_IND_64B_BLK;\
        type SECONDARY_SURFACE_DCC_EN;\
        type SECONDARY_SURFACE_DCC_IND_64B_BLK;\
+       type SURFACE_FLIP_INT_MASK;\
        type DET_BUF_PLANE1_BASE_ADDRESS;\
        type CROSSBAR_SRC_CB_B;\
        type CROSSBAR_SRC_CR_R;\
@@ -777,4 +781,6 @@ void hubp1_read_state_common(struct hubp *hubp);
 bool hubp1_in_blank(struct hubp *hubp);
 void hubp1_soft_reset(struct hubp *hubp, bool reset);
 
+void hubp1_set_flip_int(struct hubp *hubp);
+
 #endif
index 89912bb..9ba5c62 100644 (file)
@@ -2196,6 +2196,13 @@ static void dcn10_enable_plane(
        if (dc->debug.sanity_checks) {
                hws->funcs.verify_allow_pstate_change_high(dc);
        }
+
+       if (!pipe_ctx->top_pipe
+               && pipe_ctx->plane_state
+               && pipe_ctx->plane_state->flip_int_enabled
+               && pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int)
+                       pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int(pipe_ctx->plane_res.hubp);
+
 }
 
 void dcn10_program_gamut_remap(struct pipe_ctx *pipe_ctx)
index 0df0da2..bec7059 100644 (file)
@@ -1597,6 +1597,7 @@ static struct hubp_funcs dcn20_hubp_funcs = {
        .validate_dml_output = hubp2_validate_dml_output,
        .hubp_in_blank = hubp1_in_blank,
        .hubp_soft_reset = hubp1_soft_reset,
+       .hubp_set_flip_int = hubp1_set_flip_int,
 };
 
 
index 0726fb4..aece110 100644 (file)
@@ -1146,6 +1146,12 @@ void dcn20_enable_plane(
                pipe_ctx->plane_res.hubp->funcs->hubp_set_vm_system_aperture_settings(pipe_ctx->plane_res.hubp, &apt);
        }
 
+       if (!pipe_ctx->top_pipe
+               && pipe_ctx->plane_state
+               && pipe_ctx->plane_state->flip_int_enabled
+               && pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int)
+                       pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int(pipe_ctx->plane_res.hubp);
+
 //     if (dc->debug.sanity_checks) {
 //             dcn10_verify_allow_pstate_change_high(dc);
 //     }
@@ -1501,38 +1507,8 @@ static void dcn20_update_dchubp_dpp(
        if (pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed
                        || pipe_ctx->stream->update_flags.bits.gamut_remap
                        || pipe_ctx->stream->update_flags.bits.out_csc) {
-               struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
-
-               if (mpc->funcs->set_gamut_remap) {
-                       int i;
-                       int mpcc_id = hubp->inst;
-                       struct mpc_grph_gamut_adjustment adjust;
-                       bool enable_remap_dpp = false;
-
-                       memset(&adjust, 0, sizeof(adjust));
-                       adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
-
-                       /* save the enablement of gamut remap for dpp */
-                       enable_remap_dpp = pipe_ctx->stream->gamut_remap_matrix.enable_remap;
-
-                       /* force bypass gamut remap for dpp/cm */
-                       pipe_ctx->stream->gamut_remap_matrix.enable_remap = false;
-                       dc->hwss.program_gamut_remap(pipe_ctx);
-
-                       /* restore gamut remap flag and use this remap into mpc */
-                       pipe_ctx->stream->gamut_remap_matrix.enable_remap = enable_remap_dpp;
-
-                       /* build remap matrix for top plane if enabled */
-                       if (enable_remap_dpp && pipe_ctx->top_pipe == NULL) {
-                                       adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
-                                       for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++)
-                                               adjust.temperature_matrix[i] =
-                                                               pipe_ctx->stream->gamut_remap_matrix.matrix[i];
-                       }
-                       mpc->funcs->set_gamut_remap(mpc, mpcc_id, &adjust);
-               } else
-                       /* dpp/cm gamut remap*/
-                       dc->hwss.program_gamut_remap(pipe_ctx);
+               /* dpp/cm gamut remap*/
+               dc->hwss.program_gamut_remap(pipe_ctx);
 
                /*call the dcn2 method which uses mpc csc*/
                dc->hwss.program_output_csc(dc,
index f904585..b0c9180 100644 (file)
@@ -838,6 +838,7 @@ static struct hubp_funcs dcn21_hubp_funcs = {
        .hubp_set_flip_control_surface_gsl = hubp2_set_flip_control_surface_gsl,
        .hubp_init = hubp21_init,
        .validate_dml_output = hubp21_validate_dml_output,
+       .hubp_set_flip_int = hubp1_set_flip_int,
 };
 
 bool hubp21_construct(
index 072f8c8..4a3df13 100644 (file)
@@ -296,7 +296,7 @@ struct _vcs_dpi_soc_bounding_box_st dcn2_1_soc = {
        .num_banks = 8,
        .num_chans = 4,
        .vmm_page_size_bytes = 4096,
-       .dram_clock_change_latency_us = 11.72,
+       .dram_clock_change_latency_us = 23.84,
        .return_bus_width_bytes = 64,
        .dispclk_dppclk_vco_speed_mhz = 3600,
        .xfc_bus_transport_time_us = 4,
@@ -1062,8 +1062,6 @@ static void patch_bounding_box(struct dc *dc, struct _vcs_dpi_soc_bounding_box_s
 {
        int i;
 
-       DC_FP_START();
-
        if (dc->bb_overrides.sr_exit_time_ns) {
                for (i = 0; i < WM_SET_COUNT; i++) {
                          dc->clk_mgr->bw_params->wm_table.entries[i].sr_exit_time_us =
@@ -1088,8 +1086,6 @@ static void patch_bounding_box(struct dc *dc, struct _vcs_dpi_soc_bounding_box_s
                                dc->bb_overrides.dram_clock_change_latency_ns / 1000.0;
                }
        }
-
-       DC_FP_END();
 }
 
 void dcn21_calculate_wm(
@@ -1339,7 +1335,7 @@ static noinline bool dcn21_validate_bandwidth_fp(struct dc *dc,
        int vlevel = 0;
        int pipe_split_from[MAX_PIPES];
        int pipe_cnt = 0;
-       display_e2e_pipe_params_st *pipes = kzalloc(dc->res_pool->pipe_count * sizeof(display_e2e_pipe_params_st), GFP_KERNEL);
+       display_e2e_pipe_params_st *pipes = kzalloc(dc->res_pool->pipe_count * sizeof(display_e2e_pipe_params_st), GFP_ATOMIC);
        DC_LOGGER_INIT(dc->ctx->logger);
 
        BW_VAL_TRACE_COUNT();
@@ -1599,6 +1595,11 @@ static void update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_param
        dcn2_1_soc.num_chans = bw_params->num_channels;
 
        ASSERT(clk_table->num_entries);
+       /* Copy dcn2_1_soc.clock_limits to clock_limits to avoid copying over null states later */
+       for (i = 0; i < dcn2_1_soc.num_states + 1; i++) {
+               clock_limits[i] = dcn2_1_soc.clock_limits[i];
+       }
+
        for (i = 0; i < clk_table->num_entries; i++) {
                /* loop backwards*/
                for (closest_clk_lvl = 0, j = dcn2_1_soc.num_states - 1; j >= 0; j--) {
index 41a1d0e..e0df9b0 100644 (file)
@@ -113,6 +113,7 @@ bool cm3_helper_translate_curve_to_hw_format(
        struct pwl_result_data *rgb_resulted;
        struct pwl_result_data *rgb;
        struct pwl_result_data *rgb_plus_1;
+       struct pwl_result_data *rgb_minus_1;
        struct fixed31_32 end_value;
 
        int32_t region_start, region_end;
@@ -140,7 +141,7 @@ bool cm3_helper_translate_curve_to_hw_format(
                region_start = -MAX_LOW_POINT;
                region_end   = NUMBER_REGIONS - MAX_LOW_POINT;
        } else {
-               /* 10 segments
+               /* 11 segments
                 * segment is from 2^-10 to 2^0
                 * There are less than 256 points, for optimization
                 */
@@ -154,9 +155,10 @@ bool cm3_helper_translate_curve_to_hw_format(
                seg_distr[7] = 4;
                seg_distr[8] = 4;
                seg_distr[9] = 4;
+               seg_distr[10] = 1;
 
                region_start = -10;
-               region_end = 0;
+               region_end = 1;
        }
 
        for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++)
@@ -189,6 +191,10 @@ bool cm3_helper_translate_curve_to_hw_format(
        rgb_resulted[hw_points - 1].green = output_tf->tf_pts.green[start_index];
        rgb_resulted[hw_points - 1].blue = output_tf->tf_pts.blue[start_index];
 
+       rgb_resulted[hw_points].red = rgb_resulted[hw_points - 1].red;
+       rgb_resulted[hw_points].green = rgb_resulted[hw_points - 1].green;
+       rgb_resulted[hw_points].blue = rgb_resulted[hw_points - 1].blue;
+
        // All 3 color channels have same x
        corner_points[0].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
                                             dc_fixpt_from_int(region_start));
@@ -259,15 +265,18 @@ bool cm3_helper_translate_curve_to_hw_format(
 
        rgb = rgb_resulted;
        rgb_plus_1 = rgb_resulted + 1;
+       rgb_minus_1 = rgb;
 
        i = 1;
        while (i != hw_points + 1) {
-               if (dc_fixpt_lt(rgb_plus_1->red, rgb->red))
-                       rgb_plus_1->red = rgb->red;
-               if (dc_fixpt_lt(rgb_plus_1->green, rgb->green))
-                       rgb_plus_1->green = rgb->green;
-               if (dc_fixpt_lt(rgb_plus_1->blue, rgb->blue))
-                       rgb_plus_1->blue = rgb->blue;
+               if (i >= hw_points - 1) {
+                       if (dc_fixpt_lt(rgb_plus_1->red, rgb->red))
+                               rgb_plus_1->red = dc_fixpt_add(rgb->red, rgb_minus_1->delta_red);
+                       if (dc_fixpt_lt(rgb_plus_1->green, rgb->green))
+                               rgb_plus_1->green = dc_fixpt_add(rgb->green, rgb_minus_1->delta_green);
+                       if (dc_fixpt_lt(rgb_plus_1->blue, rgb->blue))
+                               rgb_plus_1->blue = dc_fixpt_add(rgb->blue, rgb_minus_1->delta_blue);
+               }
 
                rgb->delta_red   = dc_fixpt_sub(rgb_plus_1->red,   rgb->red);
                rgb->delta_green = dc_fixpt_sub(rgb_plus_1->green, rgb->green);
@@ -283,6 +292,7 @@ bool cm3_helper_translate_curve_to_hw_format(
                }
 
                ++rgb_plus_1;
+               rgb_minus_1 = rgb;
                ++rgb;
                ++i;
        }
index 88ffa9f..f246125 100644 (file)
@@ -511,6 +511,7 @@ static struct hubp_funcs dcn30_hubp_funcs = {
        .hubp_init = hubp3_init,
        .hubp_in_blank = hubp1_in_blank,
        .hubp_soft_reset = hubp1_soft_reset,
+       .hubp_set_flip_int = hubp1_set_flip_int,
 };
 
 bool hubp3_construct(
index 8d0f663..fb7f1de 100644 (file)
@@ -2508,6 +2508,19 @@ static const struct resource_funcs dcn30_res_pool_funcs = {
        .patch_unknown_plane_state = dcn20_patch_unknown_plane_state,
 };
 
+#define CTX ctx
+
+#define REG(reg_name) \
+       (DCN_BASE.instance[0].segment[mm ## reg_name ## _BASE_IDX] + mm ## reg_name)
+
+static uint32_t read_pipe_fuses(struct dc_context *ctx)
+{
+       uint32_t value = REG_READ(CC_DC_PIPE_DIS);
+       /* Support for max 6 pipes */
+       value = value & 0x3f;
+       return value;
+}
+
 static bool dcn30_resource_construct(
        uint8_t num_virtual_links,
        struct dc *dc,
@@ -2517,6 +2530,15 @@ static bool dcn30_resource_construct(
        struct dc_context *ctx = dc->ctx;
        struct irq_service_init_data init_data;
        struct ddc_service_init_data ddc_init_data;
+       uint32_t pipe_fuses = read_pipe_fuses(ctx);
+       uint32_t num_pipes = 0;
+
+       if (!(pipe_fuses == 0 || pipe_fuses == 0x3e)) {
+               BREAK_TO_DEBUGGER();
+               dm_error("DC: Unexpected fuse recipe for navi2x !\n");
+               /* fault to single pipe */
+               pipe_fuses = 0x3e;
+       }
 
        DC_FP_START();
 
@@ -2650,6 +2672,15 @@ static bool dcn30_resource_construct(
        /* PP Lib and SMU interfaces */
        init_soc_bounding_box(dc, pool);
 
+       num_pipes = dcn3_0_ip.max_num_dpp;
+
+       for (i = 0; i < dcn3_0_ip.max_num_dpp; i++)
+               if (pipe_fuses & 1 << i)
+                       num_pipes--;
+
+       dcn3_0_ip.max_num_dpp = num_pipes;
+       dcn3_0_ip.max_num_otg = num_pipes;
+
        dml_init_instance(&dc->dml, &dcn3_0_soc, &dcn3_0_ip, DML_PROJECT_DCN30);
 
        /* IRQ */
index 5d4b2c6..c494235 100644 (file)
@@ -1619,12 +1619,106 @@ static void dcn301_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *b
        dml_init_instance(&dc->dml, &dcn3_01_soc, &dcn3_01_ip, DML_PROJECT_DCN30);
 }
 
+static void calculate_wm_set_for_vlevel(
+               int vlevel,
+               struct wm_range_table_entry *table_entry,
+               struct dcn_watermarks *wm_set,
+               struct display_mode_lib *dml,
+               display_e2e_pipe_params_st *pipes,
+               int pipe_cnt)
+{
+       double dram_clock_change_latency_cached = dml->soc.dram_clock_change_latency_us;
+
+       ASSERT(vlevel < dml->soc.num_states);
+       /* only pipe 0 is read for voltage and dcf/soc clocks */
+       pipes[0].clks_cfg.voltage = vlevel;
+       pipes[0].clks_cfg.dcfclk_mhz = dml->soc.clock_limits[vlevel].dcfclk_mhz;
+       pipes[0].clks_cfg.socclk_mhz = dml->soc.clock_limits[vlevel].socclk_mhz;
+
+       dml->soc.dram_clock_change_latency_us = table_entry->pstate_latency_us;
+       dml->soc.sr_exit_time_us = table_entry->sr_exit_time_us;
+       dml->soc.sr_enter_plus_exit_time_us = table_entry->sr_enter_plus_exit_time_us;
+
+       wm_set->urgent_ns = get_wm_urgent(dml, pipes, pipe_cnt) * 1000;
+       wm_set->cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(dml, pipes, pipe_cnt) * 1000;
+       wm_set->cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(dml, pipes, pipe_cnt) * 1000;
+       wm_set->cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(dml, pipes, pipe_cnt) * 1000;
+       wm_set->pte_meta_urgent_ns = get_wm_memory_trip(dml, pipes, pipe_cnt) * 1000;
+       wm_set->frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(dml, pipes, pipe_cnt) * 1000;
+       wm_set->frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(dml, pipes, pipe_cnt) * 1000;
+       wm_set->urgent_latency_ns = get_urgent_latency(dml, pipes, pipe_cnt) * 1000;
+       dml->soc.dram_clock_change_latency_us = dram_clock_change_latency_cached;
+
+}
+
+static void dcn301_calculate_wm_and_dlg(
+               struct dc *dc, struct dc_state *context,
+               display_e2e_pipe_params_st *pipes,
+               int pipe_cnt,
+               int vlevel_req)
+{
+       int i, pipe_idx;
+       int vlevel, vlevel_max;
+       struct wm_range_table_entry *table_entry;
+       struct clk_bw_params *bw_params = dc->clk_mgr->bw_params;
+
+       ASSERT(bw_params);
+
+       vlevel_max = bw_params->clk_table.num_entries - 1;
+
+       /* WM Set D */
+       table_entry = &bw_params->wm_table.entries[WM_D];
+       if (table_entry->wm_type == WM_TYPE_RETRAINING)
+               vlevel = 0;
+       else
+               vlevel = vlevel_max;
+       calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.d,
+                                               &context->bw_ctx.dml, pipes, pipe_cnt);
+       /* WM Set C */
+       table_entry = &bw_params->wm_table.entries[WM_C];
+       vlevel = min(max(vlevel_req, 2), vlevel_max);
+       calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.c,
+                                               &context->bw_ctx.dml, pipes, pipe_cnt);
+       /* WM Set B */
+       table_entry = &bw_params->wm_table.entries[WM_B];
+       vlevel = min(max(vlevel_req, 1), vlevel_max);
+       calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.b,
+                                               &context->bw_ctx.dml, pipes, pipe_cnt);
+
+       /* WM Set A */
+       table_entry = &bw_params->wm_table.entries[WM_A];
+       vlevel = min(vlevel_req, vlevel_max);
+       calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.a,
+                                               &context->bw_ctx.dml, pipes, pipe_cnt);
+
+       for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
+               if (!context->res_ctx.pipe_ctx[i].stream)
+                       continue;
+
+               pipes[pipe_idx].clks_cfg.dispclk_mhz = get_dispclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt);
+               pipes[pipe_idx].clks_cfg.dppclk_mhz = get_dppclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx);
+
+               if (dc->config.forced_clocks) {
+                       pipes[pipe_idx].clks_cfg.dispclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dispclk_mhz;
+                       pipes[pipe_idx].clks_cfg.dppclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dppclk_mhz;
+               }
+               if (dc->debug.min_disp_clk_khz > pipes[pipe_idx].clks_cfg.dispclk_mhz * 1000)
+                       pipes[pipe_idx].clks_cfg.dispclk_mhz = dc->debug.min_disp_clk_khz / 1000.0;
+               if (dc->debug.min_dpp_clk_khz > pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000)
+                       pipes[pipe_idx].clks_cfg.dppclk_mhz = dc->debug.min_dpp_clk_khz / 1000.0;
+
+               pipe_idx++;
+       }
+
+       dcn20_calculate_dlg_params(dc, context, pipes, pipe_cnt, vlevel);
+}
+
 static struct resource_funcs dcn301_res_pool_funcs = {
        .destroy = dcn301_destroy_resource_pool,
        .link_enc_create = dcn301_link_encoder_create,
        .panel_cntl_create = dcn301_panel_cntl_create,
        .validate_bandwidth = dcn30_validate_bandwidth,
-       .calculate_wm_and_dlg = dcn30_calculate_wm_and_dlg,
+       .calculate_wm_and_dlg = dcn301_calculate_wm_and_dlg,
        .populate_dml_pipes = dcn30_populate_dml_pipes_from_context,
        .acquire_idle_pipe_for_layer = dcn20_acquire_idle_pipe_for_layer,
        .add_stream_to_ctx = dcn30_add_stream_to_ctx,
index 22f3f64..346dcd8 100644 (file)
@@ -191,6 +191,8 @@ struct hubp_funcs {
        bool (*hubp_in_blank)(struct hubp *hubp);
        void (*hubp_soft_reset)(struct hubp *hubp, bool reset);
 
+       void (*hubp_set_flip_int)(struct hubp *hubp);
+
 };
 
 #endif
index c57dc9a..a2681fe 100644 (file)
@@ -5216,10 +5216,10 @@ static int smu7_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr,
                for (j = 0; j < dep_sclk_table->count; j++) {
                        valid_entry = false;
                        for (k = 0; k < watermarks->num_wm_sets; k++) {
-                               if (dep_sclk_table->entries[i].clk / 10 >= watermarks->wm_clk_ranges[k].wm_min_eng_clk_in_khz &&
-                                   dep_sclk_table->entries[i].clk / 10 < watermarks->wm_clk_ranges[k].wm_max_eng_clk_in_khz &&
-                                   dep_mclk_table->entries[i].clk / 10 >= watermarks->wm_clk_ranges[k].wm_min_mem_clk_in_khz &&
-                                   dep_mclk_table->entries[i].clk / 10 < watermarks->wm_clk_ranges[k].wm_max_mem_clk_in_khz) {
+                               if (dep_sclk_table->entries[i].clk >= watermarks->wm_clk_ranges[k].wm_min_eng_clk_in_khz / 10 &&
+                                   dep_sclk_table->entries[i].clk < watermarks->wm_clk_ranges[k].wm_max_eng_clk_in_khz / 10 &&
+                                   dep_mclk_table->entries[i].clk >= watermarks->wm_clk_ranges[k].wm_min_mem_clk_in_khz / 10 &&
+                                   dep_mclk_table->entries[i].clk < watermarks->wm_clk_ranges[k].wm_max_mem_clk_in_khz / 10) {
                                        valid_entry = true;
                                        table->DisplayWatermark[i][j] = watermarks->wm_clk_ranges[k].wm_set_id;
                                        break;
index 29c9964..22b636e 100644 (file)
@@ -1505,6 +1505,48 @@ static int vega10_populate_single_lclk_level(struct pp_hwmgr *hwmgr,
        return 0;
 }
 
+static int vega10_override_pcie_parameters(struct pp_hwmgr *hwmgr)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev);
+       struct vega10_hwmgr *data =
+                       (struct vega10_hwmgr *)(hwmgr->backend);
+       uint32_t pcie_gen = 0, pcie_width = 0;
+       PPTable_t *pp_table = &(data->smc_state_table.pp_table);
+       int i;
+
+       if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN4)
+               pcie_gen = 3;
+       else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
+               pcie_gen = 2;
+       else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2)
+               pcie_gen = 1;
+       else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1)
+               pcie_gen = 0;
+
+       if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X16)
+               pcie_width = 6;
+       else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X12)
+               pcie_width = 5;
+       else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X8)
+               pcie_width = 4;
+       else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X4)
+               pcie_width = 3;
+       else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X2)
+               pcie_width = 2;
+       else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X1)
+               pcie_width = 1;
+
+       for (i = 0; i < NUM_LINK_LEVELS; i++) {
+               if (pp_table->PcieGenSpeed[i] > pcie_gen)
+                       pp_table->PcieGenSpeed[i] = pcie_gen;
+
+               if (pp_table->PcieLaneCount[i] > pcie_width)
+                       pp_table->PcieLaneCount[i] = pcie_width;
+       }
+
+       return 0;
+}
+
 static int vega10_populate_smc_link_levels(struct pp_hwmgr *hwmgr)
 {
        int result = -1;
@@ -2556,6 +2598,11 @@ static int vega10_init_smc_table(struct pp_hwmgr *hwmgr)
                        "Failed to initialize Link Level!",
                        return result);
 
+       result = vega10_override_pcie_parameters(hwmgr);
+       PP_ASSERT_WITH_CODE(!result,
+                       "Failed to override pcie parameters!",
+                       return result);
+
        result = vega10_populate_all_graphic_levels(hwmgr);
        PP_ASSERT_WITH_CODE(!result,
                        "Failed to initialize Graphics Level!",
@@ -2922,6 +2969,7 @@ static int vega10_start_dpm(struct pp_hwmgr *hwmgr, uint32_t bitmap)
        return 0;
 }
 
+
 static int vega10_enable_disable_PCC_limit_feature(struct pp_hwmgr *hwmgr, bool enable)
 {
        struct vega10_hwmgr *data = hwmgr->backend;
index c075302..43e01d8 100644 (file)
@@ -481,6 +481,67 @@ static void vega12_init_dpm_state(struct vega12_dpm_state *dpm_state)
        dpm_state->hard_max_level = 0xffff;
 }
 
+static int vega12_override_pcie_parameters(struct pp_hwmgr *hwmgr)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev);
+       struct vega12_hwmgr *data =
+                       (struct vega12_hwmgr *)(hwmgr->backend);
+       uint32_t pcie_gen = 0, pcie_width = 0, smu_pcie_arg, pcie_gen_arg, pcie_width_arg;
+       PPTable_t *pp_table = &(data->smc_state_table.pp_table);
+       int i;
+       int ret;
+
+       if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN4)
+               pcie_gen = 3;
+       else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
+               pcie_gen = 2;
+       else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2)
+               pcie_gen = 1;
+       else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1)
+               pcie_gen = 0;
+
+       if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X16)
+               pcie_width = 6;
+       else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X12)
+               pcie_width = 5;
+       else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X8)
+               pcie_width = 4;
+       else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X4)
+               pcie_width = 3;
+       else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X2)
+               pcie_width = 2;
+       else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X1)
+               pcie_width = 1;
+
+       /* Bit 31:16: LCLK DPM level. 0 is DPM0, and 1 is DPM1
+        * Bit 15:8:  PCIE GEN, 0 to 3 corresponds to GEN1 to GEN4
+        * Bit 7:0:   PCIE lane width, 1 to 7 corresponds is x1 to x32
+        */
+       for (i = 0; i < NUM_LINK_LEVELS; i++) {
+               pcie_gen_arg = (pp_table->PcieGenSpeed[i] > pcie_gen) ? pcie_gen :
+                       pp_table->PcieGenSpeed[i];
+               pcie_width_arg = (pp_table->PcieLaneCount[i] > pcie_width) ? pcie_width :
+                       pp_table->PcieLaneCount[i];
+
+               if (pcie_gen_arg != pp_table->PcieGenSpeed[i] || pcie_width_arg !=
+                   pp_table->PcieLaneCount[i]) {
+                       smu_pcie_arg = (i << 16) | (pcie_gen_arg << 8) | pcie_width_arg;
+                       ret = smum_send_msg_to_smc_with_parameter(hwmgr,
+                               PPSMC_MSG_OverridePcieParameters, smu_pcie_arg,
+                               NULL);
+                       PP_ASSERT_WITH_CODE(!ret,
+                               "[OverridePcieParameters] Attempt to override pcie params failed!",
+                               return ret);
+               }
+
+               /* update the pptable */
+               pp_table->PcieGenSpeed[i] = pcie_gen_arg;
+               pp_table->PcieLaneCount[i] = pcie_width_arg;
+       }
+
+       return 0;
+}
+
 static int vega12_get_number_of_dpm_level(struct pp_hwmgr *hwmgr,
                PPCLK_e clk_id, uint32_t *num_of_levels)
 {
@@ -968,6 +1029,11 @@ static int vega12_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
                        "Failed to enable all smu features!",
                        return result);
 
+       result = vega12_override_pcie_parameters(hwmgr);
+       PP_ASSERT_WITH_CODE(!result,
+                       "[EnableDPMTasks] Failed to override pcie parameters!",
+                       return result);
+
        tmp_result = vega12_power_control_set_level(hwmgr);
        PP_ASSERT_WITH_CODE(!tmp_result,
                        "Failed to power control set level!",
index 87811b0..f19964c 100644 (file)
@@ -831,7 +831,9 @@ static int vega20_override_pcie_parameters(struct pp_hwmgr *hwmgr)
        struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev);
        struct vega20_hwmgr *data =
                        (struct vega20_hwmgr *)(hwmgr->backend);
-       uint32_t pcie_gen = 0, pcie_width = 0, smu_pcie_arg;
+       uint32_t pcie_gen = 0, pcie_width = 0, smu_pcie_arg, pcie_gen_arg, pcie_width_arg;
+       PPTable_t *pp_table = &(data->smc_state_table.pp_table);
+       int i;
        int ret;
 
        if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN4)
@@ -860,17 +862,27 @@ static int vega20_override_pcie_parameters(struct pp_hwmgr *hwmgr)
         * Bit 15:8:  PCIE GEN, 0 to 3 corresponds to GEN1 to GEN4
         * Bit 7:0:   PCIE lane width, 1 to 7 corresponds is x1 to x32
         */
-       smu_pcie_arg = (1 << 16) | (pcie_gen << 8) | pcie_width;
-       ret = smum_send_msg_to_smc_with_parameter(hwmgr,
-                       PPSMC_MSG_OverridePcieParameters, smu_pcie_arg,
-                       NULL);
-       PP_ASSERT_WITH_CODE(!ret,
-               "[OverridePcieParameters] Attempt to override pcie params failed!",
-               return ret);
+       for (i = 0; i < NUM_LINK_LEVELS; i++) {
+               pcie_gen_arg = (pp_table->PcieGenSpeed[i] > pcie_gen) ? pcie_gen :
+                       pp_table->PcieGenSpeed[i];
+               pcie_width_arg = (pp_table->PcieLaneCount[i] > pcie_width) ? pcie_width :
+                       pp_table->PcieLaneCount[i];
+
+               if (pcie_gen_arg != pp_table->PcieGenSpeed[i] || pcie_width_arg !=
+                   pp_table->PcieLaneCount[i]) {
+                       smu_pcie_arg = (i << 16) | (pcie_gen_arg << 8) | pcie_width_arg;
+                       ret = smum_send_msg_to_smc_with_parameter(hwmgr,
+                               PPSMC_MSG_OverridePcieParameters, smu_pcie_arg,
+                               NULL);
+                       PP_ASSERT_WITH_CODE(!ret,
+                               "[OverridePcieParameters] Attempt to override pcie params failed!",
+                               return ret);
+               }
 
-       data->pcie_parameters_override = true;
-       data->pcie_gen_level1 = pcie_gen;
-       data->pcie_width_level1 = pcie_width;
+               /* update the pptable */
+               pp_table->PcieGenSpeed[i] = pcie_gen_arg;
+               pp_table->PcieLaneCount[i] = pcie_width_arg;
+       }
 
        return 0;
 }
@@ -3319,9 +3331,7 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
                        data->od8_settings.od8_settings_array;
        OverDriveTable_t *od_table =
                        &(data->smc_state_table.overdrive_table);
-       struct phm_ppt_v3_information *pptable_information =
-               (struct phm_ppt_v3_information *)hwmgr->pptable;
-       PPTable_t *pptable = (PPTable_t *)pptable_information->smc_pptable;
+       PPTable_t *pptable = &(data->smc_state_table.pp_table);
        struct pp_clock_levels_with_latency clocks;
        struct vega20_single_dpm_table *fclk_dpm_table =
                        &(data->dpm_table.fclk_table);
@@ -3420,13 +3430,9 @@ static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr,
                current_lane_width =
                        vega20_get_current_pcie_link_width_level(hwmgr);
                for (i = 0; i < NUM_LINK_LEVELS; i++) {
-                       if (i == 1 && data->pcie_parameters_override) {
-                               gen_speed = data->pcie_gen_level1;
-                               lane_width = data->pcie_width_level1;
-                       } else {
-                               gen_speed = pptable->PcieGenSpeed[i];
-                               lane_width = pptable->PcieLaneCount[i];
-                       }
+                       gen_speed = pptable->PcieGenSpeed[i];
+                       lane_width = pptable->PcieLaneCount[i];
+
                        size += sprintf(buf + size, "%d: %s %s %dMhz %s\n", i,
                                        (gen_speed == 0) ? "2.5GT/s," :
                                        (gen_speed == 1) ? "5.0GT/s," :
index b9a6167..f6baa20 100644 (file)
@@ -2048,7 +2048,7 @@ static void drm_fbdev_cleanup(struct drm_fb_helper *fb_helper)
 
        if (shadow)
                vfree(shadow);
-       else
+       else if (fb_helper->buffer)
                drm_client_buffer_vunmap(fb_helper->buffer);
 
        drm_client_framebuffer_delete(fb_helper->buffer);
index 9825c37..6d625ce 100644 (file)
@@ -357,13 +357,14 @@ static void drm_gem_shmem_vunmap_locked(struct drm_gem_shmem_object *shmem,
        if (--shmem->vmap_use_count > 0)
                return;
 
-       if (obj->import_attach)
+       if (obj->import_attach) {
                dma_buf_vunmap(obj->import_attach->dmabuf, map);
-       else
+       } else {
                vunmap(shmem->vaddr);
+               drm_gem_shmem_put_pages(shmem);
+       }
 
        shmem->vaddr = NULL;
-       drm_gem_shmem_put_pages(shmem);
 }
 
 /*
@@ -525,14 +526,28 @@ static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)
        struct drm_gem_object *obj = vma->vm_private_data;
        struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
        loff_t num_pages = obj->size >> PAGE_SHIFT;
+       vm_fault_t ret;
        struct page *page;
+       pgoff_t page_offset;
 
-       if (vmf->pgoff >= num_pages || WARN_ON_ONCE(!shmem->pages))
-               return VM_FAULT_SIGBUS;
+       /* We don't use vmf->pgoff since that has the fake offset */
+       page_offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT;
 
-       page = shmem->pages[vmf->pgoff];
+       mutex_lock(&shmem->pages_lock);
 
-       return vmf_insert_page(vma, vmf->address, page);
+       if (page_offset >= num_pages ||
+           WARN_ON_ONCE(!shmem->pages) ||
+           shmem->madv < 0) {
+               ret = VM_FAULT_SIGBUS;
+       } else {
+               page = shmem->pages[page_offset];
+
+               ret = vmf_insert_page(vma, vmf->address, page);
+       }
+
+       mutex_unlock(&shmem->pages_lock);
+
+       return ret;
 }
 
 static void drm_gem_shmem_vm_open(struct vm_area_struct *vma)
@@ -581,9 +596,6 @@ int drm_gem_shmem_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
        struct drm_gem_shmem_object *shmem;
        int ret;
 
-       /* Remove the fake offset */
-       vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node);
-
        if (obj->import_attach) {
                /* Drop the reference drm_gem_mmap_obj() acquired.*/
                drm_gem_object_put(obj);
index f86448a..dc734d4 100644 (file)
@@ -99,6 +99,8 @@ static int compat_drm_version(struct file *file, unsigned int cmd,
        if (copy_from_user(&v32, (void __user *)arg, sizeof(v32)))
                return -EFAULT;
 
+       memset(&v, 0, sizeof(v));
+
        v = (struct drm_version) {
                .name_len = v32.name_len,
                .name = compat_ptr(v32.name),
@@ -137,6 +139,9 @@ static int compat_drm_getunique(struct file *file, unsigned int cmd,
 
        if (copy_from_user(&uq32, (void __user *)arg, sizeof(uq32)))
                return -EFAULT;
+
+       memset(&uq, 0, sizeof(uq));
+
        uq = (struct drm_unique){
                .unique_len = uq32.unique_len,
                .unique = compat_ptr(uq32.unique),
@@ -265,6 +270,8 @@ static int compat_drm_getclient(struct file *file, unsigned int cmd,
        if (copy_from_user(&c32, argp, sizeof(c32)))
                return -EFAULT;
 
+       memset(&client, 0, sizeof(client));
+
        client.idx = c32.idx;
 
        err = drm_ioctl_kernel(file, drm_getclient, &client, 0);
@@ -852,6 +859,8 @@ static int compat_drm_wait_vblank(struct file *file, unsigned int cmd,
        if (copy_from_user(&req32, argp, sizeof(req32)))
                return -EFAULT;
 
+       memset(&req, 0, sizeof(req));
+
        req.request.type = req32.request.type;
        req.request.sequence = req32.request.sequence;
        req.request.signal = req32.request.signal;
@@ -889,6 +898,8 @@ static int compat_drm_mode_addfb2(struct file *file, unsigned int cmd,
        struct drm_mode_fb_cmd2 req64;
        int err;
 
+       memset(&req64, 0, sizeof(req64));
+
        if (copy_from_user(&req64, argp,
                           offsetof(drm_mode_fb_cmd232_t, modifier)))
                return -EFAULT;
index fb1b1d0..9cf555d 100644 (file)
@@ -713,9 +713,12 @@ static int engine_setup_common(struct intel_engine_cs *engine)
                goto err_status;
        }
 
+       err = intel_engine_init_cmd_parser(engine);
+       if (err)
+               goto err_cmd_parser;
+
        intel_engine_init_active(engine, ENGINE_PHYSICAL);
        intel_engine_init_execlists(engine);
-       intel_engine_init_cmd_parser(engine);
        intel_engine_init__pm(engine);
        intel_engine_init_retire(engine);
 
@@ -732,6 +735,8 @@ static int engine_setup_common(struct intel_engine_cs *engine)
 
        return 0;
 
+err_cmd_parser:
+       intel_breadcrumbs_free(engine->breadcrumbs);
 err_status:
        cleanup_status_page(engine);
        return err;
index ced9a96..5f86f5b 100644 (file)
@@ -940,7 +940,7 @@ static void fini_hash_table(struct intel_engine_cs *engine)
  * struct intel_engine_cs based on whether the platform requires software
  * command parsing.
  */
-void intel_engine_init_cmd_parser(struct intel_engine_cs *engine)
+int intel_engine_init_cmd_parser(struct intel_engine_cs *engine)
 {
        const struct drm_i915_cmd_table *cmd_tables;
        int cmd_table_count;
@@ -948,7 +948,7 @@ void intel_engine_init_cmd_parser(struct intel_engine_cs *engine)
 
        if (!IS_GEN(engine->i915, 7) && !(IS_GEN(engine->i915, 9) &&
                                          engine->class == COPY_ENGINE_CLASS))
-               return;
+               return 0;
 
        switch (engine->class) {
        case RENDER_CLASS:
@@ -1013,19 +1013,19 @@ void intel_engine_init_cmd_parser(struct intel_engine_cs *engine)
                break;
        default:
                MISSING_CASE(engine->class);
-               return;
+               goto out;
        }
 
        if (!validate_cmds_sorted(engine, cmd_tables, cmd_table_count)) {
                drm_err(&engine->i915->drm,
                        "%s: command descriptions are not sorted\n",
                        engine->name);
-               return;
+               goto out;
        }
        if (!validate_regs_sorted(engine)) {
                drm_err(&engine->i915->drm,
                        "%s: registers are not sorted\n", engine->name);
-               return;
+               goto out;
        }
 
        ret = init_hash_table(engine, cmd_tables, cmd_table_count);
@@ -1033,10 +1033,17 @@ void intel_engine_init_cmd_parser(struct intel_engine_cs *engine)
                drm_err(&engine->i915->drm,
                        "%s: initialised failed!\n", engine->name);
                fini_hash_table(engine);
-               return;
+               goto out;
        }
 
        engine->flags |= I915_ENGINE_USING_CMD_PARSER;
+
+out:
+       if (intel_engine_requires_cmd_parser(engine) &&
+           !intel_engine_using_cmd_parser(engine))
+               return -EINVAL;
+
+       return 0;
 }
 
 /**
index 26d69d0..cb62ddb 100644 (file)
@@ -1952,7 +1952,7 @@ const char *i915_cache_level_str(struct drm_i915_private *i915, int type);
 
 /* i915_cmd_parser.c */
 int i915_cmd_parser_get_version(struct drm_i915_private *dev_priv);
-void intel_engine_init_cmd_parser(struct intel_engine_cs *engine);
+int intel_engine_init_cmd_parser(struct intel_engine_cs *engine);
 void intel_engine_cleanup_cmd_parser(struct intel_engine_cs *engine);
 int intel_engine_cmd_parser(struct intel_engine_cs *engine,
                            struct i915_vma *batch,
index 112ba5f..e62ad69 100644 (file)
@@ -603,7 +603,6 @@ static int append_oa_sample(struct i915_perf_stream *stream,
 {
        int report_size = stream->oa_buffer.format_size;
        struct drm_i915_perf_record_header header;
-       u32 sample_flags = stream->sample_flags;
 
        header.type = DRM_I915_PERF_RECORD_SAMPLE;
        header.pad = 0;
@@ -617,10 +616,8 @@ static int append_oa_sample(struct i915_perf_stream *stream,
                return -EFAULT;
        buf += sizeof(header);
 
-       if (sample_flags & SAMPLE_OA_REPORT) {
-               if (copy_to_user(buf, report, report_size))
-                       return -EFAULT;
-       }
+       if (copy_to_user(buf, report, report_size))
+               return -EFAULT;
 
        (*offset) += header.size;
 
@@ -2682,7 +2679,7 @@ static void i915_oa_stream_enable(struct i915_perf_stream *stream)
 
        stream->perf->ops.oa_enable(stream);
 
-       if (stream->periodic)
+       if (stream->sample_flags & SAMPLE_OA_REPORT)
                hrtimer_start(&stream->poll_check_timer,
                              ns_to_ktime(stream->poll_oa_period),
                              HRTIMER_MODE_REL_PINNED);
@@ -2745,7 +2742,7 @@ static void i915_oa_stream_disable(struct i915_perf_stream *stream)
 {
        stream->perf->ops.oa_disable(stream);
 
-       if (stream->periodic)
+       if (stream->sample_flags & SAMPLE_OA_REPORT)
                hrtimer_cancel(&stream->poll_check_timer);
 }
 
@@ -3028,7 +3025,7 @@ static ssize_t i915_perf_read(struct file *file,
         * disabled stream as an error. In particular it might otherwise lead
         * to a deadlock for blocking file descriptors...
         */
-       if (!stream->enabled)
+       if (!stream->enabled || !(stream->sample_flags & SAMPLE_OA_REPORT))
                return -EIO;
 
        if (!(file->f_flags & O_NONBLOCK)) {
index 7146cd0..aaf1f00 100644 (file)
@@ -3316,7 +3316,18 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
 
 #define ILK_DISPLAY_CHICKEN1   _MMIO(0x42000)
 #define   ILK_FBCQ_DIS         (1 << 22)
-#define          ILK_PABSTRETCH_DIS    (1 << 21)
+#define   ILK_PABSTRETCH_DIS   REG_BIT(21)
+#define   ILK_SABSTRETCH_DIS   REG_BIT(20)
+#define   IVB_PRI_STRETCH_MAX_MASK     REG_GENMASK(21, 20)
+#define   IVB_PRI_STRETCH_MAX_X8       REG_FIELD_PREP(IVB_PRI_STRETCH_MAX_MASK, 0)
+#define   IVB_PRI_STRETCH_MAX_X4       REG_FIELD_PREP(IVB_PRI_STRETCH_MAX_MASK, 1)
+#define   IVB_PRI_STRETCH_MAX_X2       REG_FIELD_PREP(IVB_PRI_STRETCH_MAX_MASK, 2)
+#define   IVB_PRI_STRETCH_MAX_X1       REG_FIELD_PREP(IVB_PRI_STRETCH_MAX_MASK, 3)
+#define   IVB_SPR_STRETCH_MAX_MASK     REG_GENMASK(19, 18)
+#define   IVB_SPR_STRETCH_MAX_X8       REG_FIELD_PREP(IVB_SPR_STRETCH_MAX_MASK, 0)
+#define   IVB_SPR_STRETCH_MAX_X4       REG_FIELD_PREP(IVB_SPR_STRETCH_MAX_MASK, 1)
+#define   IVB_SPR_STRETCH_MAX_X2       REG_FIELD_PREP(IVB_SPR_STRETCH_MAX_MASK, 2)
+#define   IVB_SPR_STRETCH_MAX_X1       REG_FIELD_PREP(IVB_SPR_STRETCH_MAX_MASK, 3)
 
 
 /*
@@ -8039,6 +8050,16 @@ enum {
 
 #define _CHICKEN_PIPESL_1_A    0x420b0
 #define _CHICKEN_PIPESL_1_B    0x420b4
+#define  HSW_PRI_STRETCH_MAX_MASK      REG_GENMASK(28, 27)
+#define  HSW_PRI_STRETCH_MAX_X8                REG_FIELD_PREP(HSW_PRI_STRETCH_MAX_MASK, 0)
+#define  HSW_PRI_STRETCH_MAX_X4                REG_FIELD_PREP(HSW_PRI_STRETCH_MAX_MASK, 1)
+#define  HSW_PRI_STRETCH_MAX_X2                REG_FIELD_PREP(HSW_PRI_STRETCH_MAX_MASK, 2)
+#define  HSW_PRI_STRETCH_MAX_X1                REG_FIELD_PREP(HSW_PRI_STRETCH_MAX_MASK, 3)
+#define  HSW_SPR_STRETCH_MAX_MASK      REG_GENMASK(26, 25)
+#define  HSW_SPR_STRETCH_MAX_X8                REG_FIELD_PREP(HSW_SPR_STRETCH_MAX_MASK, 0)
+#define  HSW_SPR_STRETCH_MAX_X4                REG_FIELD_PREP(HSW_SPR_STRETCH_MAX_MASK, 1)
+#define  HSW_SPR_STRETCH_MAX_X2                REG_FIELD_PREP(HSW_SPR_STRETCH_MAX_MASK, 2)
+#define  HSW_SPR_STRETCH_MAX_X1                REG_FIELD_PREP(HSW_SPR_STRETCH_MAX_MASK, 3)
 #define  HSW_FBCQ_DIS                  (1 << 22)
 #define  BDW_DPRS_MASK_VBLANK_SRD      (1 << 0)
 #define CHICKEN_PIPESL_1(pipe) _MMIO_PIPE(pipe, _CHICKEN_PIPESL_1_A, _CHICKEN_PIPESL_1_B)
index 0c3e63f..97b57ac 100644 (file)
@@ -7245,11 +7245,16 @@ static void bdw_init_clock_gating(struct drm_i915_private *dev_priv)
        intel_uncore_write(&dev_priv->uncore, CHICKEN_PAR1_1,
                   intel_uncore_read(&dev_priv->uncore, CHICKEN_PAR1_1) | DPA_MASK_VBLANK_SRD);
 
-       /* WaPsrDPRSUnmaskVBlankInSRD:bdw */
        for_each_pipe(dev_priv, pipe) {
+               /* WaPsrDPRSUnmaskVBlankInSRD:bdw */
                intel_uncore_write(&dev_priv->uncore, CHICKEN_PIPESL_1(pipe),
                           intel_uncore_read(&dev_priv->uncore, CHICKEN_PIPESL_1(pipe)) |
                           BDW_DPRS_MASK_VBLANK_SRD);
+
+               /* Undocumented but fixes async flip + VT-d corruption */
+               if (intel_vtd_active())
+                       intel_uncore_rmw(&dev_priv->uncore, CHICKEN_PIPESL_1(pipe),
+                                        HSW_PRI_STRETCH_MAX_MASK, HSW_PRI_STRETCH_MAX_X1);
        }
 
        /* WaVSRefCountFullforceMissDisable:bdw */
@@ -7285,11 +7290,20 @@ static void bdw_init_clock_gating(struct drm_i915_private *dev_priv)
 
 static void hsw_init_clock_gating(struct drm_i915_private *dev_priv)
 {
+       enum pipe pipe;
+
        /* WaFbcAsynchFlipDisableFbcQueue:hsw,bdw */
        intel_uncore_write(&dev_priv->uncore, CHICKEN_PIPESL_1(PIPE_A),
                   intel_uncore_read(&dev_priv->uncore, CHICKEN_PIPESL_1(PIPE_A)) |
                   HSW_FBCQ_DIS);
 
+       for_each_pipe(dev_priv, pipe) {
+               /* Undocumented but fixes async flip + VT-d corruption */
+               if (intel_vtd_active())
+                       intel_uncore_rmw(&dev_priv->uncore, CHICKEN_PIPESL_1(pipe),
+                                        HSW_PRI_STRETCH_MAX_MASK, HSW_PRI_STRETCH_MAX_X1);
+       }
+
        /* This is required by WaCatErrorRejectionIssue:hsw */
        intel_uncore_write(&dev_priv->uncore, GEN7_SQ_CHICKEN_MBCUNIT_CONFIG,
                   intel_uncore_read(&dev_priv->uncore, GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) |
index 42c5d32..453d8b4 100644 (file)
@@ -482,6 +482,16 @@ static int meson_probe_remote(struct platform_device *pdev,
        return count;
 }
 
+static void meson_drv_shutdown(struct platform_device *pdev)
+{
+       struct meson_drm *priv = dev_get_drvdata(&pdev->dev);
+       struct drm_device *drm = priv->drm;
+
+       DRM_DEBUG_DRIVER("\n");
+       drm_kms_helper_poll_fini(drm);
+       drm_atomic_helper_shutdown(drm);
+}
+
 static int meson_drv_probe(struct platform_device *pdev)
 {
        struct component_match *match = NULL;
@@ -553,6 +563,7 @@ static const struct dev_pm_ops meson_drv_pm_ops = {
 
 static struct platform_driver meson_drm_platform_driver = {
        .probe      = meson_drv_probe,
+       .shutdown   = meson_drv_shutdown,
        .driver     = {
                .name   = "meson-drm",
                .of_match_table = dt_match,
index 2375711..f2720a0 100644 (file)
@@ -551,12 +551,17 @@ nouveau_bo_sync_for_device(struct nouveau_bo *nvbo)
 
        if (!ttm_dma)
                return;
+       if (!ttm_dma->pages) {
+               NV_DEBUG(drm, "ttm_dma 0x%p: pages NULL\n", ttm_dma);
+               return;
+       }
 
        /* Don't waste time looping if the object is coherent */
        if (nvbo->force_coherent)
                return;
 
-       for (i = 0; i < ttm_dma->num_pages; ++i) {
+       i = 0;
+       while (i < ttm_dma->num_pages) {
                struct page *p = ttm_dma->pages[i];
                size_t num_pages = 1;
 
@@ -582,12 +587,17 @@ nouveau_bo_sync_for_cpu(struct nouveau_bo *nvbo)
 
        if (!ttm_dma)
                return;
+       if (!ttm_dma->pages) {
+               NV_DEBUG(drm, "ttm_dma 0x%p: pages NULL\n", ttm_dma);
+               return;
+       }
 
        /* Don't waste time looping if the object is coherent */
        if (nvbo->force_coherent)
                return;
 
-       for (i = 0; i < ttm_dma->num_pages; ++i) {
+       i = 0;
+       while (i < ttm_dma->num_pages) {
                struct page *p = ttm_dma->pages[i];
                size_t num_pages = 1;
 
index 8e11612..b31d750 100644 (file)
@@ -2149,11 +2149,12 @@ static int dsi_vc_send_short(struct dsi_data *dsi, int vc,
                             const struct mipi_dsi_msg *msg)
 {
        struct mipi_dsi_packet pkt;
+       int ret;
        u32 r;
 
-       r = mipi_dsi_create_packet(&pkt, msg);
-       if (r < 0)
-               return r;
+       ret = mipi_dsi_create_packet(&pkt, msg);
+       if (ret < 0)
+               return ret;
 
        WARN_ON(!dsi_bus_is_locked(dsi));
 
index 012bce0..10738e0 100644 (file)
@@ -328,6 +328,7 @@ static void qxl_crtc_update_monitors_config(struct drm_crtc *crtc,
 
        head.id = i;
        head.flags = 0;
+       head.surface_id = 0;
        oldcount = qdev->monitors_config->count;
        if (crtc->state->active) {
                struct drm_display_mode *mode = &crtc->mode;
index 0fcfc95..b372455 100644 (file)
@@ -321,7 +321,7 @@ int qxl_alloc_release_reserved(struct qxl_device *qdev, unsigned long size,
                                       int type, struct qxl_release **release,
                                       struct qxl_bo **rbo)
 {
-       struct qxl_bo *bo;
+       struct qxl_bo *bo, *free_bo = NULL;
        int idr_ret;
        int ret = 0;
        union qxl_release_info *info;
@@ -347,7 +347,7 @@ int qxl_alloc_release_reserved(struct qxl_device *qdev, unsigned long size,
 
        mutex_lock(&qdev->release_mutex);
        if (qdev->current_release_bo_offset[cur_idx] + 1 >= releases_per_bo[cur_idx]) {
-               qxl_bo_unref(&qdev->current_release_bo[cur_idx]);
+               free_bo = qdev->current_release_bo[cur_idx];
                qdev->current_release_bo_offset[cur_idx] = 0;
                qdev->current_release_bo[cur_idx] = NULL;
        }
@@ -355,6 +355,10 @@ int qxl_alloc_release_reserved(struct qxl_device *qdev, unsigned long size,
                ret = qxl_release_bo_alloc(qdev, &qdev->current_release_bo[cur_idx]);
                if (ret) {
                        mutex_unlock(&qdev->release_mutex);
+                       if (free_bo) {
+                               qxl_bo_unpin(free_bo);
+                               qxl_bo_unref(&free_bo);
+                       }
                        qxl_release_free(qdev, *release);
                        return ret;
                }
@@ -370,6 +374,10 @@ int qxl_alloc_release_reserved(struct qxl_device *qdev, unsigned long size,
                *rbo = bo;
 
        mutex_unlock(&qdev->release_mutex);
+       if (free_bo) {
+               qxl_bo_unpin(free_bo);
+               qxl_bo_unref(&free_bo);
+       }
 
        ret = qxl_release_list_add(*release, bo);
        qxl_bo_unref(&bo);
index f09989b..3effc8c 100644 (file)
@@ -574,6 +574,8 @@ struct radeon_gem {
        struct list_head        objects;
 };
 
+extern const struct drm_gem_object_funcs radeon_gem_object_funcs;
+
 int radeon_gem_init(struct radeon_device *rdev);
 void radeon_gem_fini(struct radeon_device *rdev);
 int radeon_gem_object_create(struct radeon_device *rdev, unsigned long size,
index 9418269..db14a82 100644 (file)
@@ -43,7 +43,7 @@ struct sg_table *radeon_gem_prime_get_sg_table(struct drm_gem_object *obj);
 int radeon_gem_prime_pin(struct drm_gem_object *obj);
 void radeon_gem_prime_unpin(struct drm_gem_object *obj);
 
-static const struct drm_gem_object_funcs radeon_gem_object_funcs;
+const struct drm_gem_object_funcs radeon_gem_object_funcs;
 
 static void radeon_gem_object_free(struct drm_gem_object *gobj)
 {
@@ -227,7 +227,7 @@ static int radeon_gem_handle_lockup(struct radeon_device *rdev, int r)
        return r;
 }
 
-static const struct drm_gem_object_funcs radeon_gem_object_funcs = {
+const struct drm_gem_object_funcs radeon_gem_object_funcs = {
        .free = radeon_gem_object_free,
        .open = radeon_gem_object_open,
        .close = radeon_gem_object_close,
index ab29eb9..42a8794 100644 (file)
@@ -56,6 +56,8 @@ struct drm_gem_object *radeon_gem_prime_import_sg_table(struct drm_device *dev,
        if (ret)
                return ERR_PTR(ret);
 
+       bo->tbo.base.funcs = &radeon_gem_object_funcs;
+
        mutex_lock(&rdev->gem.mutex);
        list_add_tail(&bo->list, &rdev->gem.objects);
        mutex_unlock(&rdev->gem.mutex);
index 33f65f4..23866a5 100644 (file)
@@ -83,6 +83,7 @@ MODULE_PARM_DESC(eco_mode, "Turn on Eco mode (less bright, more silent)");
 
 struct gm12u320_device {
        struct drm_device                dev;
+       struct device                   *dmadev;
        struct drm_simple_display_pipe   pipe;
        struct drm_connector             conn;
        unsigned char                   *cmd_buf;
@@ -601,6 +602,22 @@ static const uint64_t gm12u320_pipe_modifiers[] = {
        DRM_FORMAT_MOD_INVALID
 };
 
+/*
+ * FIXME: Dma-buf sharing requires DMA support by the importing device.
+ *        This function is a workaround to make USB devices work as well.
+ *        See todo.rst for how to fix the issue in the dma-buf framework.
+ */
+static struct drm_gem_object *gm12u320_gem_prime_import(struct drm_device *dev,
+                                                       struct dma_buf *dma_buf)
+{
+       struct gm12u320_device *gm12u320 = to_gm12u320(dev);
+
+       if (!gm12u320->dmadev)
+               return ERR_PTR(-ENODEV);
+
+       return drm_gem_prime_import_dev(dev, dma_buf, gm12u320->dmadev);
+}
+
 DEFINE_DRM_GEM_FOPS(gm12u320_fops);
 
 static const struct drm_driver gm12u320_drm_driver = {
@@ -614,6 +631,7 @@ static const struct drm_driver gm12u320_drm_driver = {
 
        .fops            = &gm12u320_fops,
        DRM_GEM_SHMEM_DRIVER_OPS,
+       .gem_prime_import = gm12u320_gem_prime_import,
 };
 
 static const struct drm_mode_config_funcs gm12u320_mode_config_funcs = {
@@ -640,15 +658,18 @@ static int gm12u320_usb_probe(struct usb_interface *interface,
                                      struct gm12u320_device, dev);
        if (IS_ERR(gm12u320))
                return PTR_ERR(gm12u320);
+       dev = &gm12u320->dev;
+
+       gm12u320->dmadev = usb_intf_get_dma_device(to_usb_interface(dev->dev));
+       if (!gm12u320->dmadev)
+               drm_warn(dev, "buffer sharing not supported"); /* not an error */
 
        INIT_DELAYED_WORK(&gm12u320->fb_update.work, gm12u320_fb_update_work);
        mutex_init(&gm12u320->fb_update.lock);
 
-       dev = &gm12u320->dev;
-
        ret = drmm_mode_config_init(dev);
        if (ret)
-               return ret;
+               goto err_put_device;
 
        dev->mode_config.min_width = GM12U320_USER_WIDTH;
        dev->mode_config.max_width = GM12U320_USER_WIDTH;
@@ -658,15 +679,15 @@ static int gm12u320_usb_probe(struct usb_interface *interface,
 
        ret = gm12u320_usb_alloc(gm12u320);
        if (ret)
-               return ret;
+               goto err_put_device;
 
        ret = gm12u320_set_ecomode(gm12u320);
        if (ret)
-               return ret;
+               goto err_put_device;
 
        ret = gm12u320_conn_init(gm12u320);
        if (ret)
-               return ret;
+               goto err_put_device;
 
        ret = drm_simple_display_pipe_init(&gm12u320->dev,
                                           &gm12u320->pipe,
@@ -676,24 +697,31 @@ static int gm12u320_usb_probe(struct usb_interface *interface,
                                           gm12u320_pipe_modifiers,
                                           &gm12u320->conn);
        if (ret)
-               return ret;
+               goto err_put_device;
 
        drm_mode_config_reset(dev);
 
        usb_set_intfdata(interface, dev);
        ret = drm_dev_register(dev, 0);
        if (ret)
-               return ret;
+               goto err_put_device;
 
        drm_fbdev_generic_setup(dev, 0);
 
        return 0;
+
+err_put_device:
+       put_device(gm12u320->dmadev);
+       return ret;
 }
 
 static void gm12u320_usb_disconnect(struct usb_interface *interface)
 {
        struct drm_device *dev = usb_get_intfdata(interface);
+       struct gm12u320_device *gm12u320 = to_gm12u320(dev);
 
+       put_device(gm12u320->dmadev);
+       gm12u320->dmadev = NULL;
        drm_dev_unplug(dev);
        drm_atomic_helper_shutdown(dev);
 }
index 20a2566..101a68d 100644 (file)
@@ -136,7 +136,8 @@ void ttm_bo_move_to_lru_tail(struct ttm_buffer_object *bo,
        struct ttm_bo_device *bdev = bo->bdev;
        struct ttm_resource_manager *man;
 
-       dma_resv_assert_held(bo->base.resv);
+       if (!bo->deleted)
+               dma_resv_assert_held(bo->base.resv);
 
        if (bo->pin_count) {
                ttm_bo_del_from_lru(bo);
@@ -508,8 +509,11 @@ static void ttm_bo_release(struct kref *kref)
                 * Make pinned bos immediately available to
                 * shrinkers, now that they are queued for
                 * destruction.
+                *
+                * FIXME: QXL is triggering this. Can be removed when the
+                * driver is fixed.
                 */
-               if (WARN_ON(bo->pin_count)) {
+               if (WARN_ON_ONCE(bo->pin_count)) {
                        bo->pin_count = 0;
                        ttm_bo_move_to_lru_tail(bo, &bo->mem, NULL);
                }
index 6e27cb1..4eb6efb 100644 (file)
@@ -268,13 +268,13 @@ static void ttm_pool_type_init(struct ttm_pool_type *pt, struct ttm_pool *pool,
 /* Remove a pool_type from the global shrinker list and free all pages */
 static void ttm_pool_type_fini(struct ttm_pool_type *pt)
 {
-       struct page *p, *tmp;
+       struct page *p;
 
        mutex_lock(&shrinker_lock);
        list_del(&pt->shrinker_list);
        mutex_unlock(&shrinker_lock);
 
-       list_for_each_entry_safe(p, tmp, &pt->pages, lru)
+       while ((p = ttm_pool_type_take(pt)))
                ttm_pool_free_page(pt->pool, pt->caching, pt->order, p);
 }
 
index 9269092..5703277 100644 (file)
@@ -32,6 +32,22 @@ static int udl_usb_resume(struct usb_interface *interface)
        return drm_mode_config_helper_resume(dev);
 }
 
+/*
+ * FIXME: Dma-buf sharing requires DMA support by the importing device.
+ *        This function is a workaround to make USB devices work as well.
+ *        See todo.rst for how to fix the issue in the dma-buf framework.
+ */
+static struct drm_gem_object *udl_driver_gem_prime_import(struct drm_device *dev,
+                                                         struct dma_buf *dma_buf)
+{
+       struct udl_device *udl = to_udl(dev);
+
+       if (!udl->dmadev)
+               return ERR_PTR(-ENODEV);
+
+       return drm_gem_prime_import_dev(dev, dma_buf, udl->dmadev);
+}
+
 DEFINE_DRM_GEM_FOPS(udl_driver_fops);
 
 static const struct drm_driver driver = {
@@ -40,6 +56,7 @@ static const struct drm_driver driver = {
        /* GEM hooks */
        .fops = &udl_driver_fops,
        DRM_GEM_SHMEM_DRIVER_OPS,
+       .gem_prime_import = udl_driver_gem_prime_import,
 
        .name = DRIVER_NAME,
        .desc = DRIVER_DESC,
index 875e735..cc16a13 100644 (file)
@@ -50,6 +50,7 @@ struct urb_list {
 struct udl_device {
        struct drm_device drm;
        struct device *dev;
+       struct device *dmadev;
 
        struct drm_simple_display_pipe display_pipe;
 
index 0e2a376..853f147 100644 (file)
@@ -315,6 +315,10 @@ int udl_init(struct udl_device *udl)
 
        DRM_DEBUG("\n");
 
+       udl->dmadev = usb_intf_get_dma_device(to_usb_interface(dev->dev));
+       if (!udl->dmadev)
+               drm_warn(dev, "buffer sharing not supported"); /* not an error */
+
        mutex_init(&udl->gem_lock);
 
        if (!udl_parse_vendor_descriptor(udl)) {
@@ -343,12 +347,18 @@ int udl_init(struct udl_device *udl)
 err:
        if (udl->urbs.count)
                udl_free_urb_list(dev);
+       put_device(udl->dmadev);
        DRM_ERROR("%d\n", ret);
        return ret;
 }
 
 int udl_drop_usb(struct drm_device *dev)
 {
+       struct udl_device *udl = to_udl(dev);
+
        udl_free_urb_list(dev);
+       put_device(udl->dmadev);
+       udl->dmadev = NULL;
+
        return 0;
 }
index 0a900af..45c9c6a 100644 (file)
@@ -500,8 +500,6 @@ vm_fault_t vmw_bo_vm_huge_fault(struct vm_fault *vmf,
        vm_fault_t ret;
        pgoff_t fault_page_size;
        bool write = vmf->flags & FAULT_FLAG_WRITE;
-       bool is_cow_mapping =
-               (vma->vm_flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE;
 
        switch (pe_size) {
        case PE_SIZE_PMD:
@@ -518,7 +516,7 @@ vm_fault_t vmw_bo_vm_huge_fault(struct vm_fault *vmf,
        }
 
        /* Always do write dirty-tracking and COW on PTE level. */
-       if (write && (READ_ONCE(vbo->dirty) || is_cow_mapping))
+       if (write && (READ_ONCE(vbo->dirty) || is_cow_mapping(vma->vm_flags)))
                return VM_FAULT_FALLBACK;
 
        ret = ttm_bo_vm_reserve(bo, vmf);
index 3c03b17..cb99758 100644 (file)
@@ -49,7 +49,7 @@ int vmw_mmap(struct file *filp, struct vm_area_struct *vma)
        vma->vm_ops = &vmw_vm_ops;
 
        /* Use VM_PFNMAP rather than VM_MIXEDMAP if not a COW mapping */
-       if ((vma->vm_flags & (VM_SHARED | VM_MAYWRITE)) != VM_MAYWRITE)
+       if (!is_cow_mapping(vma->vm_flags))
                vma->vm_flags = (vma->vm_flags & ~VM_MIXEDMAP) | VM_PFNMAP;
 
        return 0;
index bf7d22f..e0667c4 100644 (file)
@@ -266,6 +266,8 @@ config ADI_AXI_ADC
        select IIO_BUFFER
        select IIO_BUFFER_HW_CONSUMER
        select IIO_BUFFER_DMAENGINE
+       depends on HAS_IOMEM
+       depends on OF
        help
          Say yes here to build support for Analog Devices Generic
          AXI ADC IP core. The IP core is used for interfacing with
@@ -923,6 +925,7 @@ config STM32_ADC_CORE
        depends on ARCH_STM32 || COMPILE_TEST
        depends on OF
        depends on REGULATOR
+       depends on HAS_IOMEM
        select IIO_BUFFER
        select MFD_STM32_TIMERS
        select IIO_STM32_TIMER_TRIGGER
index 6f9a3e2..7b5212b 100644 (file)
@@ -918,7 +918,7 @@ static int ab8500_gpadc_read_raw(struct iio_dev *indio_dev,
                        return processed;
 
                /* Return millivolt or milliamps or millicentigrades */
-               *val = processed * 1000;
+               *val = processed;
                return IIO_VAL_INT;
        }
 
index 5d597e5..1b4b320 100644 (file)
@@ -91,7 +91,7 @@ static int ad7949_spi_read_channel(struct ad7949_adc_chip *ad7949_adc, int *val,
        int ret;
        int i;
        int bits_per_word = ad7949_adc->resolution;
-       int mask = GENMASK(ad7949_adc->resolution, 0);
+       int mask = GENMASK(ad7949_adc->resolution - 1, 0);
        struct spi_message msg;
        struct spi_transfer tx[] = {
                {
index 05ff948..07b1a99 100644 (file)
@@ -597,7 +597,7 @@ static const struct vadc_channels vadc_chans[] = {
        VADC_CHAN_NO_SCALE(P_MUX16_1_3, 1)
 
        VADC_CHAN_NO_SCALE(LR_MUX1_BAT_THERM, 0)
-       VADC_CHAN_NO_SCALE(LR_MUX2_BAT_ID, 0)
+       VADC_CHAN_VOLT(LR_MUX2_BAT_ID, 0, SCALE_DEFAULT)
        VADC_CHAN_NO_SCALE(LR_MUX3_XO_THERM, 0)
        VADC_CHAN_NO_SCALE(LR_MUX4_AMUX_THM1, 0)
        VADC_CHAN_NO_SCALE(LR_MUX5_AMUX_THM2, 0)
index dfa31a2..ac90be0 100644 (file)
@@ -551,6 +551,8 @@ static irqreturn_t mpu3050_trigger_handler(int irq, void *p)
                                               MPU3050_FIFO_R,
                                               &fifo_values[offset],
                                               toread);
+                       if (ret)
+                               goto out_trigger_unlock;
 
                        dev_dbg(mpu3050->dev,
                                "%04x %04x %04x %04x %04x\n",
index 52f6051..d627054 100644 (file)
 struct hid_humidity_state {
        struct hid_sensor_common common_attributes;
        struct hid_sensor_hub_attribute_info humidity_attr;
-       s32 humidity_data;
+       struct {
+               s32 humidity_data;
+               u64 timestamp __aligned(8);
+       } scan;
        int scale_pre_decml;
        int scale_post_decml;
        int scale_precision;
@@ -125,9 +128,8 @@ static int humidity_proc_event(struct hid_sensor_hub_device *hsdev,
        struct hid_humidity_state *humid_st = iio_priv(indio_dev);
 
        if (atomic_read(&humid_st->common_attributes.data_ready))
-               iio_push_to_buffers_with_timestamp(indio_dev,
-                                       &humid_st->humidity_data,
-                                       iio_get_time_ns(indio_dev));
+               iio_push_to_buffers_with_timestamp(indio_dev, &humid_st->scan,
+                                                  iio_get_time_ns(indio_dev));
 
        return 0;
 }
@@ -142,7 +144,7 @@ static int humidity_capture_sample(struct hid_sensor_hub_device *hsdev,
 
        switch (usage_id) {
        case HID_USAGE_SENSOR_ATMOSPHERIC_HUMIDITY:
-               humid_st->humidity_data = *(s32 *)raw_data;
+               humid_st->scan.humidity_data = *(s32 *)raw_data;
 
                return 0;
        default:
index 54af2ed..785a4ce 100644 (file)
@@ -462,8 +462,7 @@ static int adis16400_initial_setup(struct iio_dev *indio_dev)
                if (ret)
                        goto err_ret;
 
-               ret = sscanf(indio_dev->name, "adis%u\n", &device_id);
-               if (ret != 1) {
+               if (sscanf(indio_dev->name, "adis%u\n", &device_id) != 1) {
                        ret = -EINVAL;
                        goto err_ret;
                }
index 330cf35..e9e00ce 100644 (file)
@@ -23,6 +23,9 @@ struct prox_state {
        struct hid_sensor_common common_attributes;
        struct hid_sensor_hub_attribute_info prox_attr;
        u32 human_presence;
+       int scale_pre_decml;
+       int scale_post_decml;
+       int scale_precision;
 };
 
 /* Channel definitions */
@@ -93,8 +96,9 @@ static int prox_read_raw(struct iio_dev *indio_dev,
                ret_type = IIO_VAL_INT;
                break;
        case IIO_CHAN_INFO_SCALE:
-               *val = prox_state->prox_attr.units;
-               ret_type = IIO_VAL_INT;
+               *val = prox_state->scale_pre_decml;
+               *val2 = prox_state->scale_post_decml;
+               ret_type = prox_state->scale_precision;
                break;
        case IIO_CHAN_INFO_OFFSET:
                *val = hid_sensor_convert_exponent(
@@ -234,6 +238,11 @@ static int prox_parse_report(struct platform_device *pdev,
                        HID_USAGE_SENSOR_HUMAN_PRESENCE,
                        &st->common_attributes.sensitivity);
 
+       st->scale_precision = hid_sensor_format_scale(
+                               hsdev->usage,
+                               &st->prox_attr,
+                               &st->scale_pre_decml, &st->scale_post_decml);
+
        return ret;
 }
 
index 81688f1..da9a247 100644 (file)
 struct temperature_state {
        struct hid_sensor_common common_attributes;
        struct hid_sensor_hub_attribute_info temperature_attr;
-       s32 temperature_data;
+       struct {
+               s32 temperature_data;
+               u64 timestamp __aligned(8);
+       } scan;
        int scale_pre_decml;
        int scale_post_decml;
        int scale_precision;
@@ -32,7 +35,7 @@ static const struct iio_chan_spec temperature_channels[] = {
                        BIT(IIO_CHAN_INFO_SAMP_FREQ) |
                        BIT(IIO_CHAN_INFO_HYSTERESIS),
        },
-       IIO_CHAN_SOFT_TIMESTAMP(3),
+       IIO_CHAN_SOFT_TIMESTAMP(1),
 };
 
 /* Adjust channel real bits based on report descriptor */
@@ -123,9 +126,8 @@ static int temperature_proc_event(struct hid_sensor_hub_device *hsdev,
        struct temperature_state *temp_st = iio_priv(indio_dev);
 
        if (atomic_read(&temp_st->common_attributes.data_ready))
-               iio_push_to_buffers_with_timestamp(indio_dev,
-                               &temp_st->temperature_data,
-                               iio_get_time_ns(indio_dev));
+               iio_push_to_buffers_with_timestamp(indio_dev, &temp_st->scan,
+                                                  iio_get_time_ns(indio_dev));
 
        return 0;
 }
@@ -140,7 +142,7 @@ static int temperature_capture_sample(struct hid_sensor_hub_device *hsdev,
 
        switch (usage_id) {
        case HID_USAGE_SENSOR_DATA_ENVIRONMENTAL_TEMPERATURE:
-               temp_st->temperature_data = *(s32 *)raw_data;
+               temp_st->scan.temperature_data = *(s32 *)raw_data;
                return 0;
        default:
                return -EINVAL;
index 430dc69..da8963a 100644 (file)
@@ -26,7 +26,6 @@
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 MODULE_DESCRIPTION("Joystick device interfaces");
-MODULE_SUPPORTED_DEVICE("input/js");
 MODULE_LICENSE("GPL");
 
 #define JOYDEV_MINOR_BASE      0
index ad1b6c9..7237dc4 100644 (file)
@@ -94,6 +94,17 @@ config INPUT_ARIZONA_HAPTICS
          To compile this driver as a module, choose M here: the
          module will be called arizona-haptics.
 
+config INPUT_ATC260X_ONKEY
+       tristate "Actions Semi ATC260x PMIC ONKEY"
+       depends on MFD_ATC260X
+       help
+         Support the ONKEY of ATC260x PMICs as an input device reporting
+         power button status. ONKEY can be used to wakeup from low power
+         modes and force a reset on long press.
+
+         To compile this driver as a module, choose M here: the
+         module will be called atc260x-onkey.
+
 config INPUT_ATMEL_CAPTOUCH
        tristate "Atmel Capacitive Touch Button Driver"
        depends on OF || COMPILE_TEST
index 7f202ba..46db664 100644 (file)
@@ -17,6 +17,7 @@ obj-$(CONFIG_INPUT_ADXL34X_SPI)               += adxl34x-spi.o
 obj-$(CONFIG_INPUT_APANEL)             += apanel.o
 obj-$(CONFIG_INPUT_ARIEL_PWRBUTTON)    += ariel-pwrbutton.o
 obj-$(CONFIG_INPUT_ARIZONA_HAPTICS)    += arizona-haptics.o
+obj-$(CONFIG_INPUT_ATC260X_ONKEY)      += atc260x-onkey.o
 obj-$(CONFIG_INPUT_ATI_REMOTE2)                += ati_remote2.o
 obj-$(CONFIG_INPUT_ATLAS_BTNS)         += atlas_btns.o
 obj-$(CONFIG_INPUT_ATMEL_CAPTOUCH)     += atmel_captouch.o
@@ -86,4 +87,3 @@ obj-$(CONFIG_INPUT_WM831X_ON)         += wm831x-on.o
 obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND)        += xen-kbdfront.o
 obj-$(CONFIG_INPUT_YEALINK)            += yealink.o
 obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR)   += ideapad_slidebar.o
-
diff --git a/drivers/input/misc/atc260x-onkey.c b/drivers/input/misc/atc260x-onkey.c
new file mode 100644 (file)
index 0000000..999aabf
--- /dev/null
@@ -0,0 +1,305 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Onkey driver for Actions Semi ATC260x PMICs.
+ *
+ * Copyright (c) 2020 Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/atc260x/core.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+/* <2s for short press, >2s for long press */
+#define KEY_PRESS_TIME_SEC     2
+
+/* Driver internals */
+enum atc260x_onkey_reset_status {
+       KEY_RESET_HW_DEFAULT,
+       KEY_RESET_DISABLED,
+       KEY_RESET_USER_SEL,
+};
+
+struct atc260x_onkey_params {
+       u32 reg_int_ctl;
+       u32 kdwn_state_bm;
+       u32 long_int_pnd_bm;
+       u32 short_int_pnd_bm;
+       u32 kdwn_int_pnd_bm;
+       u32 press_int_en_bm;
+       u32 kdwn_int_en_bm;
+       u32 press_time_bm;
+       u32 reset_en_bm;
+       u32 reset_time_bm;
+};
+
+struct atc260x_onkey {
+       struct atc260x *atc260x;
+       const struct atc260x_onkey_params *params;
+       struct input_dev *input_dev;
+       struct delayed_work work;
+       int irq;
+};
+
+static const struct atc260x_onkey_params atc2603c_onkey_params = {
+       .reg_int_ctl            = ATC2603C_PMU_SYS_CTL2,
+       .long_int_pnd_bm        = ATC2603C_PMU_SYS_CTL2_ONOFF_LONG_PRESS,
+       .short_int_pnd_bm       = ATC2603C_PMU_SYS_CTL2_ONOFF_SHORT_PRESS,
+       .kdwn_int_pnd_bm        = ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_PD,
+       .press_int_en_bm        = ATC2603C_PMU_SYS_CTL2_ONOFF_INT_EN,
+       .kdwn_int_en_bm         = ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_INT_EN,
+       .kdwn_state_bm          = ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS,
+       .press_time_bm          = ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_TIME,
+       .reset_en_bm            = ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_RESET_EN,
+       .reset_time_bm          = ATC2603C_PMU_SYS_CTL2_ONOFF_RESET_TIME_SEL,
+};
+
+static const struct atc260x_onkey_params atc2609a_onkey_params = {
+       .reg_int_ctl            = ATC2609A_PMU_SYS_CTL2,
+       .long_int_pnd_bm        = ATC2609A_PMU_SYS_CTL2_ONOFF_LONG_PRESS,
+       .short_int_pnd_bm       = ATC2609A_PMU_SYS_CTL2_ONOFF_SHORT_PRESS,
+       .kdwn_int_pnd_bm        = ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS_PD,
+       .press_int_en_bm        = ATC2609A_PMU_SYS_CTL2_ONOFF_LSP_INT_EN,
+       .kdwn_int_en_bm         = ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS_INT_EN,
+       .kdwn_state_bm          = ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS,
+       .press_time_bm          = ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS_TIME,
+       .reset_en_bm            = ATC2609A_PMU_SYS_CTL2_ONOFF_RESET_EN,
+       .reset_time_bm          = ATC2609A_PMU_SYS_CTL2_ONOFF_RESET_TIME_SEL,
+};
+
+static int atc2603x_onkey_hw_init(struct atc260x_onkey *onkey,
+                                 enum atc260x_onkey_reset_status reset_status,
+                                 u32 reset_time, u32 press_time)
+{
+       u32 reg_bm, reg_val;
+
+       reg_bm = onkey->params->long_int_pnd_bm |
+                onkey->params->short_int_pnd_bm |
+                onkey->params->kdwn_int_pnd_bm |
+                onkey->params->press_int_en_bm |
+                onkey->params->kdwn_int_en_bm;
+
+       reg_val = reg_bm | press_time;
+       reg_bm |= onkey->params->press_time_bm;
+
+       if (reset_status == KEY_RESET_DISABLED) {
+               reg_bm |= onkey->params->reset_en_bm;
+       } else if (reset_status == KEY_RESET_USER_SEL) {
+               reg_bm |= onkey->params->reset_en_bm |
+                         onkey->params->reset_time_bm;
+               reg_val |= onkey->params->reset_en_bm | reset_time;
+       }
+
+       return regmap_update_bits(onkey->atc260x->regmap,
+                                 onkey->params->reg_int_ctl, reg_bm, reg_val);
+}
+
+static void atc260x_onkey_query(struct atc260x_onkey *onkey)
+{
+       u32 reg_bits;
+       int ret, key_down;
+
+       ret = regmap_read(onkey->atc260x->regmap,
+                         onkey->params->reg_int_ctl, &key_down);
+       if (ret) {
+               key_down = 1;
+               dev_err(onkey->atc260x->dev,
+                       "Failed to read onkey status: %d\n", ret);
+       } else {
+               key_down &= onkey->params->kdwn_state_bm;
+       }
+
+       /*
+        * The hardware generates interrupt only when the onkey pin is
+        * asserted. Hence, the deassertion of the pin is simulated through
+        * work queue.
+        */
+       if (key_down) {
+               schedule_delayed_work(&onkey->work, msecs_to_jiffies(200));
+               return;
+       }
+
+       /*
+        * The key-down status bit is cleared when the On/Off button
+        * is released.
+        */
+       input_report_key(onkey->input_dev, KEY_POWER, 0);
+       input_sync(onkey->input_dev);
+
+       reg_bits = onkey->params->long_int_pnd_bm |
+                  onkey->params->short_int_pnd_bm |
+                  onkey->params->kdwn_int_pnd_bm |
+                  onkey->params->press_int_en_bm |
+                  onkey->params->kdwn_int_en_bm;
+
+       /* Clear key press pending events and enable key press interrupts. */
+       regmap_update_bits(onkey->atc260x->regmap, onkey->params->reg_int_ctl,
+                          reg_bits, reg_bits);
+}
+
+static void atc260x_onkey_work(struct work_struct *work)
+{
+       struct atc260x_onkey *onkey = container_of(work, struct atc260x_onkey,
+                                                  work.work);
+       atc260x_onkey_query(onkey);
+}
+
+static irqreturn_t atc260x_onkey_irq(int irq, void *data)
+{
+       struct atc260x_onkey *onkey = data;
+       int ret;
+
+       /* Disable key press interrupts. */
+       ret = regmap_update_bits(onkey->atc260x->regmap,
+                                onkey->params->reg_int_ctl,
+                                onkey->params->press_int_en_bm |
+                                onkey->params->kdwn_int_en_bm, 0);
+       if (ret)
+               dev_err(onkey->atc260x->dev,
+                       "Failed to disable interrupts: %d\n", ret);
+
+       input_report_key(onkey->input_dev, KEY_POWER, 1);
+       input_sync(onkey->input_dev);
+
+       atc260x_onkey_query(onkey);
+
+       return IRQ_HANDLED;
+}
+
+static int atc260x_onkey_open(struct input_dev *dev)
+{
+       struct atc260x_onkey *onkey = input_get_drvdata(dev);
+
+       enable_irq(onkey->irq);
+
+       return 0;
+}
+
+static void atc260x_onkey_close(struct input_dev *dev)
+{
+       struct atc260x_onkey *onkey = input_get_drvdata(dev);
+
+       disable_irq(onkey->irq);
+       cancel_delayed_work_sync(&onkey->work);
+}
+
+static int atc260x_onkey_probe(struct platform_device *pdev)
+{
+       struct atc260x *atc260x = dev_get_drvdata(pdev->dev.parent);
+       struct atc260x_onkey *onkey;
+       struct input_dev *input_dev;
+       enum atc260x_onkey_reset_status reset_status;
+       u32 press_time = KEY_PRESS_TIME_SEC, reset_time = 0;
+       int val, error;
+
+       onkey = devm_kzalloc(&pdev->dev, sizeof(*onkey), GFP_KERNEL);
+       if (!onkey)
+               return -ENOMEM;
+
+       error = device_property_read_u32(pdev->dev.parent,
+                                        "reset-time-sec", &val);
+       if (error) {
+               reset_status = KEY_RESET_HW_DEFAULT;
+       } else if (val) {
+               if (val < 6 || val > 12) {
+                       dev_err(&pdev->dev, "reset-time-sec out of range\n");
+                       return -EINVAL;
+               }
+
+               reset_status = KEY_RESET_USER_SEL;
+               reset_time = (val - 6) / 2;
+       } else {
+               reset_status = KEY_RESET_DISABLED;
+               dev_dbg(&pdev->dev, "Disabled reset on long-press\n");
+       }
+
+       switch (atc260x->ic_type) {
+       case ATC2603C:
+               onkey->params = &atc2603c_onkey_params;
+               press_time = FIELD_PREP(ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_TIME,
+                                       press_time);
+               reset_time = FIELD_PREP(ATC2603C_PMU_SYS_CTL2_ONOFF_RESET_TIME_SEL,
+                                       reset_time);
+               break;
+       case ATC2609A:
+               onkey->params = &atc2609a_onkey_params;
+               press_time = FIELD_PREP(ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS_TIME,
+                                       press_time);
+               reset_time = FIELD_PREP(ATC2609A_PMU_SYS_CTL2_ONOFF_RESET_TIME_SEL,
+                                       reset_time);
+               break;
+       default:
+               dev_err(&pdev->dev,
+                       "OnKey not supported for ATC260x PMIC type: %u\n",
+                       atc260x->ic_type);
+               return -EINVAL;
+       }
+
+       input_dev = devm_input_allocate_device(&pdev->dev);
+       if (!input_dev) {
+               dev_err(&pdev->dev, "Failed to allocate input device\n");
+               return -ENOMEM;
+       }
+
+       onkey->input_dev = input_dev;
+       onkey->atc260x = atc260x;
+
+       input_dev->name = "atc260x-onkey";
+       input_dev->phys = "atc260x-onkey/input0";
+       input_dev->open = atc260x_onkey_open;
+       input_dev->close = atc260x_onkey_close;
+
+       input_set_capability(input_dev, EV_KEY, KEY_POWER);
+       input_set_drvdata(input_dev, onkey);
+
+       INIT_DELAYED_WORK(&onkey->work, atc260x_onkey_work);
+
+       onkey->irq = platform_get_irq(pdev, 0);
+       if (onkey->irq < 0)
+               return onkey->irq;
+
+       error = devm_request_threaded_irq(&pdev->dev, onkey->irq, NULL,
+                                         atc260x_onkey_irq, IRQF_ONESHOT,
+                                         dev_name(&pdev->dev), onkey);
+       if (error) {
+               dev_err(&pdev->dev,
+                       "Failed to register IRQ %d: %d\n", onkey->irq, error);
+               return error;
+       }
+
+       /* Keep IRQ disabled until atc260x_onkey_open() is called. */
+       disable_irq(onkey->irq);
+
+       error = input_register_device(input_dev);
+       if (error) {
+               dev_err(&pdev->dev,
+                       "Failed to register input device: %d\n", error);
+               return error;
+       }
+
+       error = atc2603x_onkey_hw_init(onkey, reset_status,
+                                      reset_time, press_time);
+       if (error)
+               return error;
+
+       device_init_wakeup(&pdev->dev, true);
+
+       return 0;
+}
+
+static struct platform_driver atc260x_onkey_driver = {
+       .probe  = atc260x_onkey_probe,
+       .driver = {
+               .name = "atc260x-onkey",
+       },
+};
+
+module_platform_driver(atc260x_onkey_driver);
+
+MODULE_DESCRIPTION("Onkey driver for ATC260x PMICs");
+MODULE_AUTHOR("Cristian Ciocaltea <cristian.ciocaltea@gmail.com>");
+MODULE_LICENSE("GPL");
index 9126efc..321f590 100644 (file)
@@ -2714,7 +2714,6 @@ static int __init early_amd_iommu_init(void)
        struct acpi_table_header *ivrs_base;
        int i, remap_cache_sz, ret;
        acpi_status status;
-       u32 pci_id;
 
        if (!amd_iommu_detected)
                return -ENODEV;
@@ -2804,16 +2803,6 @@ static int __init early_amd_iommu_init(void)
        if (ret)
                goto out;
 
-       /* Disable IOMMU if there's Stoney Ridge graphics */
-       for (i = 0; i < 32; i++) {
-               pci_id = read_pci_config(0, i, 0, 0);
-               if ((pci_id & 0xffff) == 0x1002 && (pci_id >> 16) == 0x98e4) {
-                       pr_info("Disable IOMMU on Stoney Ridge\n");
-                       amd_iommu_disabled = true;
-                       break;
-               }
-       }
-
        /* Disable any previously enabled IOMMUs */
        if (!is_kdump_kernel() || amd_iommu_disabled)
                disable_iommus();
@@ -2880,6 +2869,7 @@ static bool detect_ivrs(void)
 {
        struct acpi_table_header *ivrs_base;
        acpi_status status;
+       int i;
 
        status = acpi_get_table("IVRS", 0, &ivrs_base);
        if (status == AE_NOT_FOUND)
@@ -2892,6 +2882,17 @@ static bool detect_ivrs(void)
 
        acpi_put_table(ivrs_base);
 
+       /* Don't use IOMMU if there is Stoney Ridge graphics */
+       for (i = 0; i < 32; i++) {
+               u32 pci_id;
+
+               pci_id = read_pci_config(0, i, 0, 0);
+               if ((pci_id & 0xffff) == 0x1002 && (pci_id >> 16) == 0x98e4) {
+                       pr_info("Disable IOMMU on Stoney Ridge\n");
+                       return false;
+               }
+       }
+
        /* Make sure ACS will be enabled during PCI probe */
        pci_request_acs();
 
@@ -2918,12 +2919,12 @@ static int __init state_next(void)
                }
                break;
        case IOMMU_IVRS_DETECTED:
-               ret = early_amd_iommu_init();
-               init_state = ret ? IOMMU_INIT_ERROR : IOMMU_ACPI_FINISHED;
-               if (init_state == IOMMU_ACPI_FINISHED && amd_iommu_disabled) {
-                       pr_info("AMD IOMMU disabled\n");
+               if (amd_iommu_disabled) {
                        init_state = IOMMU_CMDLINE_DISABLED;
                        ret = -EINVAL;
+               } else {
+                       ret = early_amd_iommu_init();
+                       init_state = ret ? IOMMU_INIT_ERROR : IOMMU_ACPI_FINISHED;
                }
                break;
        case IOMMU_ACPI_FINISHED:
@@ -3001,8 +3002,11 @@ int __init amd_iommu_prepare(void)
        amd_iommu_irq_remap = true;
 
        ret = iommu_go_to_state(IOMMU_ACPI_FINISHED);
-       if (ret)
+       if (ret) {
+               amd_iommu_irq_remap = false;
                return ret;
+       }
+
        return amd_iommu_irq_remap ? 0 : -ENODEV;
 }
 
index 97eb62f..602aab9 100644 (file)
@@ -849,12 +849,11 @@ static struct iommu_device *tegra_smmu_probe_device(struct device *dev)
                smmu = tegra_smmu_find(args.np);
                if (smmu) {
                        err = tegra_smmu_configure(smmu, dev, &args);
-                       of_node_put(args.np);
 
-                       if (err < 0)
+                       if (err < 0) {
+                               of_node_put(args.np);
                                return ERR_PTR(err);
-
-                       break;
+                       }
                }
 
                of_node_put(args.np);
index e74fa20..15536e3 100644 (file)
@@ -8,7 +8,6 @@ config IRQCHIP
 config ARM_GIC
        bool
        select IRQ_DOMAIN_HIERARCHY
-       select GENERIC_IRQ_MULTI_HANDLER
        select GENERIC_IRQ_EFFECTIVE_AFF_MASK
 
 config ARM_GIC_PM
@@ -33,7 +32,6 @@ config GIC_NON_BANKED
 
 config ARM_GIC_V3
        bool
-       select GENERIC_IRQ_MULTI_HANDLER
        select IRQ_DOMAIN_HIERARCHY
        select PARTITION_PERCPU
        select GENERIC_IRQ_EFFECTIVE_AFF_MASK
@@ -64,7 +62,6 @@ config ARM_NVIC
 config ARM_VIC
        bool
        select IRQ_DOMAIN
-       select GENERIC_IRQ_MULTI_HANDLER
 
 config ARM_VIC_NR
        int
@@ -99,14 +96,12 @@ config ATMEL_AIC_IRQ
        bool
        select GENERIC_IRQ_CHIP
        select IRQ_DOMAIN
-       select GENERIC_IRQ_MULTI_HANDLER
        select SPARSE_IRQ
 
 config ATMEL_AIC5_IRQ
        bool
        select GENERIC_IRQ_CHIP
        select IRQ_DOMAIN
-       select GENERIC_IRQ_MULTI_HANDLER
        select SPARSE_IRQ
 
 config I8259
@@ -153,7 +148,6 @@ config DW_APB_ICTL
 config FARADAY_FTINTC010
        bool
        select IRQ_DOMAIN
-       select GENERIC_IRQ_MULTI_HANDLER
        select SPARSE_IRQ
 
 config HISILICON_IRQ_MBIGEN
@@ -169,7 +163,6 @@ config IMGPDC_IRQ
 config IXP4XX_IRQ
        bool
        select IRQ_DOMAIN
-       select GENERIC_IRQ_MULTI_HANDLER
        select SPARSE_IRQ
 
 config MADERA_IRQ
@@ -186,7 +179,6 @@ config CLPS711X_IRQCHIP
        bool
        depends on ARCH_CLPS711X
        select IRQ_DOMAIN
-       select GENERIC_IRQ_MULTI_HANDLER
        select SPARSE_IRQ
        default y
 
@@ -205,7 +197,6 @@ config OMAP_IRQCHIP
 config ORION_IRQCHIP
        bool
        select IRQ_DOMAIN
-       select GENERIC_IRQ_MULTI_HANDLER
 
 config PIC32_EVIC
        bool
index 7a7222d..b938d1d 100644 (file)
@@ -179,5 +179,6 @@ err_free_tcu:
 }
 IRQCHIP_DECLARE(jz4740_tcu_irq, "ingenic,jz4740-tcu", ingenic_tcu_irq_init);
 IRQCHIP_DECLARE(jz4725b_tcu_irq, "ingenic,jz4725b-tcu", ingenic_tcu_irq_init);
+IRQCHIP_DECLARE(jz4760_tcu_irq, "ingenic,jz4760-tcu", ingenic_tcu_irq_init);
 IRQCHIP_DECLARE(jz4770_tcu_irq, "ingenic,jz4770-tcu", ingenic_tcu_irq_init);
 IRQCHIP_DECLARE(x1000_tcu_irq, "ingenic,x1000-tcu", ingenic_tcu_irq_init);
index b61a890..ea36bb0 100644 (file)
@@ -155,6 +155,7 @@ static int __init intc_2chip_of_init(struct device_node *node,
 {
        return ingenic_intc_of_init(node, 2);
 }
+IRQCHIP_DECLARE(jz4760_intc, "ingenic,jz4760-intc", intc_2chip_of_init);
 IRQCHIP_DECLARE(jz4770_intc, "ingenic,jz4770-intc", intc_2chip_of_init);
 IRQCHIP_DECLARE(jz4775_intc, "ingenic,jz4775-intc", intc_2chip_of_init);
 IRQCHIP_DECLARE(jz4780_intc, "ingenic,jz4780-intc", intc_2chip_of_init);
index d2ab6ab..f62db7e 100644 (file)
@@ -51,10 +51,8 @@ static ssize_t ttyname_store(struct device *dev,
 
        if (size) {
                ttyname = kmemdup_nul(buf, size, GFP_KERNEL);
-               if (!ttyname) {
-                       ret = -ENOMEM;
-                       goto out_unlock;
-               }
+               if (!ttyname)
+                       return -ENOMEM;
        } else {
                ttyname = NULL;
        }
@@ -69,7 +67,6 @@ static ssize_t ttyname_store(struct device *dev,
 
        trigger_data->ttyname = ttyname;
 
-out_unlock:
        mutex_unlock(&trigger_data->mutex);
 
        if (ttyname && !running)
@@ -125,12 +122,12 @@ static void ledtrig_tty_work(struct work_struct *work)
 
        if (icount.rx != trigger_data->rx ||
            icount.tx != trigger_data->tx) {
-               led_set_brightness(trigger_data->led_cdev, LED_ON);
+               led_set_brightness_sync(trigger_data->led_cdev, LED_ON);
 
                trigger_data->rx = icount.rx;
                trigger_data->tx = icount.tx;
        } else {
-               led_set_brightness(trigger_data->led_cdev, LED_OFF);
+               led_set_brightness_sync(trigger_data->led_cdev, LED_OFF);
        }
 
 out:
index 71691f3..03e1fe4 100644 (file)
@@ -965,7 +965,7 @@ static int bcache_device_init(struct bcache_device *d, unsigned int block_size,
        q->limits.max_hw_sectors        = UINT_MAX;
        q->limits.max_sectors           = UINT_MAX;
        q->limits.max_segment_size      = UINT_MAX;
-       q->limits.max_segments          = BIO_MAX_PAGES;
+       q->limits.max_segments          = BIO_MAX_VECS;
        blk_queue_max_discard_sectors(q, UINT_MAX);
        q->limits.discard_granularity   = 512;
        q->limits.io_min                = block_size;
index 11c105e..b0ab080 100644 (file)
@@ -229,7 +229,7 @@ static DEFINE_SPINLOCK(dm_crypt_clients_lock);
 static unsigned dm_crypt_clients_n = 0;
 static volatile unsigned long dm_crypt_pages_per_client;
 #define DM_CRYPT_MEMORY_PERCENT                        2
-#define DM_CRYPT_MIN_PAGES_PER_CLIENT          (BIO_MAX_PAGES * 16)
+#define DM_CRYPT_MIN_PAGES_PER_CLIENT          (BIO_MAX_VECS * 16)
 
 static void clone_init(struct dm_crypt_io *, struct bio *);
 static void kcryptd_queue_crypt(struct dm_crypt_io *io);
@@ -3246,7 +3246,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                ALIGN(sizeof(struct dm_crypt_io) + cc->dmreq_start + additional_req_size,
                      ARCH_KMALLOC_MINALIGN);
 
-       ret = mempool_init(&cc->page_pool, BIO_MAX_PAGES, crypt_page_alloc, crypt_page_free, cc);
+       ret = mempool_init(&cc->page_pool, BIO_MAX_VECS, crypt_page_alloc, crypt_page_free, cc);
        if (ret) {
                ti->error = "Cannot allocate page mempool";
                goto bad;
@@ -3373,9 +3373,9 @@ static int crypt_map(struct dm_target *ti, struct bio *bio)
        /*
         * Check if bio is too large, split as needed.
         */
-       if (unlikely(bio->bi_iter.bi_size > (BIO_MAX_PAGES << PAGE_SHIFT)) &&
+       if (unlikely(bio->bi_iter.bi_size > (BIO_MAX_VECS << PAGE_SHIFT)) &&
            (bio_data_dir(bio) == WRITE || cc->on_disk_tag_size))
-               dm_accept_partial_bio(bio, ((BIO_MAX_PAGES << PAGE_SHIFT) >> SECTOR_SHIFT));
+               dm_accept_partial_bio(bio, ((BIO_MAX_VECS << PAGE_SHIFT) >> SECTOR_SHIFT));
 
        /*
         * Ensure that bio is a multiple of internal sector encryption size
index 844c4be..4f72b6f 100644 (file)
@@ -1892,10 +1892,10 @@ restart:
                        list_add(&g->lru, &wbl.list);
                        wbl.size++;
                        g->write_in_progress = true;
-                       g->wc_list_contiguous = BIO_MAX_PAGES;
+                       g->wc_list_contiguous = BIO_MAX_VECS;
                        f = g;
                        e->wc_list_contiguous++;
-                       if (unlikely(e->wc_list_contiguous == BIO_MAX_PAGES)) {
+                       if (unlikely(e->wc_list_contiguous == BIO_MAX_VECS)) {
                                if (unlikely(wc->writeback_all)) {
                                        next_node = rb_next(&f->rb_node);
                                        if (likely(next_node))
index 4337ae0..0b5dcaa 100644 (file)
@@ -735,7 +735,7 @@ static void r5l_submit_current_io(struct r5l_log *log)
 
 static struct bio *r5l_bio_alloc(struct r5l_log *log)
 {
-       struct bio *bio = bio_alloc_bioset(GFP_NOIO, BIO_MAX_PAGES, &log->bs);
+       struct bio *bio = bio_alloc_bioset(GFP_NOIO, BIO_MAX_VECS, &log->bs);
 
        bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
        bio_set_dev(bio, log->rdev->bdev);
@@ -1634,7 +1634,7 @@ static int r5l_recovery_allocate_ra_pool(struct r5l_log *log,
 {
        struct page *page;
 
-       ctx->ra_bio = bio_alloc_bioset(GFP_KERNEL, BIO_MAX_PAGES, &log->bs);
+       ctx->ra_bio = bio_alloc_bioset(GFP_KERNEL, BIO_MAX_VECS, &log->bs);
        if (!ctx->ra_bio)
                return -ENOMEM;
 
index e8c118e..3ddc2aa 100644 (file)
@@ -496,7 +496,7 @@ static void ppl_submit_iounit(struct ppl_io_unit *io)
                if (!bio_add_page(bio, sh->ppl_page, PAGE_SIZE, 0)) {
                        struct bio *prev = bio;
 
-                       bio = bio_alloc_bioset(GFP_NOIO, BIO_MAX_PAGES,
+                       bio = bio_alloc_bioset(GFP_NOIO, BIO_MAX_VECS,
                                               &ppl_conf->bs);
                        bio->bi_opf = prev->bi_opf;
                        bio->bi_write_hint = prev->bi_write_hint;
index 8a85852..5f6e97a 100644 (file)
@@ -430,4 +430,3 @@ MODULE_AUTHOR("Andreas Monitzer <andy@monitzer.com>");
 MODULE_AUTHOR("Ben Backx <ben@bbackx.com>");
 MODULE_DESCRIPTION("FireDTV DVB Driver");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("FireDTV DVB");
index 692b95a..9a82e68 100644 (file)
@@ -41,7 +41,6 @@ MODULE_PARM_DESC(debug,
 
 MODULE_AUTHOR("Andy Walls");
 MODULE_DESCRIPTION("CX23418 ALSA Interface");
-MODULE_SUPPORTED_DEVICE("CX23418 MPEG2 encoder");
 MODULE_LICENSE("GPL");
 
 MODULE_VERSION(CX18_VERSION);
index 95aed00..f2440eb 100644 (file)
@@ -232,7 +232,6 @@ MODULE_PARM_DESC(cx18_first_minor,
 
 MODULE_AUTHOR("Hans Verkuil");
 MODULE_DESCRIPTION("CX23418 driver");
-MODULE_SUPPORTED_DEVICE("CX23418 MPEG2 encoder");
 MODULE_LICENSE("GPL");
 
 MODULE_VERSION(CX18_VERSION);
index 608fbaf..8797d85 100644 (file)
@@ -104,7 +104,6 @@ MODULE_PARM_DESC(index, "Index value for cx25821 capture interface(s).");
 MODULE_DESCRIPTION("ALSA driver module for cx25821 based capture cards");
 MODULE_AUTHOR("Hiep Huynh");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Conexant,25821}");  /* "{{Conexant,23881}," */
 
 static unsigned int debug;
 module_param(debug, int, 0644);
index 95e0cbb..c83814c 100644 (file)
@@ -98,7 +98,6 @@ MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@kernel.org>");
 MODULE_LICENSE("GPL v2");
 MODULE_VERSION(CX88_VERSION);
 
-MODULE_SUPPORTED_DEVICE("{{Conexant,23881},{{Conexant,23882},{{Conexant,23883}");
 static unsigned int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable debug messages");
index 39029b8..4cefdb2 100644 (file)
@@ -38,7 +38,6 @@ MODULE_PARM_DESC(index,
 
 MODULE_AUTHOR("Andy Walls");
 MODULE_DESCRIPTION("CX23415/CX23416 ALSA Interface");
-MODULE_SUPPORTED_DEVICE("CX23415/CX23416 MPEG2 encoder");
 MODULE_LICENSE("GPL");
 
 MODULE_VERSION(IVTV_VERSION);
index 6e448cb..942b8c2 100644 (file)
@@ -275,9 +275,6 @@ MODULE_PARM_DESC(ivtv_first_minor, "Set device node number assigned to first car
 
 MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil");
 MODULE_DESCRIPTION("CX23415/CX23416 driver");
-MODULE_SUPPORTED_DEVICE
-    ("CX23415/CX23416 MPEG2 encoder (WinTV PVR-150/250/350/500,\n"
-               "\t\t\tYuan MPG series and similar)");
 MODULE_LICENSE("GPL");
 
 MODULE_VERSION(IVTV_VERSION);
index 336df65..524912f 100644 (file)
@@ -1269,6 +1269,5 @@ late_initcall_sync(sta2x11_vip_init_module);
 MODULE_DESCRIPTION("STA2X11 Video Input Port driver");
 MODULE_AUTHOR("Wind River");
 MODULE_LICENSE("GPL v2");
-MODULE_SUPPORTED_DEVICE("sta2x11 video input");
 MODULE_VERSION(DRV_VERSION);
 MODULE_DEVICE_TABLE(pci, sta2x11_vip_pci_tbl);
index 0514be6..e392b3e 100644 (file)
@@ -1363,4 +1363,3 @@ module_platform_driver(atmel_isi_driver);
 MODULE_AUTHOR("Josh Wu <josh.wu@atmel.com>");
 MODULE_DESCRIPTION("The V4L2 driver for Atmel Linux");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("video");
index 0b78fec..61d9885 100644 (file)
@@ -330,4 +330,3 @@ module_platform_driver(atmel_isc_driver);
 MODULE_AUTHOR("Songjun Wu");
 MODULE_DESCRIPTION("The V4L2 driver for Atmel-ISC");
 MODULE_LICENSE("GPL v2");
-MODULE_SUPPORTED_DEVICE("video");
index 9c94a8b..baac86f 100644 (file)
 MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
 MODULE_DESCRIPTION("Marvell 88ALP01 CMOS Camera Controller driver");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("Video");
-
-
-
 
 struct cafe_camera {
        int registered;                 /* Fully initialized? */
index aa5f457..a60c302 100644 (file)
@@ -1288,7 +1288,6 @@ static void rkisp1_params_config_parameter(struct rkisp1_params *params)
        memset(hst.hist_weight, 0x01, sizeof(hst.hist_weight));
        rkisp1_hst_config(params, &hst);
        rkisp1_param_set_bits(params, RKISP1_CIF_ISP_HIST_PROP,
-                             ~RKISP1_CIF_ISP_HIST_PROP_MODE_MASK |
                              rkisp1_hst_params_default_config.mode);
 
        /* set the  range */
index bbcc225..d9b4ad0 100644 (file)
@@ -2149,4 +2149,3 @@ MODULE_AUTHOR("Yannick Fertre <yannick.fertre@st.com>");
 MODULE_AUTHOR("Hugues Fruchet <hugues.fruchet@st.com>");
 MODULE_DESCRIPTION("STMicroelectronics STM32 Digital Camera Memory Interface driver");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("video");
index 86d5e3f..06f74d4 100644 (file)
@@ -245,7 +245,7 @@ static int vsp1_du_pipeline_setup_brx(struct vsp1_device *vsp1,
                brx = &vsp1->bru->entity;
        else if (pipe->brx && !drm_pipe->force_brx_release)
                brx = pipe->brx;
-       else if (!vsp1->bru->entity.pipe)
+       else if (vsp1_feature(vsp1, VSP1_HAS_BRU) && !vsp1->bru->entity.pipe)
                brx = &vsp1->bru->entity;
        else
                brx = &vsp1->brs->entity;
@@ -462,9 +462,9 @@ static int vsp1_du_pipeline_setup_inputs(struct vsp1_device *vsp1,
         * make sure it is present in the pipeline's list of entities if it
         * wasn't already.
         */
-       if (!use_uif) {
+       if (drm_pipe->uif && !use_uif) {
                drm_pipe->uif->pipe = NULL;
-       } else if (!drm_pipe->uif->pipe) {
+       } else if (drm_pipe->uif && !drm_pipe->uif->pipe) {
                drm_pipe->uif->pipe = pipe;
                list_add_tail(&drm_pipe->uif->list_pipe, &pipe->entities);
        }
index 5bb2932..ff6a8fc 100644 (file)
@@ -5,6 +5,7 @@ obj-y += keymaps/
 obj-$(CONFIG_RC_CORE) += rc-core.o
 rc-core-y := rc-main.o rc-ir-raw.o
 rc-core-$(CONFIG_LIRC) += lirc_dev.o
+rc-core-$(CONFIG_MEDIA_CEC_RC) += keymaps/rc-cec.o
 rc-core-$(CONFIG_BPF_LIRC_MODE2) += bpf-lirc.o
 obj-$(CONFIG_IR_NEC_DECODER) += ir-nec-decoder.o
 obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-decoder.o
index b252a1d..cc6662e 100644 (file)
@@ -21,7 +21,6 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
                        rc-behold.o \
                        rc-behold-columbus.o \
                        rc-budget-ci-old.o \
-                       rc-cec.o \
                        rc-cinergy-1400.o \
                        rc-cinergy.o \
                        rc-d680-dmb.o \
index 3e3bd11..068e22a 100644 (file)
@@ -1,5 +1,15 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /* Keytable for the CEC remote control
+ *
+ * This keymap is unusual in that it can't be built as a module,
+ * instead it is registered directly in rc-main.c if CONFIG_MEDIA_CEC_RC
+ * is set. This is because it can be called from drm_dp_cec_set_edid() via
+ * cec_register_adapter() in an asynchronous context, and it is not
+ * allowed to use request_module() to load rc-cec.ko in that case.
+ *
+ * Since this keymap is only used if CONFIG_MEDIA_CEC_RC is set, we
+ * just compile this keymap into the rc-core module and never as a
+ * separate module.
  *
  * Copyright (c) 2015 by Kamil Debski
  */
@@ -152,7 +162,7 @@ static struct rc_map_table cec[] = {
        /* 0x77-0xff: Reserved */
 };
 
-static struct rc_map_list cec_map = {
+struct rc_map_list cec_map = {
        .map = {
                .scan           = cec,
                .size           = ARRAY_SIZE(cec),
@@ -160,19 +170,3 @@ static struct rc_map_list cec_map = {
                .name           = RC_MAP_CEC,
        }
 };
-
-static int __init init_rc_map_cec(void)
-{
-       return rc_map_register(&cec_map);
-}
-
-static void __exit exit_rc_map_cec(void)
-{
-       rc_map_unregister(&cec_map);
-}
-
-module_init(init_rc_map_cec);
-module_exit(exit_rc_map_cec);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Kamil Debski");
index 1fd62c1..8e88dc8 100644 (file)
@@ -2069,6 +2069,9 @@ static int __init rc_core_init(void)
 
        led_trigger_register_simple("rc-feedback", &led_feedback);
        rc_map_register(&empty_map);
+#ifdef CONFIG_MEDIA_CEC_RC
+       rc_map_register(&cec_map);
+#endif
 
        return 0;
 }
@@ -2078,6 +2081,9 @@ static void __exit rc_core_exit(void)
        lirc_dev_exit();
        class_unregister(&rc_class);
        led_trigger_unregister_simple(led_feedback);
+#ifdef CONFIG_MEDIA_CEC_RC
+       rc_map_unregister(&cec_map);
+#endif
        rc_map_unregister(&empty_map);
 }
 
index e488e78..69d5c62 100644 (file)
@@ -56,7 +56,6 @@ MODULE_PARM_DESC(flicker_mode, "Flicker frequency (0 (disabled), " __stringify(5
 
 MODULE_AUTHOR("Steve Miller (STMicroelectronics) <steve.miller@st.com>");
 MODULE_DESCRIPTION("V4L-driver for STMicroelectronics CPiA2 based cameras");
-MODULE_SUPPORTED_DEVICE("video");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(CPIA_VERSION);
 
index 3a2df36..a19a467 100644 (file)
@@ -51,7 +51,6 @@ MODULE_PARM_DESC(index, "Index value for tm6000x capture interface(s).");
 MODULE_DESCRIPTION("ALSA driver module for tm5600/tm6000/tm6010 based TV cards");
 MODULE_AUTHOR("Mauro Carvalho Chehab");
 MODULE_LICENSE("GPL v2");
-MODULE_SUPPORTED_DEVICE("{{Trident,tm5600},{{Trident,tm6000},{{Trident,tm6010}");
 static unsigned int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable debug messages");
index 293a460..4990fa8 100644 (file)
@@ -23,8 +23,6 @@ MODULE_DESCRIPTION("DVB driver extension module for tm5600/6000/6010 based TV ca
 MODULE_AUTHOR("Mauro Carvalho Chehab");
 MODULE_LICENSE("GPL");
 
-MODULE_SUPPORTED_DEVICE("{{Trident, tm5600},{{Trident, tm6000},{{Trident, tm6010}");
-
 static int debug;
 
 module_param(debug, int, 0644);
index b57e94f..333bd30 100644 (file)
@@ -371,7 +371,7 @@ void usbtv_audio_free(struct usbtv *usbtv)
        cancel_work_sync(&usbtv->snd_trigger);
 
        if (usbtv->snd && usbtv->udev) {
-               snd_card_free(usbtv->snd);
+               snd_card_free_when_closed(usbtv->snd);
                usbtv->snd = NULL;
        }
 }
index a03de3f..7605bed 100644 (file)
@@ -1986,19 +1986,20 @@ config MFD_ROHM_BD70528
          charger.
 
 config MFD_ROHM_BD71828
-       tristate "ROHM BD71828 Power Management IC"
+       tristate "ROHM BD71828 and BD71815 Power Management IC"
        depends on I2C=y
        depends on OF
        select REGMAP_I2C
        select REGMAP_IRQ
        select MFD_CORE
        help
-         Select this option to get support for the ROHM BD71828 Power
-         Management IC. BD71828GW is a single-chip power management IC for
-         battery-powered portable devices. The IC integrates 7 buck
-         converters, 7 LDOs, and a 1500 mA single-cell linear charger.
-         Also included is a Coulomb counter, a real-time clock (RTC), and
-         a 32.768 kHz clock gate.
+         Select this option to get support for the ROHM BD71828 and BD71815
+         Power Management ICs. BD71828GW and BD71815AGW are single-chip power
+         management ICs mainly for battery-powered portable devices.
+         The BD71828 integrates 7 buck converters and 7 LDOs. The BD71815
+         has 5 bucks, 7 LDOs, and a boost for driving LEDs. Both ICs provide
+         also a single-cell linear charger, a Coulomb counter, a real-time
+         clock (RTC), GPIOs and a 32.768 kHz clock gate.
 
 config MFD_STM32_LPTIMER
        tristate "Support for STM32 Low-Power Timer"
@@ -2066,6 +2067,24 @@ config MFD_WCD934X
          This driver provides common support WCD934x audio codec and its
          associated Pin Controller, Soundwire Controller and Audio codec.
 
+config MFD_ATC260X
+       tristate
+       select MFD_CORE
+       select REGMAP
+       select REGMAP_IRQ
+
+config MFD_ATC260X_I2C
+       tristate "Actions Semi ATC260x PMICs with I2C"
+       select MFD_ATC260X
+       select REGMAP_I2C
+       depends on I2C
+       help
+         Support for the Actions Semi ATC260x PMICs controlled via I2C.
+
+         This driver provides common support for accessing the ATC2603C
+         and ATC2609A chip variants, additional drivers must be enabled
+         in order to use the functionality of the device.
+
 config MFD_KHADAS_MCU
        tristate "Support for Khadas System control Microcontroller"
        depends on I2C
index bb5e8f2..20b7aeb 100644 (file)
@@ -269,3 +269,6 @@ obj-$(CONFIG_MFD_ACER_A500_EC)      += acer-ec-a500.o
 obj-$(CONFIG_SGI_MFD_IOC3)     += ioc3.o
 obj-$(CONFIG_MFD_SIMPLE_MFD_I2C)       += simple-mfd-i2c.o
 obj-$(CONFIG_MFD_INTEL_M10_BMC)   += intel-m10-bmc.o
+
+obj-$(CONFIG_MFD_ATC260X)      += atc260x-core.o
+obj-$(CONFIG_MFD_ATC260X_I2C)  += atc260x-i2c.o
index a903791..22c0e3d 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/mfd/core.h>
 #include <linux/mfd/abx500.h>
 #include <linux/mfd/abx500/ab8500.h>
-#include <linux/mfd/abx500/ab8500-bm.h>
 #include <linux/mfd/dbx500-prcmu.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -609,14 +608,14 @@ int ab8500_suspend(struct ab8500 *ab8500)
 }
 
 static const struct mfd_cell ab8500_bm_devs[] = {
-       MFD_CELL_OF("ab8500-charger", NULL, &ab8500_bm_data,
-                   sizeof(ab8500_bm_data), 0, "stericsson,ab8500-charger"),
-       MFD_CELL_OF("ab8500-btemp", NULL, &ab8500_bm_data,
-                   sizeof(ab8500_bm_data), 0, "stericsson,ab8500-btemp"),
-       MFD_CELL_OF("ab8500-fg", NULL, &ab8500_bm_data,
-                   sizeof(ab8500_bm_data), 0, "stericsson,ab8500-fg"),
-       MFD_CELL_OF("ab8500-chargalg", NULL, &ab8500_bm_data,
-                   sizeof(ab8500_bm_data), 0, "stericsson,ab8500-chargalg"),
+       MFD_CELL_OF("ab8500-charger", NULL, NULL, 0, 0,
+                   "stericsson,ab8500-charger"),
+       MFD_CELL_OF("ab8500-btemp", NULL, NULL, 0, 0,
+                   "stericsson,ab8500-btemp"),
+       MFD_CELL_OF("ab8500-fg", NULL, NULL, 0, 0,
+                   "stericsson,ab8500-fg"),
+       MFD_CELL_OF("ab8500-chargalg", NULL, NULL, 0, 0,
+                   "stericsson,ab8500-chargalg"),
 };
 
 static const struct mfd_cell ab8500_devs[] = {
index 75f1bc6..ce6fe6d 100644 (file)
@@ -881,11 +881,6 @@ static const char * const wm5102_supplies[] = {
 static const struct mfd_cell wm5102_devs[] = {
        { .name = "arizona-micsupp" },
        { .name = "arizona-gpio" },
-       {
-               .name = "arizona-extcon",
-               .parent_supplies = wm5102_supplies,
-               .num_parent_supplies = 1, /* We only need MICVDD */
-       },
        { .name = "arizona-haptics" },
        { .name = "arizona-pwm" },
        {
@@ -898,11 +893,6 @@ static const struct mfd_cell wm5102_devs[] = {
 static const struct mfd_cell wm5110_devs[] = {
        { .name = "arizona-micsupp" },
        { .name = "arizona-gpio" },
-       {
-               .name = "arizona-extcon",
-               .parent_supplies = wm5102_supplies,
-               .num_parent_supplies = 1, /* We only need MICVDD */
-       },
        { .name = "arizona-haptics" },
        { .name = "arizona-pwm" },
        {
@@ -939,11 +929,6 @@ static const char * const wm8997_supplies[] = {
 static const struct mfd_cell wm8997_devs[] = {
        { .name = "arizona-micsupp" },
        { .name = "arizona-gpio" },
-       {
-               .name = "arizona-extcon",
-               .parent_supplies = wm8997_supplies,
-               .num_parent_supplies = 1, /* We only need MICVDD */
-       },
        { .name = "arizona-haptics" },
        { .name = "arizona-pwm" },
        {
@@ -956,11 +941,6 @@ static const struct mfd_cell wm8997_devs[] = {
 static const struct mfd_cell wm8998_devs[] = {
        { .name = "arizona-micsupp" },
        { .name = "arizona-gpio" },
-       {
-               .name = "arizona-extcon",
-               .parent_supplies = wm5102_supplies,
-               .num_parent_supplies = 1, /* We only need MICVDD */
-       },
        { .name = "arizona-haptics" },
        { .name = "arizona-pwm" },
        {
diff --git a/drivers/mfd/atc260x-core.c b/drivers/mfd/atc260x-core.c
new file mode 100644 (file)
index 0000000..7148ff5
--- /dev/null
@@ -0,0 +1,310 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Core support for ATC260x PMICs
+ *
+ * Copyright (C) 2019 Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ * Copyright (C) 2020 Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
+ */
+
+#include <linux/interrupt.h>
+#include <linux/mfd/atc260x/core.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+
+#define ATC260X_CHIP_REV_MAX   31
+
+struct atc260x_init_regs {
+       unsigned int cmu_devrst;
+       unsigned int cmu_devrst_ints;
+       unsigned int ints_msk;
+       unsigned int pad_en;
+       unsigned int pad_en_extirq;
+};
+
+static void regmap_lock_mutex(void *__mutex)
+{
+       struct mutex *mutex = __mutex;
+
+       /*
+        * Using regmap within an atomic context (e.g. accessing a PMIC when
+        * powering system down) is normally allowed only if the regmap type
+        * is MMIO and the regcache type is either REGCACHE_NONE or
+        * REGCACHE_FLAT. For slow buses like I2C and SPI, the regmap is
+        * internally protected by a mutex which is acquired non-atomically.
+        *
+        * Let's improve this by using a customized locking scheme inspired
+        * from I2C atomic transfer. See i2c_in_atomic_xfer_mode() for a
+        * starting point.
+        */
+       if (system_state > SYSTEM_RUNNING && irqs_disabled())
+               mutex_trylock(mutex);
+       else
+               mutex_lock(mutex);
+}
+
+static void regmap_unlock_mutex(void *__mutex)
+{
+       struct mutex *mutex = __mutex;
+
+       mutex_unlock(mutex);
+}
+
+static const struct regmap_config atc2603c_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 16,
+       .max_register = ATC2603C_SADDR,
+       .cache_type = REGCACHE_NONE,
+};
+
+static const struct regmap_config atc2609a_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 16,
+       .max_register = ATC2609A_SADDR,
+       .cache_type = REGCACHE_NONE,
+};
+
+static const struct regmap_irq atc2603c_regmap_irqs[] = {
+       REGMAP_IRQ_REG(ATC2603C_IRQ_AUDIO,      0, ATC2603C_INTS_MSK_AUDIO),
+       REGMAP_IRQ_REG(ATC2603C_IRQ_OV,         0, ATC2603C_INTS_MSK_OV),
+       REGMAP_IRQ_REG(ATC2603C_IRQ_OC,         0, ATC2603C_INTS_MSK_OC),
+       REGMAP_IRQ_REG(ATC2603C_IRQ_OT,         0, ATC2603C_INTS_MSK_OT),
+       REGMAP_IRQ_REG(ATC2603C_IRQ_UV,         0, ATC2603C_INTS_MSK_UV),
+       REGMAP_IRQ_REG(ATC2603C_IRQ_ALARM,      0, ATC2603C_INTS_MSK_ALARM),
+       REGMAP_IRQ_REG(ATC2603C_IRQ_ONOFF,      0, ATC2603C_INTS_MSK_ONOFF),
+       REGMAP_IRQ_REG(ATC2603C_IRQ_SGPIO,      0, ATC2603C_INTS_MSK_SGPIO),
+       REGMAP_IRQ_REG(ATC2603C_IRQ_IR,         0, ATC2603C_INTS_MSK_IR),
+       REGMAP_IRQ_REG(ATC2603C_IRQ_REMCON,     0, ATC2603C_INTS_MSK_REMCON),
+       REGMAP_IRQ_REG(ATC2603C_IRQ_POWER_IN,   0, ATC2603C_INTS_MSK_POWERIN),
+};
+
+static const struct regmap_irq atc2609a_regmap_irqs[] = {
+       REGMAP_IRQ_REG(ATC2609A_IRQ_AUDIO,      0, ATC2609A_INTS_MSK_AUDIO),
+       REGMAP_IRQ_REG(ATC2609A_IRQ_OV,         0, ATC2609A_INTS_MSK_OV),
+       REGMAP_IRQ_REG(ATC2609A_IRQ_OC,         0, ATC2609A_INTS_MSK_OC),
+       REGMAP_IRQ_REG(ATC2609A_IRQ_OT,         0, ATC2609A_INTS_MSK_OT),
+       REGMAP_IRQ_REG(ATC2609A_IRQ_UV,         0, ATC2609A_INTS_MSK_UV),
+       REGMAP_IRQ_REG(ATC2609A_IRQ_ALARM,      0, ATC2609A_INTS_MSK_ALARM),
+       REGMAP_IRQ_REG(ATC2609A_IRQ_ONOFF,      0, ATC2609A_INTS_MSK_ONOFF),
+       REGMAP_IRQ_REG(ATC2609A_IRQ_WKUP,       0, ATC2609A_INTS_MSK_WKUP),
+       REGMAP_IRQ_REG(ATC2609A_IRQ_IR,         0, ATC2609A_INTS_MSK_IR),
+       REGMAP_IRQ_REG(ATC2609A_IRQ_REMCON,     0, ATC2609A_INTS_MSK_REMCON),
+       REGMAP_IRQ_REG(ATC2609A_IRQ_POWER_IN,   0, ATC2609A_INTS_MSK_POWERIN),
+};
+
+static const struct regmap_irq_chip atc2603c_regmap_irq_chip = {
+       .name = "atc2603c",
+       .irqs = atc2603c_regmap_irqs,
+       .num_irqs = ARRAY_SIZE(atc2603c_regmap_irqs),
+       .num_regs = 1,
+       .status_base = ATC2603C_INTS_PD,
+       .mask_base = ATC2603C_INTS_MSK,
+       .mask_invert = true,
+};
+
+static const struct regmap_irq_chip atc2609a_regmap_irq_chip = {
+       .name = "atc2609a",
+       .irqs = atc2609a_regmap_irqs,
+       .num_irqs = ARRAY_SIZE(atc2609a_regmap_irqs),
+       .num_regs = 1,
+       .status_base = ATC2609A_INTS_PD,
+       .mask_base = ATC2609A_INTS_MSK,
+       .mask_invert = true,
+};
+
+static const struct resource atc2603c_onkey_resources[] = {
+       DEFINE_RES_IRQ(ATC2603C_IRQ_ONOFF),
+};
+
+static const struct resource atc2609a_onkey_resources[] = {
+       DEFINE_RES_IRQ(ATC2609A_IRQ_ONOFF),
+};
+
+static const struct mfd_cell atc2603c_mfd_cells[] = {
+       { .name = "atc260x-regulator" },
+       { .name = "atc260x-pwrc" },
+       {
+               .name = "atc260x-onkey",
+               .num_resources = ARRAY_SIZE(atc2603c_onkey_resources),
+               .resources = atc2603c_onkey_resources,
+       },
+};
+
+static const struct mfd_cell atc2609a_mfd_cells[] = {
+       { .name = "atc260x-regulator" },
+       { .name = "atc260x-pwrc" },
+       {
+               .name = "atc260x-onkey",
+               .num_resources = ARRAY_SIZE(atc2609a_onkey_resources),
+               .resources = atc2609a_onkey_resources,
+       },
+};
+
+static const struct atc260x_init_regs atc2603c_init_regs = {
+       .cmu_devrst = ATC2603C_CMU_DEVRST,
+       .cmu_devrst_ints = ATC2603C_CMU_DEVRST_INTS,
+       .ints_msk = ATC2603C_INTS_MSK,
+       .pad_en = ATC2603C_PAD_EN,
+       .pad_en_extirq = ATC2603C_PAD_EN_EXTIRQ,
+};
+
+static const struct atc260x_init_regs atc2609a_init_regs = {
+       .cmu_devrst = ATC2609A_CMU_DEVRST,
+       .cmu_devrst_ints = ATC2609A_CMU_DEVRST_INTS,
+       .ints_msk = ATC2609A_INTS_MSK,
+       .pad_en = ATC2609A_PAD_EN,
+       .pad_en_extirq = ATC2609A_PAD_EN_EXTIRQ,
+};
+
+static void atc260x_cmu_reset(struct atc260x *atc260x)
+{
+       const struct atc260x_init_regs *regs = atc260x->init_regs;
+
+       /* Assert reset */
+       regmap_update_bits(atc260x->regmap, regs->cmu_devrst,
+                          regs->cmu_devrst_ints, ~regs->cmu_devrst_ints);
+
+       /* De-assert reset */
+       regmap_update_bits(atc260x->regmap, regs->cmu_devrst,
+                          regs->cmu_devrst_ints, regs->cmu_devrst_ints);
+}
+
+static void atc260x_dev_init(struct atc260x *atc260x)
+{
+       const struct atc260x_init_regs *regs = atc260x->init_regs;
+
+       /* Initialize interrupt block */
+       atc260x_cmu_reset(atc260x);
+
+       /* Disable all interrupt sources */
+       regmap_write(atc260x->regmap, regs->ints_msk, 0);
+
+       /* Enable EXTIRQ pad */
+       regmap_update_bits(atc260x->regmap, regs->pad_en,
+                          regs->pad_en_extirq, regs->pad_en_extirq);
+}
+
+/**
+ * atc260x_match_device(): Setup ATC260x variant related fields
+ *
+ * @atc260x: ATC260x device to setup (.dev field must be set)
+ * @regmap_cfg: regmap config associated with this ATC260x device
+ *
+ * This lets the ATC260x core configure the MFD cells and register maps
+ * for later use.
+ */
+int atc260x_match_device(struct atc260x *atc260x, struct regmap_config *regmap_cfg)
+{
+       struct device *dev = atc260x->dev;
+       const void *of_data;
+
+       of_data = of_device_get_match_data(dev);
+       if (!of_data)
+               return -ENODEV;
+
+       atc260x->ic_type = (unsigned long)of_data;
+
+       switch (atc260x->ic_type) {
+       case ATC2603C:
+               *regmap_cfg = atc2603c_regmap_config;
+               atc260x->regmap_irq_chip = &atc2603c_regmap_irq_chip;
+               atc260x->cells = atc2603c_mfd_cells;
+               atc260x->nr_cells = ARRAY_SIZE(atc2603c_mfd_cells);
+               atc260x->type_name = "atc2603c";
+               atc260x->rev_reg = ATC2603C_CHIP_VER;
+               atc260x->init_regs = &atc2603c_init_regs;
+               break;
+       case ATC2609A:
+               *regmap_cfg = atc2609a_regmap_config;
+               atc260x->regmap_irq_chip = &atc2609a_regmap_irq_chip;
+               atc260x->cells = atc2609a_mfd_cells;
+               atc260x->nr_cells = ARRAY_SIZE(atc2609a_mfd_cells);
+               atc260x->type_name = "atc2609a";
+               atc260x->rev_reg = ATC2609A_CHIP_VER;
+               atc260x->init_regs = &atc2609a_init_regs;
+               break;
+       default:
+               dev_err(dev, "Unsupported ATC260x device type: %u\n",
+                       atc260x->ic_type);
+               return -EINVAL;
+       }
+
+       atc260x->regmap_mutex = devm_kzalloc(dev, sizeof(*atc260x->regmap_mutex),
+                                            GFP_KERNEL);
+       if (!atc260x->regmap_mutex)
+               return -ENOMEM;
+
+       mutex_init(atc260x->regmap_mutex);
+
+       regmap_cfg->lock = regmap_lock_mutex,
+       regmap_cfg->unlock = regmap_unlock_mutex,
+       regmap_cfg->lock_arg = atc260x->regmap_mutex;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(atc260x_match_device);
+
+/**
+ * atc260x_device_probe(): Probe a configured ATC260x device
+ *
+ * @atc260x: ATC260x device to probe (must be configured)
+ *
+ * This function lets the ATC260x core register the ATC260x MFD devices
+ * and IRQCHIP. The ATC260x device passed in must be fully configured
+ * with atc260x_match_device, its IRQ set, and regmap created.
+ */
+int atc260x_device_probe(struct atc260x *atc260x)
+{
+       struct device *dev = atc260x->dev;
+       unsigned int chip_rev;
+       int ret;
+
+       if (!atc260x->irq) {
+               dev_err(dev, "No interrupt support\n");
+               return -EINVAL;
+       }
+
+       /* Initialize the hardware */
+       atc260x_dev_init(atc260x);
+
+       ret = regmap_read(atc260x->regmap, atc260x->rev_reg, &chip_rev);
+       if (ret) {
+               dev_err(dev, "Failed to get chip revision\n");
+               return ret;
+       }
+
+       if (chip_rev > ATC260X_CHIP_REV_MAX) {
+               dev_err(dev, "Unknown chip revision: %u\n", chip_rev);
+               return -EINVAL;
+       }
+
+       atc260x->ic_ver = __ffs(chip_rev + 1U);
+
+       dev_info(dev, "Detected chip type %s rev.%c\n",
+                atc260x->type_name, 'A' + atc260x->ic_ver);
+
+       ret = devm_regmap_add_irq_chip(dev, atc260x->regmap, atc260x->irq, IRQF_ONESHOT,
+                                      -1, atc260x->regmap_irq_chip, &atc260x->irq_data);
+       if (ret) {
+               dev_err(dev, "Failed to add IRQ chip: %d\n", ret);
+               return ret;
+       }
+
+       ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
+                                  atc260x->cells, atc260x->nr_cells, NULL, 0,
+                                  regmap_irq_get_domain(atc260x->irq_data));
+       if (ret) {
+               dev_err(dev, "Failed to add child devices: %d\n", ret);
+               regmap_del_irq_chip(atc260x->irq, atc260x->irq_data);
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(atc260x_device_probe);
+
+MODULE_DESCRIPTION("ATC260x PMICs Core support");
+MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>");
+MODULE_AUTHOR("Cristian Ciocaltea <cristian.ciocaltea@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/atc260x-i2c.c b/drivers/mfd/atc260x-i2c.c
new file mode 100644 (file)
index 0000000..3620057
--- /dev/null
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * I2C bus interface for ATC260x PMICs
+ *
+ * Copyright (C) 2019 Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ * Copyright (C) 2020 Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
+ */
+
+#include <linux/i2c.h>
+#include <linux/mfd/atc260x/core.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+
+static int atc260x_i2c_probe(struct i2c_client *client,
+                            const struct i2c_device_id *id)
+{
+       struct atc260x *atc260x;
+       struct regmap_config regmap_cfg;
+       int ret;
+
+       atc260x = devm_kzalloc(&client->dev, sizeof(*atc260x), GFP_KERNEL);
+       if (!atc260x)
+               return -ENOMEM;
+
+       atc260x->dev = &client->dev;
+       atc260x->irq = client->irq;
+
+       ret = atc260x_match_device(atc260x, &regmap_cfg);
+       if (ret)
+               return ret;
+
+       i2c_set_clientdata(client, atc260x);
+
+       atc260x->regmap = devm_regmap_init_i2c(client, &regmap_cfg);
+       if (IS_ERR(atc260x->regmap)) {
+               ret = PTR_ERR(atc260x->regmap);
+               dev_err(&client->dev, "failed to init regmap: %d\n", ret);
+               return ret;
+       }
+
+       return atc260x_device_probe(atc260x);
+}
+
+const struct of_device_id atc260x_i2c_of_match[] = {
+       { .compatible = "actions,atc2603c", .data = (void *)ATC2603C },
+       { .compatible = "actions,atc2609a", .data = (void *)ATC2609A },
+       { }
+};
+MODULE_DEVICE_TABLE(of, atc260x_i2c_of_match);
+
+static struct i2c_driver atc260x_i2c_driver = {
+       .driver = {
+               .name = "atc260x",
+               .of_match_table = of_match_ptr(atc260x_i2c_of_match),
+       },
+       .probe = atc260x_i2c_probe,
+};
+module_i2c_driver(atc260x_i2c_driver);
+
+MODULE_DESCRIPTION("ATC260x PMICs I2C bus interface");
+MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>");
+MODULE_AUTHOR("Cristian Ciocaltea <cristian.ciocaltea@gmail.com>");
+MODULE_LICENSE("GPL");
index 744b230..dd7eb61 100644 (file)
@@ -49,10 +49,14 @@ enum pmt_quirks {
 
        /* Use shift instead of mask to read discovery table offset */
        PMT_QUIRK_TABLE_SHIFT   = BIT(2),
+
+       /* DVSEC not present (provided in driver data) */
+       PMT_QUIRK_NO_DVSEC      = BIT(3),
 };
 
 struct pmt_platform_info {
        unsigned long quirks;
+       struct intel_dvsec_header **capabilities;
 };
 
 static const struct pmt_platform_info tgl_info = {
@@ -60,6 +64,26 @@ static const struct pmt_platform_info tgl_info = {
                  PMT_QUIRK_TABLE_SHIFT,
 };
 
+/* DG1 Platform with DVSEC quirk*/
+static struct intel_dvsec_header dg1_telemetry = {
+       .length = 0x10,
+       .id = 2,
+       .num_entries = 1,
+       .entry_size = 3,
+       .tbir = 0,
+       .offset = 0x466000,
+};
+
+static struct intel_dvsec_header *dg1_capabilities[] = {
+       &dg1_telemetry,
+       NULL
+};
+
+static const struct pmt_platform_info dg1_info = {
+       .quirks = PMT_QUIRK_NO_DVSEC,
+       .capabilities = dg1_capabilities,
+};
+
 static int pmt_add_dev(struct pci_dev *pdev, struct intel_dvsec_header *header,
                       unsigned long quirks)
 {
@@ -79,19 +103,18 @@ static int pmt_add_dev(struct pci_dev *pdev, struct intel_dvsec_header *header,
        case DVSEC_INTEL_ID_WATCHER:
                if (quirks & PMT_QUIRK_NO_WATCHER) {
                        dev_info(dev, "Watcher not supported\n");
-                       return 0;
+                       return -EINVAL;
                }
                name = "pmt_watcher";
                break;
        case DVSEC_INTEL_ID_CRASHLOG:
                if (quirks & PMT_QUIRK_NO_CRASHLOG) {
                        dev_info(dev, "Crashlog not supported\n");
-                       return 0;
+                       return -EINVAL;
                }
                name = "pmt_crashlog";
                break;
        default:
-               dev_err(dev, "Unrecognized PMT capability: %d\n", id);
                return -EINVAL;
        }
 
@@ -148,41 +171,54 @@ static int pmt_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        if (info)
                quirks = info->quirks;
 
-       do {
-               struct intel_dvsec_header header;
-               u32 table;
-               u16 vid;
-
-               pos = pci_find_next_ext_capability(pdev, pos, PCI_EXT_CAP_ID_DVSEC);
-               if (!pos)
-                       break;
-
-               pci_read_config_word(pdev, pos + PCI_DVSEC_HEADER1, &vid);
-               if (vid != PCI_VENDOR_ID_INTEL)
-                       continue;
-
-               pci_read_config_word(pdev, pos + PCI_DVSEC_HEADER2,
-                                    &header.id);
-               pci_read_config_byte(pdev, pos + INTEL_DVSEC_ENTRIES,
-                                    &header.num_entries);
-               pci_read_config_byte(pdev, pos + INTEL_DVSEC_SIZE,
-                                    &header.entry_size);
-               pci_read_config_dword(pdev, pos + INTEL_DVSEC_TABLE,
-                                     &table);
-
-               header.tbir = INTEL_DVSEC_TABLE_BAR(table);
-               header.offset = INTEL_DVSEC_TABLE_OFFSET(table);
-
-               ret = pmt_add_dev(pdev, &header, quirks);
-               if (ret) {
-                       dev_warn(&pdev->dev,
-                                "Failed to add device for DVSEC id %d\n",
-                                header.id);
-                       continue;
-               }
+       if (info && (info->quirks & PMT_QUIRK_NO_DVSEC)) {
+               struct intel_dvsec_header **header;
+
+               header = info->capabilities;
+               while (*header) {
+                       ret = pmt_add_dev(pdev, *header, quirks);
+                       if (ret)
+                               dev_warn(&pdev->dev,
+                                        "Failed to add device for DVSEC id %d\n",
+                                        (*header)->id);
+                       else
+                               found_devices = true;
 
-               found_devices = true;
-       } while (true);
+                       ++header;
+               }
+       } else {
+               do {
+                       struct intel_dvsec_header header;
+                       u32 table;
+                       u16 vid;
+
+                       pos = pci_find_next_ext_capability(pdev, pos, PCI_EXT_CAP_ID_DVSEC);
+                       if (!pos)
+                               break;
+
+                       pci_read_config_word(pdev, pos + PCI_DVSEC_HEADER1, &vid);
+                       if (vid != PCI_VENDOR_ID_INTEL)
+                               continue;
+
+                       pci_read_config_word(pdev, pos + PCI_DVSEC_HEADER2,
+                                            &header.id);
+                       pci_read_config_byte(pdev, pos + INTEL_DVSEC_ENTRIES,
+                                            &header.num_entries);
+                       pci_read_config_byte(pdev, pos + INTEL_DVSEC_SIZE,
+                                            &header.entry_size);
+                       pci_read_config_dword(pdev, pos + INTEL_DVSEC_TABLE,
+                                             &table);
+
+                       header.tbir = INTEL_DVSEC_TABLE_BAR(table);
+                       header.offset = INTEL_DVSEC_TABLE_OFFSET(table);
+
+                       ret = pmt_add_dev(pdev, &header, quirks);
+                       if (ret)
+                               continue;
+
+                       found_devices = true;
+               } while (true);
+       }
 
        if (!found_devices)
                return -ENODEV;
@@ -200,10 +236,12 @@ static void pmt_pci_remove(struct pci_dev *pdev)
 }
 
 #define PCI_DEVICE_ID_INTEL_PMT_ADL    0x467d
+#define PCI_DEVICE_ID_INTEL_PMT_DG1    0x490e
 #define PCI_DEVICE_ID_INTEL_PMT_OOBMSM 0x09a7
 #define PCI_DEVICE_ID_INTEL_PMT_TGL    0x9a0d
 static const struct pci_device_id pmt_pci_ids[] = {
        { PCI_DEVICE_DATA(INTEL, PMT_ADL, &tgl_info) },
+       { PCI_DEVICE_DATA(INTEL, PMT_DG1, &dg1_info) },
        { PCI_DEVICE_DATA(INTEL, PMT_OOBMSM, NULL) },
        { PCI_DEVICE_DATA(INTEL, PMT_TGL, &tgl_info) },
        { }
index 210261d..714d9fc 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Copyright (C) 2019 ROHM Semiconductors
 //
-// ROHM BD71828 PMIC driver
+// ROHM BD71828/BD71815 PMIC driver
 
 #include <linux/gpio_keys.h>
 #include <linux/i2c.h>
@@ -11,7 +11,9 @@
 #include <linux/ioport.h>
 #include <linux/irq.h>
 #include <linux/mfd/core.h>
+#include <linux/mfd/rohm-bd71815.h>
 #include <linux/mfd/rohm-bd71828.h>
+#include <linux/mfd/rohm-generic.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/regmap.h>
@@ -29,12 +31,84 @@ static struct gpio_keys_platform_data bd71828_powerkey_data = {
        .name = "bd71828-pwrkey",
 };
 
-static const struct resource rtc_irqs[] = {
+static const struct resource bd71815_rtc_irqs[] = {
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC0, "bd71815-rtc-alm-0"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC1, "bd71815-rtc-alm-1"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC2, "bd71815-rtc-alm-2"),
+};
+
+static const struct resource bd71828_rtc_irqs[] = {
        DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC0, "bd71828-rtc-alm-0"),
        DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC1, "bd71828-rtc-alm-1"),
        DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC2, "bd71828-rtc-alm-2"),
 };
 
+static struct resource bd71815_power_irqs[] = {
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_RMV, "bd71815-dcin-rmv"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_CLPS_OUT, "bd71815-clps-out"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_CLPS_IN, "bd71815-clps-in"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_OVP_RES, "bd71815-dcin-ovp-res"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_OVP_DET, "bd71815-dcin-ovp-det"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_MON_RES, "bd71815-dcin-mon-res"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_MON_DET, "bd71815-dcin-mon-det"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_UV_RES, "bd71815-vsys-uv-res"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_UV_DET, "bd71815-vsys-uv-det"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_LOW_RES, "bd71815-vsys-low-res"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_LOW_DET, "bd71815-vsys-low-det"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_MON_RES, "bd71815-vsys-mon-res"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_MON_RES, "bd71815-vsys-mon-det"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_WDG_TEMP, "bd71815-chg-wdg-temp"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_WDG_TIME, "bd71815-chg-wdg"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_RECHARGE_RES, "bd71815-rechg-res"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_RECHARGE_DET, "bd71815-rechg-det"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_RANGED_TEMP_TRANSITION, "bd71815-ranged-temp-transit"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_STATE_TRANSITION, "bd71815-chg-state-change"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_TEMP_NORMAL, "bd71815-bat-temp-normal"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_TEMP_ERANGE, "bd71815-bat-temp-erange"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_REMOVED, "bd71815-bat-rmv"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_DETECTED, "bd71815-bat-det"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_THERM_REMOVED, "bd71815-therm-rmv"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_THERM_DETECTED, "bd71815-therm-det"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_DEAD, "bd71815-bat-dead"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_SHORTC_RES, "bd71815-bat-short-res"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_SHORTC_DET, "bd71815-bat-short-det"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_LOW_VOLT_RES, "bd71815-bat-low-res"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_LOW_VOLT_DET, "bd71815-bat-low-det"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_VOLT_RES, "bd71815-bat-over-res"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_VOLT_DET, "bd71815-bat-over-det"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_MON_RES, "bd71815-bat-mon-res"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_MON_DET, "bd71815-bat-mon-det"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_CC_MON1, "bd71815-bat-cc-mon1"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_CC_MON2, "bd71815-bat-cc-mon2"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_CC_MON3, "bd71815-bat-cc-mon3"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_1_RES, "bd71815-bat-oc1-res"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_1_DET, "bd71815-bat-oc1-det"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_2_RES, "bd71815-bat-oc2-res"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_2_DET, "bd71815-bat-oc2-det"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_3_RES, "bd71815-bat-oc3-res"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_3_DET, "bd71815-bat-oc3-det"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_LOW_RES, "bd71815-bat-low-res"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_LOW_DET, "bd71815-bat-low-det"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_HI_RES, "bd71815-bat-hi-res"),
+       DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_HI_DET, "bd71815-bat-hi-det"),
+};
+
+static struct mfd_cell bd71815_mfd_cells[] = {
+       { .name = "bd71815-pmic", },
+       { .name = "bd71815-clk", },
+       { .name = "bd71815-gpo", },
+       {
+               .name = "bd71815-power",
+               .num_resources = ARRAY_SIZE(bd71815_power_irqs),
+               .resources = &bd71815_power_irqs[0],
+       },
+       {
+               .name = "bd71815-rtc",
+               .num_resources = ARRAY_SIZE(bd71815_rtc_irqs),
+               .resources = &bd71815_rtc_irqs[0],
+       },
+};
+
 static struct mfd_cell bd71828_mfd_cells[] = {
        { .name = "bd71828-pmic", },
        { .name = "bd71828-gpio", },
@@ -47,8 +121,8 @@ static struct mfd_cell bd71828_mfd_cells[] = {
        { .name = "bd71827-power", },
        {
                .name = "bd71828-rtc",
-               .resources = rtc_irqs,
-               .num_resources = ARRAY_SIZE(rtc_irqs),
+               .resources = bd71828_rtc_irqs,
+               .num_resources = ARRAY_SIZE(bd71828_rtc_irqs),
        }, {
                .name = "gpio-keys",
                .platform_data = &bd71828_powerkey_data,
@@ -56,7 +130,35 @@ static struct mfd_cell bd71828_mfd_cells[] = {
        },
 };
 
-static const struct regmap_range volatile_ranges[] = {
+static const struct regmap_range bd71815_volatile_ranges[] = {
+       {
+               .range_min = BD71815_REG_SEC,
+               .range_max = BD71815_REG_YEAR,
+       }, {
+               .range_min = BD71815_REG_CONF,
+               .range_max = BD71815_REG_BAT_TEMP,
+       }, {
+               .range_min = BD71815_REG_VM_IBAT_U,
+               .range_max = BD71815_REG_CC_CTRL,
+       }, {
+               .range_min = BD71815_REG_CC_STAT,
+               .range_max = BD71815_REG_CC_CURCD_L,
+       }, {
+               .range_min = BD71815_REG_VM_BTMP_MON,
+               .range_max = BD71815_REG_VM_BTMP_MON,
+       }, {
+               .range_min = BD71815_REG_INT_STAT,
+               .range_max = BD71815_REG_INT_UPDATE,
+       }, {
+               .range_min = BD71815_REG_VM_VSYS_U,
+               .range_max = BD71815_REG_REX_CTRL_1,
+       }, {
+               .range_min = BD71815_REG_FULL_CCNTD_3,
+               .range_max = BD71815_REG_CCNTD_CHG_2,
+       },
+};
+
+static const struct regmap_range bd71828_volatile_ranges[] = {
        {
                .range_min = BD71828_REG_PS_CTRL_1,
                .range_max = BD71828_REG_PS_CTRL_1,
@@ -80,15 +182,28 @@ static const struct regmap_range volatile_ranges[] = {
        },
 };
 
-static const struct regmap_access_table volatile_regs = {
-       .yes_ranges = &volatile_ranges[0],
-       .n_yes_ranges = ARRAY_SIZE(volatile_ranges),
+static const struct regmap_access_table bd71815_volatile_regs = {
+       .yes_ranges = &bd71815_volatile_ranges[0],
+       .n_yes_ranges = ARRAY_SIZE(bd71815_volatile_ranges),
+};
+
+static const struct regmap_access_table bd71828_volatile_regs = {
+       .yes_ranges = &bd71828_volatile_ranges[0],
+       .n_yes_ranges = ARRAY_SIZE(bd71828_volatile_ranges),
+};
+
+static const struct regmap_config bd71815_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .volatile_table = &bd71815_volatile_regs,
+       .max_register = BD71815_MAX_REGISTER - 1,
+       .cache_type = REGCACHE_RBTREE,
 };
 
-static struct regmap_config bd71828_regmap = {
+static const struct regmap_config bd71828_regmap = {
        .reg_bits = 8,
        .val_bits = 8,
-       .volatile_table = &volatile_regs,
+       .volatile_table = &bd71828_volatile_regs,
        .max_register = BD71828_MAX_REGISTER,
        .cache_type = REGCACHE_RBTREE,
 };
@@ -96,7 +211,7 @@ static struct regmap_config bd71828_regmap = {
 /*
  * Mapping of main IRQ register bits to sub-IRQ register offsets so that we can
  * access corect sub-IRQ registers based on bits that are set in main IRQ
- * register.
+ * register. BD71815 and BD71828 have same sub-register-block offests.
  */
 
 static unsigned int bit0_offsets[] = {11};             /* RTC IRQ */
@@ -108,7 +223,7 @@ static unsigned int bit5_offsets[] = {3};           /* VSYS IRQ */
 static unsigned int bit6_offsets[] = {1, 2};           /* DCIN IRQ */
 static unsigned int bit7_offsets[] = {0};              /* BUCK IRQ */
 
-static struct regmap_irq_sub_irq_map bd71828_sub_irq_offsets[] = {
+static struct regmap_irq_sub_irq_map bd718xx_sub_irq_offsets[] = {
        REGMAP_IRQ_MAIN_REG_OFFSET(bit0_offsets),
        REGMAP_IRQ_MAIN_REG_OFFSET(bit1_offsets),
        REGMAP_IRQ_MAIN_REG_OFFSET(bit2_offsets),
@@ -119,6 +234,88 @@ static struct regmap_irq_sub_irq_map bd71828_sub_irq_offsets[] = {
        REGMAP_IRQ_MAIN_REG_OFFSET(bit7_offsets),
 };
 
+static const struct regmap_irq bd71815_irqs[] = {
+       REGMAP_IRQ_REG(BD71815_INT_BUCK1_OCP, 0, BD71815_INT_BUCK1_OCP_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_BUCK2_OCP, 0, BD71815_INT_BUCK2_OCP_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_BUCK3_OCP, 0, BD71815_INT_BUCK3_OCP_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_BUCK4_OCP, 0, BD71815_INT_BUCK4_OCP_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_BUCK5_OCP, 0, BD71815_INT_BUCK5_OCP_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_LED_OVP, 0, BD71815_INT_LED_OVP_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_LED_OCP, 0, BD71815_INT_LED_OCP_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_LED_SCP, 0, BD71815_INT_LED_SCP_MASK),
+       /* DCIN1 interrupts */
+       REGMAP_IRQ_REG(BD71815_INT_DCIN_RMV, 1, BD71815_INT_DCIN_RMV_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_CLPS_OUT, 1, BD71815_INT_CLPS_OUT_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_CLPS_IN, 1, BD71815_INT_CLPS_IN_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_DCIN_OVP_RES, 1, BD71815_INT_DCIN_OVP_RES_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_DCIN_OVP_DET, 1, BD71815_INT_DCIN_OVP_DET_MASK),
+       /* DCIN2 interrupts */
+       REGMAP_IRQ_REG(BD71815_INT_DCIN_MON_RES, 2, BD71815_INT_DCIN_MON_RES_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_DCIN_MON_DET, 2, BD71815_INT_DCIN_MON_DET_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_WDOG, 2, BD71815_INT_WDOG_MASK),
+       /* Vsys */
+       REGMAP_IRQ_REG(BD71815_INT_VSYS_UV_RES, 3, BD71815_INT_VSYS_UV_RES_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_VSYS_UV_DET, 3, BD71815_INT_VSYS_UV_DET_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_VSYS_LOW_RES, 3, BD71815_INT_VSYS_LOW_RES_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_VSYS_LOW_DET, 3, BD71815_INT_VSYS_LOW_DET_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_VSYS_MON_RES, 3, BD71815_INT_VSYS_MON_RES_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_VSYS_MON_DET, 3, BD71815_INT_VSYS_MON_DET_MASK),
+       /* Charger */
+       REGMAP_IRQ_REG(BD71815_INT_CHG_WDG_TEMP, 4, BD71815_INT_CHG_WDG_TEMP_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_CHG_WDG_TIME, 4, BD71815_INT_CHG_WDG_TIME_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_CHG_RECHARGE_RES, 4, BD71815_INT_CHG_RECHARGE_RES_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_CHG_RECHARGE_DET, 4, BD71815_INT_CHG_RECHARGE_DET_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_CHG_RANGED_TEMP_TRANSITION, 4,
+                      BD71815_INT_CHG_RANGED_TEMP_TRANSITION_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_CHG_STATE_TRANSITION, 4, BD71815_INT_CHG_STATE_TRANSITION_MASK),
+       /* Battery */
+       REGMAP_IRQ_REG(BD71815_INT_BAT_TEMP_NORMAL, 5, BD71815_INT_BAT_TEMP_NORMAL_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_BAT_TEMP_ERANGE, 5, BD71815_INT_BAT_TEMP_ERANGE_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_BAT_REMOVED, 5, BD71815_INT_BAT_REMOVED_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_BAT_DETECTED, 5, BD71815_INT_BAT_DETECTED_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_THERM_REMOVED, 5, BD71815_INT_THERM_REMOVED_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_THERM_DETECTED, 5, BD71815_INT_THERM_DETECTED_MASK),
+       /* Battery Mon 1 */
+       REGMAP_IRQ_REG(BD71815_INT_BAT_DEAD, 6, BD71815_INT_BAT_DEAD_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_BAT_SHORTC_RES, 6, BD71815_INT_BAT_SHORTC_RES_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_BAT_SHORTC_DET, 6, BD71815_INT_BAT_SHORTC_DET_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_BAT_LOW_VOLT_RES, 6, BD71815_INT_BAT_LOW_VOLT_RES_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_BAT_LOW_VOLT_DET, 6, BD71815_INT_BAT_LOW_VOLT_DET_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_VOLT_RES, 6, BD71815_INT_BAT_OVER_VOLT_RES_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_VOLT_DET, 6, BD71815_INT_BAT_OVER_VOLT_DET_MASK),
+       /* Battery Mon 2 */
+       REGMAP_IRQ_REG(BD71815_INT_BAT_MON_RES, 7, BD71815_INT_BAT_MON_RES_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_BAT_MON_DET, 7, BD71815_INT_BAT_MON_DET_MASK),
+       /* Battery Mon 3 (Coulomb counter) */
+       REGMAP_IRQ_REG(BD71815_INT_BAT_CC_MON1, 8, BD71815_INT_BAT_CC_MON1_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_BAT_CC_MON2, 8, BD71815_INT_BAT_CC_MON2_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_BAT_CC_MON3, 8, BD71815_INT_BAT_CC_MON3_MASK),
+       /* Battery Mon 4 */
+       REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_1_RES, 9, BD71815_INT_BAT_OVER_CURR_1_RES_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_1_DET, 9, BD71815_INT_BAT_OVER_CURR_1_DET_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_2_RES, 9, BD71815_INT_BAT_OVER_CURR_2_RES_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_2_DET, 9, BD71815_INT_BAT_OVER_CURR_2_DET_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_3_RES, 9, BD71815_INT_BAT_OVER_CURR_3_RES_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_3_DET, 9, BD71815_INT_BAT_OVER_CURR_3_DET_MASK),
+       /* Temperature */
+       REGMAP_IRQ_REG(BD71815_INT_TEMP_BAT_LOW_RES, 10, BD71815_INT_TEMP_BAT_LOW_RES_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_TEMP_BAT_LOW_DET, 10, BD71815_INT_TEMP_BAT_LOW_DET_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_TEMP_BAT_HI_RES, 10, BD71815_INT_TEMP_BAT_HI_RES_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_TEMP_BAT_HI_DET, 10, BD71815_INT_TEMP_BAT_HI_DET_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_TEMP_CHIP_OVER_125_RES, 10,
+                      BD71815_INT_TEMP_CHIP_OVER_125_RES_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_TEMP_CHIP_OVER_125_DET, 10,
+                      BD71815_INT_TEMP_CHIP_OVER_125_DET_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_TEMP_CHIP_OVER_VF_RES, 10,
+                      BD71815_INT_TEMP_CHIP_OVER_VF_RES_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_TEMP_CHIP_OVER_VF_DET, 10,
+                      BD71815_INT_TEMP_CHIP_OVER_VF_DET_MASK),
+       /* RTC Alarm */
+       REGMAP_IRQ_REG(BD71815_INT_RTC0, 11, BD71815_INT_RTC0_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_RTC1, 11, BD71815_INT_RTC1_MASK),
+       REGMAP_IRQ_REG(BD71815_INT_RTC2, 11, BD71815_INT_RTC2_MASK),
+};
+
 static struct regmap_irq bd71828_irqs[] = {
        REGMAP_IRQ_REG(BD71828_INT_BUCK1_OCP, 0, BD71828_INT_BUCK1_OCP_MASK),
        REGMAP_IRQ_REG(BD71828_INT_BUCK2_OCP, 0, BD71828_INT_BUCK2_OCP_MASK),
@@ -134,10 +331,8 @@ static struct regmap_irq bd71828_irqs[] = {
        REGMAP_IRQ_REG(BD71828_INT_CLPS_OUT, 1, BD71828_INT_CLPS_OUT_MASK),
        REGMAP_IRQ_REG(BD71828_INT_CLPS_IN, 1, BD71828_INT_CLPS_IN_MASK),
        /* DCIN2 interrupts */
-       REGMAP_IRQ_REG(BD71828_INT_DCIN_MON_RES, 2,
-                      BD71828_INT_DCIN_MON_RES_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_DCIN_MON_DET, 2,
-                      BD71828_INT_DCIN_MON_DET_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_DCIN_MON_RES, 2, BD71828_INT_DCIN_MON_RES_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_DCIN_MON_DET, 2, BD71828_INT_DCIN_MON_DET_MASK),
        REGMAP_IRQ_REG(BD71828_INT_LONGPUSH, 2, BD71828_INT_LONGPUSH_MASK),
        REGMAP_IRQ_REG(BD71828_INT_MIDPUSH, 2, BD71828_INT_MIDPUSH_MASK),
        REGMAP_IRQ_REG(BD71828_INT_SHORTPUSH, 2, BD71828_INT_SHORTPUSH_MASK),
@@ -145,102 +340,59 @@ static struct regmap_irq bd71828_irqs[] = {
        REGMAP_IRQ_REG(BD71828_INT_WDOG, 2, BD71828_INT_WDOG_MASK),
        REGMAP_IRQ_REG(BD71828_INT_SWRESET, 2, BD71828_INT_SWRESET_MASK),
        /* Vsys */
-       REGMAP_IRQ_REG(BD71828_INT_VSYS_UV_RES, 3,
-                      BD71828_INT_VSYS_UV_RES_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_VSYS_UV_DET, 3,
-                      BD71828_INT_VSYS_UV_DET_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_VSYS_LOW_RES, 3,
-                      BD71828_INT_VSYS_LOW_RES_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_VSYS_LOW_DET, 3,
-                      BD71828_INT_VSYS_LOW_DET_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_VSYS_HALL_IN, 3,
-                      BD71828_INT_VSYS_HALL_IN_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_VSYS_HALL_TOGGLE, 3,
-                      BD71828_INT_VSYS_HALL_TOGGLE_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_VSYS_MON_RES, 3,
-                      BD71828_INT_VSYS_MON_RES_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_VSYS_MON_DET, 3,
-                      BD71828_INT_VSYS_MON_DET_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_VSYS_UV_RES, 3, BD71828_INT_VSYS_UV_RES_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_VSYS_UV_DET, 3, BD71828_INT_VSYS_UV_DET_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_VSYS_LOW_RES, 3, BD71828_INT_VSYS_LOW_RES_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_VSYS_LOW_DET, 3, BD71828_INT_VSYS_LOW_DET_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_VSYS_HALL_IN, 3, BD71828_INT_VSYS_HALL_IN_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_VSYS_HALL_TOGGLE, 3, BD71828_INT_VSYS_HALL_TOGGLE_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_VSYS_MON_RES, 3, BD71828_INT_VSYS_MON_RES_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_VSYS_MON_DET, 3, BD71828_INT_VSYS_MON_DET_MASK),
        /* Charger */
-       REGMAP_IRQ_REG(BD71828_INT_CHG_DCIN_ILIM, 4,
-                      BD71828_INT_CHG_DCIN_ILIM_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_CHG_TOPOFF_TO_DONE, 4,
-                      BD71828_INT_CHG_TOPOFF_TO_DONE_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_CHG_WDG_TEMP, 4,
-                      BD71828_INT_CHG_WDG_TEMP_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_CHG_WDG_TIME, 4,
-                      BD71828_INT_CHG_WDG_TIME_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_CHG_RECHARGE_RES, 4,
-                      BD71828_INT_CHG_RECHARGE_RES_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_CHG_RECHARGE_DET, 4,
-                      BD71828_INT_CHG_RECHARGE_DET_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_CHG_DCIN_ILIM, 4, BD71828_INT_CHG_DCIN_ILIM_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_CHG_TOPOFF_TO_DONE, 4, BD71828_INT_CHG_TOPOFF_TO_DONE_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_CHG_WDG_TEMP, 4, BD71828_INT_CHG_WDG_TEMP_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_CHG_WDG_TIME, 4, BD71828_INT_CHG_WDG_TIME_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_CHG_RECHARGE_RES, 4, BD71828_INT_CHG_RECHARGE_RES_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_CHG_RECHARGE_DET, 4, BD71828_INT_CHG_RECHARGE_DET_MASK),
        REGMAP_IRQ_REG(BD71828_INT_CHG_RANGED_TEMP_TRANSITION, 4,
                       BD71828_INT_CHG_RANGED_TEMP_TRANSITION_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_CHG_STATE_TRANSITION, 4,
-                      BD71828_INT_CHG_STATE_TRANSITION_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_CHG_STATE_TRANSITION, 4, BD71828_INT_CHG_STATE_TRANSITION_MASK),
        /* Battery */
-       REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_NORMAL, 5,
-                      BD71828_INT_BAT_TEMP_NORMAL_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_ERANGE, 5,
-                      BD71828_INT_BAT_TEMP_ERANGE_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_WARN, 5,
-                      BD71828_INT_BAT_TEMP_WARN_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_BAT_REMOVED, 5,
-                      BD71828_INT_BAT_REMOVED_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_BAT_DETECTED, 5,
-                      BD71828_INT_BAT_DETECTED_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_THERM_REMOVED, 5,
-                      BD71828_INT_THERM_REMOVED_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_THERM_DETECTED, 5,
-                      BD71828_INT_THERM_DETECTED_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_NORMAL, 5, BD71828_INT_BAT_TEMP_NORMAL_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_ERANGE, 5, BD71828_INT_BAT_TEMP_ERANGE_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_WARN, 5, BD71828_INT_BAT_TEMP_WARN_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_BAT_REMOVED, 5, BD71828_INT_BAT_REMOVED_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_BAT_DETECTED, 5, BD71828_INT_BAT_DETECTED_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_THERM_REMOVED, 5, BD71828_INT_THERM_REMOVED_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_THERM_DETECTED, 5, BD71828_INT_THERM_DETECTED_MASK),
        /* Battery Mon 1 */
        REGMAP_IRQ_REG(BD71828_INT_BAT_DEAD, 6, BD71828_INT_BAT_DEAD_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_BAT_SHORTC_RES, 6,
-                      BD71828_INT_BAT_SHORTC_RES_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_BAT_SHORTC_DET, 6,
-                      BD71828_INT_BAT_SHORTC_DET_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_BAT_LOW_VOLT_RES, 6,
-                      BD71828_INT_BAT_LOW_VOLT_RES_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_BAT_LOW_VOLT_DET, 6,
-                      BD71828_INT_BAT_LOW_VOLT_DET_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_VOLT_RES, 6,
-                      BD71828_INT_BAT_OVER_VOLT_RES_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_VOLT_DET, 6,
-                      BD71828_INT_BAT_OVER_VOLT_DET_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_BAT_SHORTC_RES, 6, BD71828_INT_BAT_SHORTC_RES_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_BAT_SHORTC_DET, 6, BD71828_INT_BAT_SHORTC_DET_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_BAT_LOW_VOLT_RES, 6, BD71828_INT_BAT_LOW_VOLT_RES_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_BAT_LOW_VOLT_DET, 6, BD71828_INT_BAT_LOW_VOLT_DET_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_VOLT_RES, 6, BD71828_INT_BAT_OVER_VOLT_RES_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_VOLT_DET, 6, BD71828_INT_BAT_OVER_VOLT_DET_MASK),
        /* Battery Mon 2 */
-       REGMAP_IRQ_REG(BD71828_INT_BAT_MON_RES, 7,
-                      BD71828_INT_BAT_MON_RES_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_BAT_MON_DET, 7,
-                      BD71828_INT_BAT_MON_DET_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_BAT_MON_RES, 7, BD71828_INT_BAT_MON_RES_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_BAT_MON_DET, 7, BD71828_INT_BAT_MON_DET_MASK),
        /* Battery Mon 3 (Coulomb counter) */
-       REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON1, 8,
-                      BD71828_INT_BAT_CC_MON1_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON2, 8,
-                      BD71828_INT_BAT_CC_MON2_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON3, 8,
-                      BD71828_INT_BAT_CC_MON3_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON1, 8, BD71828_INT_BAT_CC_MON1_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON2, 8, BD71828_INT_BAT_CC_MON2_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON3, 8, BD71828_INT_BAT_CC_MON3_MASK),
        /* Battery Mon 4 */
-       REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_1_RES, 9,
-                      BD71828_INT_BAT_OVER_CURR_1_RES_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_1_DET, 9,
-                      BD71828_INT_BAT_OVER_CURR_1_DET_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_2_RES, 9,
-                      BD71828_INT_BAT_OVER_CURR_2_RES_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_2_DET, 9,
-                      BD71828_INT_BAT_OVER_CURR_2_DET_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_3_RES, 9,
-                      BD71828_INT_BAT_OVER_CURR_3_RES_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_3_DET, 9,
-                      BD71828_INT_BAT_OVER_CURR_3_DET_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_1_RES, 9, BD71828_INT_BAT_OVER_CURR_1_RES_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_1_DET, 9, BD71828_INT_BAT_OVER_CURR_1_DET_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_2_RES, 9, BD71828_INT_BAT_OVER_CURR_2_RES_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_2_DET, 9, BD71828_INT_BAT_OVER_CURR_2_DET_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_3_RES, 9, BD71828_INT_BAT_OVER_CURR_3_RES_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_3_DET, 9, BD71828_INT_BAT_OVER_CURR_3_DET_MASK),
        /* Temperature */
-       REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_LOW_RES, 10,
-                      BD71828_INT_TEMP_BAT_LOW_RES_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_LOW_DET, 10,
-                      BD71828_INT_TEMP_BAT_LOW_DET_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_HI_RES, 10,
-                      BD71828_INT_TEMP_BAT_HI_RES_MASK),
-       REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_HI_DET, 10,
-                      BD71828_INT_TEMP_BAT_HI_DET_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_LOW_RES, 10, BD71828_INT_TEMP_BAT_LOW_RES_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_LOW_DET, 10, BD71828_INT_TEMP_BAT_LOW_DET_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_HI_RES, 10, BD71828_INT_TEMP_BAT_HI_RES_MASK),
+       REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_HI_DET, 10, BD71828_INT_TEMP_BAT_HI_DET_MASK),
        REGMAP_IRQ_REG(BD71828_INT_TEMP_CHIP_OVER_125_RES, 10,
                       BD71828_INT_TEMP_CHIP_OVER_125_RES_MASK),
        REGMAP_IRQ_REG(BD71828_INT_TEMP_CHIP_OVER_125_DET, 10,
@@ -267,57 +419,133 @@ static struct regmap_irq_chip bd71828_irq_chip = {
        .init_ack_masked = true,
        .num_regs = 12,
        .num_main_regs = 1,
-       .sub_reg_offsets = &bd71828_sub_irq_offsets[0],
+       .sub_reg_offsets = &bd718xx_sub_irq_offsets[0],
+       .num_main_status_bits = 8,
+       .irq_reg_stride = 1,
+};
+
+static struct regmap_irq_chip bd71815_irq_chip = {
+       .name = "bd71815_irq",
+       .main_status = BD71815_REG_INT_STAT,
+       .irqs = &bd71815_irqs[0],
+       .num_irqs = ARRAY_SIZE(bd71815_irqs),
+       .status_base = BD71815_REG_INT_STAT_01,
+       .mask_base = BD71815_REG_INT_EN_01,
+       .ack_base = BD71815_REG_INT_STAT_01,
+       .mask_invert = true,
+       .init_ack_masked = true,
+       .num_regs = 12,
+       .num_main_regs = 1,
+       .sub_reg_offsets = &bd718xx_sub_irq_offsets[0],
        .num_main_status_bits = 8,
        .irq_reg_stride = 1,
 };
 
+static int set_clk_mode(struct device *dev, struct regmap *regmap,
+                       int clkmode_reg)
+{
+       int ret;
+       unsigned int open_drain;
+
+       ret = of_property_read_u32(dev->of_node, "rohm,clkout-open-drain", &open_drain);
+       if (ret) {
+               if (ret == -EINVAL)
+                       return 0;
+               return ret;
+       }
+       if (open_drain > 1) {
+               dev_err(dev, "bad clk32kout mode configuration");
+               return -EINVAL;
+       }
+
+       if (open_drain)
+               return regmap_update_bits(regmap, clkmode_reg, OUT32K_MODE,
+                                         OUT32K_MODE_OPEN_DRAIN);
+
+       return regmap_update_bits(regmap, clkmode_reg, OUT32K_MODE,
+                                 OUT32K_MODE_CMOS);
+}
+
 static int bd71828_i2c_probe(struct i2c_client *i2c)
 {
-       struct rohm_regmap_dev *chip;
        struct regmap_irq_chip_data *irq_data;
        int ret;
+       struct regmap *regmap;
+       const struct regmap_config *regmap_config;
+       struct regmap_irq_chip *irqchip;
+       unsigned int chip_type;
+       struct mfd_cell *mfd;
+       int cells;
+       int button_irq;
+       int clkmode_reg;
 
        if (!i2c->irq) {
                dev_err(&i2c->dev, "No IRQ configured\n");
                return -EINVAL;
        }
 
-       chip = devm_kzalloc(&i2c->dev, sizeof(*chip), GFP_KERNEL);
-       if (!chip)
-               return -ENOMEM;
-
-       dev_set_drvdata(&i2c->dev, chip);
+       chip_type = (unsigned int)(uintptr_t)
+                   of_device_get_match_data(&i2c->dev);
+       switch (chip_type) {
+       case ROHM_CHIP_TYPE_BD71828:
+               mfd = bd71828_mfd_cells;
+               cells = ARRAY_SIZE(bd71828_mfd_cells);
+               regmap_config = &bd71828_regmap;
+               irqchip = &bd71828_irq_chip;
+               clkmode_reg = BD71828_REG_OUT32K;
+               button_irq = BD71828_INT_SHORTPUSH;
+               break;
+       case ROHM_CHIP_TYPE_BD71815:
+               mfd = bd71815_mfd_cells;
+               cells = ARRAY_SIZE(bd71815_mfd_cells);
+               regmap_config = &bd71815_regmap;
+               irqchip = &bd71815_irq_chip;
+               clkmode_reg = BD71815_REG_OUT32K;
+               /*
+                * If BD71817 support is needed we should be able to handle it
+                * with proper DT configs + BD71815 drivers + power-button.
+                * BD71815 data-sheet does not list the power-button IRQ so we
+                * don't use it.
+                */
+               button_irq = 0;
+               break;
+       default:
+               dev_err(&i2c->dev, "Unknown device type");
+               return -EINVAL;
+       }
 
-       chip->regmap = devm_regmap_init_i2c(i2c, &bd71828_regmap);
-       if (IS_ERR(chip->regmap)) {
+       regmap = devm_regmap_init_i2c(i2c, regmap_config);
+       if (IS_ERR(regmap)) {
                dev_err(&i2c->dev, "Failed to initialize Regmap\n");
-               return PTR_ERR(chip->regmap);
+               return PTR_ERR(regmap);
        }
 
-       ret = devm_regmap_add_irq_chip(&i2c->dev, chip->regmap,
-                                      i2c->irq, IRQF_ONESHOT, 0,
-                                      &bd71828_irq_chip, &irq_data);
+       ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, i2c->irq,
+                                      IRQF_ONESHOT, 0, irqchip, &irq_data);
        if (ret) {
                dev_err(&i2c->dev, "Failed to add IRQ chip\n");
                return ret;
        }
 
        dev_dbg(&i2c->dev, "Registered %d IRQs for chip\n",
-               bd71828_irq_chip.num_irqs);
+               irqchip->num_irqs);
 
-       ret = regmap_irq_get_virq(irq_data, BD71828_INT_SHORTPUSH);
-       if (ret < 0) {
-               dev_err(&i2c->dev, "Failed to get the power-key IRQ\n");
-               return ret;
+       if (button_irq) {
+               ret = regmap_irq_get_virq(irq_data, button_irq);
+               if (ret < 0) {
+                       dev_err(&i2c->dev, "Failed to get the power-key IRQ\n");
+                       return ret;
+               }
+
+               button.irq = ret;
        }
 
-       button.irq = ret;
+       ret = set_clk_mode(&i2c->dev, regmap, clkmode_reg);
+       if (ret)
+               return ret;
 
-       ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO,
-                                  bd71828_mfd_cells,
-                                  ARRAY_SIZE(bd71828_mfd_cells), NULL, 0,
-                                  regmap_irq_get_domain(irq_data));
+       ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, mfd, cells,
+                                  NULL, 0, regmap_irq_get_domain(irq_data));
        if (ret)
                dev_err(&i2c->dev, "Failed to create subdevices\n");
 
@@ -325,7 +553,13 @@ static int bd71828_i2c_probe(struct i2c_client *i2c)
 }
 
 static const struct of_device_id bd71828_of_match[] = {
-       { .compatible = "rohm,bd71828", },
+       {
+               .compatible = "rohm,bd71828",
+               .data = (void *)ROHM_CHIP_TYPE_BD71828,
+       }, {
+               .compatible = "rohm,bd71815",
+               .data = (void *)ROHM_CHIP_TYPE_BD71815,
+        },
        { },
 };
 MODULE_DEVICE_TABLE(of, bd71828_of_match);
index c32c1b6..bfd81f7 100644 (file)
@@ -91,9 +91,9 @@ static const struct regmap_config bd718xx_regmap_config = {
        .cache_type = REGCACHE_RBTREE,
 };
 
-static int bd718xx_init_press_duration(struct bd718xx *bd718xx)
+static int bd718xx_init_press_duration(struct regmap *regmap,
+                                      struct device *dev)
 {
-       struct device* dev = bd718xx->chip.dev;
        u32 short_press_ms, long_press_ms;
        u32 short_press_value, long_press_value;
        int ret;
@@ -102,8 +102,7 @@ static int bd718xx_init_press_duration(struct bd718xx *bd718xx)
                                   &short_press_ms);
        if (!ret) {
                short_press_value = min(15u, (short_press_ms + 250) / 500);
-               ret = regmap_update_bits(bd718xx->chip.regmap,
-                                        BD718XX_REG_PWRONCONFIG0,
+               ret = regmap_update_bits(regmap, BD718XX_REG_PWRONCONFIG0,
                                         BD718XX_PWRBTN_PRESS_DURATION_MASK,
                                         short_press_value);
                if (ret) {
@@ -116,8 +115,7 @@ static int bd718xx_init_press_duration(struct bd718xx *bd718xx)
                                   &long_press_ms);
        if (!ret) {
                long_press_value = min(15u, (long_press_ms + 500) / 1000);
-               ret = regmap_update_bits(bd718xx->chip.regmap,
-                                        BD718XX_REG_PWRONCONFIG1,
+               ret = regmap_update_bits(regmap, BD718XX_REG_PWRONCONFIG1,
                                         BD718XX_PWRBTN_PRESS_DURATION_MASK,
                                         long_press_value);
                if (ret) {
@@ -132,7 +130,8 @@ static int bd718xx_init_press_duration(struct bd718xx *bd718xx)
 static int bd718xx_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
-       struct bd718xx *bd718xx;
+       struct regmap *regmap;
+       struct regmap_irq_chip_data *irq_data;
        int ret;
        unsigned int chip_type;
        struct mfd_cell *mfd;
@@ -142,13 +141,6 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c,
                dev_err(&i2c->dev, "No IRQ configured\n");
                return -EINVAL;
        }
-
-       bd718xx = devm_kzalloc(&i2c->dev, sizeof(struct bd718xx), GFP_KERNEL);
-
-       if (!bd718xx)
-               return -ENOMEM;
-
-       bd718xx->chip_irq = i2c->irq;
        chip_type = (unsigned int)(uintptr_t)
                    of_device_get_match_data(&i2c->dev);
        switch (chip_type) {
@@ -164,29 +156,26 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c,
                dev_err(&i2c->dev, "Unknown device type");
                return -EINVAL;
        }
-       bd718xx->chip.dev = &i2c->dev;
-       dev_set_drvdata(&i2c->dev, bd718xx);
 
-       bd718xx->chip.regmap = devm_regmap_init_i2c(i2c,
-                                                   &bd718xx_regmap_config);
-       if (IS_ERR(bd718xx->chip.regmap)) {
+       regmap = devm_regmap_init_i2c(i2c, &bd718xx_regmap_config);
+       if (IS_ERR(regmap)) {
                dev_err(&i2c->dev, "regmap initialization failed\n");
-               return PTR_ERR(bd718xx->chip.regmap);
+               return PTR_ERR(regmap);
        }
 
-       ret = devm_regmap_add_irq_chip(&i2c->dev, bd718xx->chip.regmap,
-                                      bd718xx->chip_irq, IRQF_ONESHOT, 0,
-                                      &bd718xx_irq_chip, &bd718xx->irq_data);
+       ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, i2c->irq,
+                                      IRQF_ONESHOT, 0, &bd718xx_irq_chip,
+                                      &irq_data);
        if (ret) {
                dev_err(&i2c->dev, "Failed to add irq_chip\n");
                return ret;
        }
 
-       ret = bd718xx_init_press_duration(bd718xx);
+       ret = bd718xx_init_press_duration(regmap, &i2c->dev);
        if (ret)
                return ret;
 
-       ret = regmap_irq_get_virq(bd718xx->irq_data, BD718XX_INT_PWRBTN_S);
+       ret = regmap_irq_get_virq(irq_data, BD718XX_INT_PWRBTN_S);
 
        if (ret < 0) {
                dev_err(&i2c->dev, "Failed to get the IRQ\n");
@@ -195,9 +184,9 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c,
 
        button.irq = ret;
 
-       ret = devm_mfd_add_devices(bd718xx->chip.dev, PLATFORM_DEVID_AUTO,
+       ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO,
                                   mfd, cells, NULL, 0,
-                                  regmap_irq_get_domain(bd718xx->irq_data));
+                                  regmap_irq_get_domain(irq_data));
        if (ret)
                dev_err(&i2c->dev, "Failed to create subdevices\n");
 
index f12e909..beda610 100644 (file)
@@ -950,6 +950,11 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl,  u32 kernel,
        if (!fl->cctx->rpdev)
                return -EPIPE;
 
+       if (handle == FASTRPC_INIT_HANDLE && !kernel) {
+               dev_warn_ratelimited(fl->sctx->dev, "user app trying to send a kernel RPC message (%d)\n",  handle);
+               return -EPERM;
+       }
+
        ctx = fastrpc_context_alloc(fl, kernel, sc, args);
        if (IS_ERR(ctx))
                return PTR_ERR(ctx);
index df847a6..9f19bee 100644 (file)
@@ -992,7 +992,6 @@ void hl_debugfs_add_device(struct hl_device *hdev)
        struct hl_dbg_device_entry *dev_entry = &hdev->hl_debugfs;
        int count = ARRAY_SIZE(hl_debugfs_list);
        struct hl_debugfs_entry *entry;
-       struct dentry *ent;
        int i;
 
        dev_entry->hdev = hdev;
@@ -1105,13 +1104,11 @@ void hl_debugfs_add_device(struct hl_device *hdev)
                                &hl_security_violations_fops);
 
        for (i = 0, entry = dev_entry->entry_arr ; i < count ; i++, entry++) {
-
-               ent = debugfs_create_file(hl_debugfs_list[i].name,
+               debugfs_create_file(hl_debugfs_list[i].name,
                                        0444,
                                        dev_entry->root,
                                        entry,
                                        &hl_debugfs_fops);
-               entry->dent = ent;
                entry->info_ent = &hl_debugfs_list[i];
                entry->dev_entry = dev_entry;
        }
index 15fcb5c..334009e 100644 (file)
@@ -93,12 +93,19 @@ void hl_hpriv_put(struct hl_fpriv *hpriv)
 static int hl_device_release(struct inode *inode, struct file *filp)
 {
        struct hl_fpriv *hpriv = filp->private_data;
+       struct hl_device *hdev = hpriv->hdev;
+
+       filp->private_data = NULL;
+
+       if (!hdev) {
+               pr_crit("Closing FD after device was removed. Memory leak will occur and it is advised to reboot.\n");
+               put_pid(hpriv->taskpid);
+               return 0;
+       }
 
        hl_cb_mgr_fini(hpriv->hdev, &hpriv->cb_mgr);
        hl_ctx_mgr_fini(hpriv->hdev, &hpriv->ctx_mgr);
 
-       filp->private_data = NULL;
-
        hl_hpriv_put(hpriv);
 
        return 0;
@@ -107,15 +114,20 @@ static int hl_device_release(struct inode *inode, struct file *filp)
 static int hl_device_release_ctrl(struct inode *inode, struct file *filp)
 {
        struct hl_fpriv *hpriv = filp->private_data;
-       struct hl_device *hdev;
+       struct hl_device *hdev = hpriv->hdev;
 
        filp->private_data = NULL;
 
-       hdev = hpriv->hdev;
+       if (!hdev) {
+               pr_err("Closing FD after device was removed\n");
+               goto out;
+       }
 
        mutex_lock(&hdev->fpriv_list_lock);
        list_del(&hpriv->dev_node);
        mutex_unlock(&hdev->fpriv_list_lock);
+out:
+       put_pid(hpriv->taskpid);
 
        kfree(hpriv);
 
@@ -134,8 +146,14 @@ static int hl_device_release_ctrl(struct inode *inode, struct file *filp)
 static int hl_mmap(struct file *filp, struct vm_area_struct *vma)
 {
        struct hl_fpriv *hpriv = filp->private_data;
+       struct hl_device *hdev = hpriv->hdev;
        unsigned long vm_pgoff;
 
+       if (!hdev) {
+               pr_err_ratelimited("Trying to mmap after device was removed! Please close FD\n");
+               return -ENODEV;
+       }
+
        vm_pgoff = vma->vm_pgoff;
        vma->vm_pgoff = HL_MMAP_OFFSET_VALUE_GET(vm_pgoff);
 
@@ -883,6 +901,16 @@ wait_for_processes:
        return -EBUSY;
 }
 
+static void device_disable_open_processes(struct hl_device *hdev)
+{
+       struct hl_fpriv *hpriv;
+
+       mutex_lock(&hdev->fpriv_list_lock);
+       list_for_each_entry(hpriv, &hdev->fpriv_list, dev_node)
+               hpriv->hdev = NULL;
+       mutex_unlock(&hdev->fpriv_list_lock);
+}
+
 /*
  * hl_device_reset - reset the device
  *
@@ -1556,8 +1584,10 @@ void hl_device_fini(struct hl_device *hdev)
                HL_PENDING_RESET_LONG_SEC);
 
        rc = device_kill_open_processes(hdev, HL_PENDING_RESET_LONG_SEC);
-       if (rc)
+       if (rc) {
                dev_crit(hdev->dev, "Failed to kill all open processes\n");
+               device_disable_open_processes(hdev);
+       }
 
        hl_cb_pool_fini(hdev);
 
index d933878..4b321e4 100644 (file)
@@ -1465,12 +1465,10 @@ struct hl_info_list {
 
 /**
  * struct hl_debugfs_entry - debugfs dentry wrapper.
- * @dent: base debugfs entry structure.
  * @info_ent: dentry realted ops.
  * @dev_entry: ASIC specific debugfs manager.
  */
 struct hl_debugfs_entry {
-       struct dentry                   *dent;
        const struct hl_info_list       *info_ent;
        struct hl_dbg_device_entry      *dev_entry;
 };
index 03af61c..083a309 100644 (file)
@@ -5,6 +5,8 @@
  * All Rights Reserved.
  */
 
+#define pr_fmt(fmt)    "habanalabs: " fmt
+
 #include <uapi/misc/habanalabs.h>
 #include "habanalabs.h"
 
@@ -682,6 +684,11 @@ long hl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
        const struct hl_ioctl_desc *ioctl = NULL;
        unsigned int nr = _IOC_NR(cmd);
 
+       if (!hdev) {
+               pr_err_ratelimited("Sending ioctl after device was removed! Please close FD\n");
+               return -ENODEV;
+       }
+
        if ((nr >= HL_COMMAND_START) && (nr < HL_COMMAND_END)) {
                ioctl = &hl_ioctls[nr];
        } else {
@@ -700,6 +707,11 @@ long hl_ioctl_control(struct file *filep, unsigned int cmd, unsigned long arg)
        const struct hl_ioctl_desc *ioctl = NULL;
        unsigned int nr = _IOC_NR(cmd);
 
+       if (!hdev) {
+               pr_err_ratelimited("Sending ioctl after device was removed! Please close FD\n");
+               return -ENODEV;
+       }
+
        if (nr == _IOC_NR(HL_IOCTL_INFO)) {
                ioctl = &hl_ioctls_control[nr];
        } else {
index de53fb5..44a0522 100644 (file)
@@ -47,7 +47,7 @@ inline u32 hl_cq_inc_ptr(u32 ptr)
  * Increment ptr by 1. If it reaches the number of event queue
  * entries, set it to 0
  */
-inline u32 hl_eq_inc_ptr(u32 ptr)
+static inline u32 hl_eq_inc_ptr(u32 ptr)
 {
        ptr++;
        if (unlikely(ptr == HL_EQ_LENGTH))
index 71703a3..93c9e5f 100644 (file)
@@ -499,18 +499,32 @@ static void hl_mmu_pa_page_with_offset(struct hl_ctx *ctx, u64 virt_addr,
        else /* HL_VA_RANGE_TYPE_DRAM */
                p = &prop->dmmu;
 
-       /*
-        * find the correct hop shift field in hl_mmu_properties structure
-        * in order to determine the right maks for the page offset.
-        */
-       hop0_shift_off = offsetof(struct hl_mmu_properties, hop0_shift);
-       p = (char *)p + hop0_shift_off;
-       p = (char *)p + ((hops->used_hops - 1) * sizeof(u64));
-       hop_shift = *(u64 *)p;
-       offset_mask = (1ull << hop_shift) - 1;
-       addr_mask = ~(offset_mask);
-       *phys_addr = (tmp_phys_addr & addr_mask) |
-                                       (virt_addr & offset_mask);
+       if ((hops->range_type == HL_VA_RANGE_TYPE_DRAM) &&
+                       !is_power_of_2(prop->dram_page_size)) {
+               u32 bit;
+               u64 page_offset_mask;
+               u64 phys_addr_mask;
+
+               bit = __ffs64((u64)prop->dram_page_size);
+               page_offset_mask = ((1ull << bit) - 1);
+               phys_addr_mask = ~page_offset_mask;
+               *phys_addr = (tmp_phys_addr & phys_addr_mask) |
+                               (virt_addr & page_offset_mask);
+       } else {
+               /*
+                * find the correct hop shift field in hl_mmu_properties
+                * structure in order to determine the right masks
+                * for the page offset.
+                */
+               hop0_shift_off = offsetof(struct hl_mmu_properties, hop0_shift);
+               p = (char *)p + hop0_shift_off;
+               p = (char *)p + ((hops->used_hops - 1) * sizeof(u64));
+               hop_shift = *(u64 *)p;
+               offset_mask = (1ull << hop_shift) - 1;
+               addr_mask = ~(offset_mask);
+               *phys_addr = (tmp_phys_addr & addr_mask) |
+                               (virt_addr & offset_mask);
+       }
 }
 
 int hl_mmu_va_to_pa(struct hl_ctx *ctx, u64 virt_addr, u64 *phys_addr)
index 2d778d0..c0fe329 100644 (file)
@@ -2288,15 +2288,13 @@ crq_failed:
        return -EPERM;
 }
 
-static int ibmvmc_remove(struct vio_dev *vdev)
+static void ibmvmc_remove(struct vio_dev *vdev)
 {
        struct crq_server_adapter *adapter = dev_get_drvdata(&vdev->dev);
 
        dev_info(adapter->dev, "Entering remove for UA 0x%x\n",
                 vdev->unit_address);
        ibmvmc_release_crq_queue(adapter);
-
-       return 0;
 }
 
 static struct vio_device_id ibmvmc_device_table[] = {
index 9f350e0..f1655f5 100644 (file)
@@ -140,6 +140,7 @@ static const struct of_device_id pvpanic_mmio_match[] = {
        { .compatible = "qemu,pvpanic-mmio", },
        {}
 };
+MODULE_DEVICE_TABLE(of, pvpanic_mmio_match);
 
 static const struct acpi_device_id pvpanic_device_ids[] = {
        { "QEMU0001", 0 },
index c2e70b7..4383c26 100644 (file)
@@ -399,11 +399,6 @@ void mmc_remove_card(struct mmc_card *card)
        mmc_remove_card_debugfs(card);
 #endif
 
-       if (host->cqe_enabled) {
-               host->cqe_ops->cqe_disable(host);
-               host->cqe_enabled = false;
-       }
-
        if (mmc_card_present(card)) {
                if (mmc_host_is_spi(card->host)) {
                        pr_info("%s: SPI card removed\n",
@@ -416,6 +411,10 @@ void mmc_remove_card(struct mmc_card *card)
                of_node_put(card->dev.of_node);
        }
 
+       if (host->cqe_enabled) {
+               host->cqe_ops->cqe_disable(host);
+               host->cqe_enabled = false;
+       }
+
        put_device(&card->dev);
 }
-
index 0d80b72..8741271 100644 (file)
@@ -423,10 +423,6 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
 
                /* EXT_CSD value is in units of 10ms, but we store in ms */
                card->ext_csd.part_time = 10 * ext_csd[EXT_CSD_PART_SWITCH_TIME];
-               /* Some eMMC set the value too low so set a minimum */
-               if (card->ext_csd.part_time &&
-                   card->ext_csd.part_time < MMC_MIN_PART_SWITCH_TIME)
-                       card->ext_csd.part_time = MMC_MIN_PART_SWITCH_TIME;
 
                /* Sleep / awake timeout in 100ns units */
                if (sa_shift > 0 && sa_shift <= 0x17)
@@ -616,6 +612,17 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
                card->ext_csd.data_sector_size = 512;
        }
 
+       /*
+        * GENERIC_CMD6_TIME is to be used "unless a specific timeout is defined
+        * when accessing a specific field", so use it here if there is no
+        * PARTITION_SWITCH_TIME.
+        */
+       if (!card->ext_csd.part_time)
+               card->ext_csd.part_time = card->ext_csd.generic_cmd6_time;
+       /* Some eMMC set the value too low so set a minimum */
+       if (card->ext_csd.part_time < MMC_MIN_PART_SWITCH_TIME)
+               card->ext_csd.part_time = MMC_MIN_PART_SWITCH_TIME;
+
        /* eMMC v5 or later */
        if (card->ext_csd.rev >= 7) {
                memcpy(card->ext_csd.fwrev, &ext_csd[EXT_CSD_FIRMWARE_VERSION],
index 17dbc81..984d350 100644 (file)
@@ -1242,7 +1242,11 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
                if (!cmd->busy_timeout)
                        cmd->busy_timeout = 10 * MSEC_PER_SEC;
 
-               clks = (unsigned long long)cmd->busy_timeout * host->cclk;
+               if (cmd->busy_timeout > host->mmc->max_busy_timeout)
+                       clks = (unsigned long long)host->mmc->max_busy_timeout * host->cclk;
+               else
+                       clks = (unsigned long long)cmd->busy_timeout * host->cclk;
+
                do_div(clks, MSEC_PER_SEC);
                writel_relaxed(clks, host->base + MMCIDATATIMER);
        }
@@ -2151,6 +2155,10 @@ static int mmci_probe(struct amba_device *dev,
                mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
        }
 
+       /* Variants with mandatory busy timeout in HW needs R1B responses. */
+       if (variant->busy_timeout)
+               mmc->caps |= MMC_CAP_NEED_RSP_BUSY;
+
        /* Prepare a CMD12 - needed to clear the DPSM on some variants. */
        host->stop_abort.opcode = MMC_STOP_TRANSMISSION;
        host->stop_abort.arg = 0;
index eb72582..f9cfb08 100644 (file)
@@ -32,7 +32,6 @@
 
 MODULE_AUTHOR("Eric Brower <ebrower@usa.net>");
 MODULE_DESCRIPTION("User-programmable flash device on Sun Microsystems boardsets");
-MODULE_SUPPORTED_DEVICE(DRIVER_NAME);
 MODULE_LICENSE("GPL");
 MODULE_VERSION("2.1");
 
index b09bed5..bcd31f4 100644 (file)
@@ -94,7 +94,7 @@ config WIREGUARD
        select CRYPTO_BLAKE2S_ARM if ARM
        select CRYPTO_CURVE25519_NEON if ARM && KERNEL_MODE_NEON
        select CRYPTO_CHACHA_MIPS if CPU_MIPS32_R2
-       select CRYPTO_POLY1305_MIPS if CPU_MIPS32 || (CPU_MIPS64 && 64BIT)
+       select CRYPTO_POLY1305_MIPS if MIPS
        help
          WireGuard is a secure, fast, and easy to use replacement for IPSec
          that uses modern cryptography and clever networking tricks. It's
index 74cbbb2..456315b 100644 (file)
@@ -3978,11 +3978,15 @@ static int bond_neigh_init(struct neighbour *n)
 
        rcu_read_lock();
        slave = bond_first_slave_rcu(bond);
-       if (!slave)
+       if (!slave) {
+               ret = -EINVAL;
                goto out;
+       }
        slave_ops = slave->dev->netdev_ops;
-       if (!slave_ops->ndo_neigh_setup)
+       if (!slave_ops->ndo_neigh_setup) {
+               ret = -EINVAL;
                goto out;
+       }
 
        /* TODO: find another way [1] to implement this.
         * Passing a zeroed structure is fragile,
index 971ada3..134c057 100644 (file)
@@ -701,7 +701,7 @@ static int flexcan_chip_freeze(struct flexcan_priv *priv)
        u32 reg;
 
        reg = priv->read(&regs->mcr);
-       reg |= FLEXCAN_MCR_HALT;
+       reg |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT;
        priv->write(reg, &regs->mcr);
 
        while (timeout-- && !(priv->read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
@@ -1480,10 +1480,13 @@ static int flexcan_chip_start(struct net_device *dev)
 
        flexcan_set_bittiming(dev);
 
+       /* set freeze, halt */
+       err = flexcan_chip_freeze(priv);
+       if (err)
+               goto out_chip_disable;
+
        /* MCR
         *
-        * enable freeze
-        * halt now
         * only supervisor access
         * enable warning int
         * enable individual RX masking
@@ -1492,9 +1495,8 @@ static int flexcan_chip_start(struct net_device *dev)
         */
        reg_mcr = priv->read(&regs->mcr);
        reg_mcr &= ~FLEXCAN_MCR_MAXMB(0xff);
-       reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT | FLEXCAN_MCR_SUPV |
-               FLEXCAN_MCR_WRN_EN | FLEXCAN_MCR_IRMQ | FLEXCAN_MCR_IDAM_C |
-               FLEXCAN_MCR_MAXMB(priv->tx_mb_idx);
+       reg_mcr |= FLEXCAN_MCR_SUPV | FLEXCAN_MCR_WRN_EN | FLEXCAN_MCR_IRMQ |
+               FLEXCAN_MCR_IDAM_C | FLEXCAN_MCR_MAXMB(priv->tx_mb_idx);
 
        /* MCR
         *
@@ -1865,10 +1867,14 @@ static int register_flexcandev(struct net_device *dev)
        if (err)
                goto out_chip_disable;
 
-       /* set freeze, halt and activate FIFO, restrict register access */
+       /* set freeze, halt */
+       err = flexcan_chip_freeze(priv);
+       if (err)
+               goto out_chip_disable;
+
+       /* activate FIFO, restrict register access */
        reg = priv->read(&regs->mcr);
-       reg |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT |
-               FLEXCAN_MCR_FEN | FLEXCAN_MCR_SUPV;
+       reg |=  FLEXCAN_MCR_FEN | FLEXCAN_MCR_SUPV;
        priv->write(reg, &regs->mcr);
 
        /* Currently we only support newer versions of this core
index b7caec7..4147cec 100644 (file)
@@ -237,14 +237,14 @@ static int tcan4x5x_init(struct m_can_classdev *cdev)
        if (ret)
                return ret;
 
+       /* Zero out the MCAN buffers */
+       m_can_init_ram(cdev);
+
        ret = regmap_update_bits(tcan4x5x->regmap, TCAN4X5X_CONFIG,
                                 TCAN4X5X_MODE_SEL_MASK, TCAN4X5X_MODE_NORMAL);
        if (ret)
                return ret;
 
-       /* Zero out the MCAN buffers */
-       m_can_init_ram(cdev);
-
        return ret;
 }
 
index 0df1cdf..1df3c4b 100644 (file)
@@ -21,7 +21,6 @@
 
 MODULE_AUTHOR("Stephane Grosjean <s.grosjean@peak-system.com>");
 MODULE_DESCRIPTION("Socket-CAN driver for PEAK PCAN PCIe/M.2 FD family cards");
-MODULE_SUPPORTED_DEVICE("PEAK PCAN PCIe/M.2 FD CAN cards");
 MODULE_LICENSE("GPL v2");
 
 #define PCIEFD_DRV_NAME                "peak_pciefd"
index 6f88c99..4ab9175 100644 (file)
@@ -21,7 +21,6 @@
 
 MODULE_AUTHOR("Sebastian Haas <haas@ems-wuenche.com>");
 MODULE_DESCRIPTION("Socket-CAN driver for EMS CPC-PCI/PCIe/104P CAN cards");
-MODULE_SUPPORTED_DEVICE("EMS CPC-PCI/PCIe/104P CAN card");
 MODULE_LICENSE("GPL v2");
 
 #define EMS_PCI_V1_MAX_CHAN 2
index 770304e..e21b169 100644 (file)
@@ -21,7 +21,6 @@
 
 MODULE_AUTHOR("Markus Plessing <plessing@ems-wuensche.com>");
 MODULE_DESCRIPTION("Socket-CAN driver for EMS CPC-CARD cards");
-MODULE_SUPPORTED_DEVICE("EMS CPC-CARD CAN card");
 MODULE_LICENSE("GPL v2");
 
 #define EMS_PCMCIA_MAX_CHAN 2
index 0ea6b71..95fe9ee 100644 (file)
@@ -33,7 +33,6 @@
 
 MODULE_AUTHOR("Per Dalen <per.dalen@cnw.se>");
 MODULE_DESCRIPTION("Socket-CAN driver for KVASER PCAN PCI cards");
-MODULE_SUPPORTED_DEVICE("KVASER PCAN PCI CAN card");
 MODULE_LICENSE("GPL v2");
 
 #define MAX_NO_OF_CHANNELS        4 /* max no of channels on a single card */
index 4713921..84eac8c 100644 (file)
@@ -24,8 +24,6 @@
 
 MODULE_AUTHOR("Stephane Grosjean <s.grosjean@peak-system.com>");
 MODULE_DESCRIPTION("Socket-CAN driver for PEAK PCAN PCI family cards");
-MODULE_SUPPORTED_DEVICE("PEAK PCAN PCI/PCIe/PCIeC miniPCI CAN cards");
-MODULE_SUPPORTED_DEVICE("PEAK PCAN miniPCIe/cPCI PC/104+ PCI/104e CAN Cards");
 MODULE_LICENSE("GPL v2");
 
 #define DRV_NAME  "peak_pci"
index cf951a7..131a084 100644 (file)
@@ -22,7 +22,6 @@
 MODULE_AUTHOR("Stephane Grosjean <s.grosjean@peak-system.com>");
 MODULE_DESCRIPTION("CAN driver for PEAK-System PCAN-PC Cards");
 MODULE_LICENSE("GPL v2");
-MODULE_SUPPORTED_DEVICE("PEAK PCAN-PC Card");
 
 /* PEAK-System PCMCIA driver name */
 #define PCC_NAME               "peak_pcmcia"
index 8567958..5de1ebb 100644 (file)
 MODULE_AUTHOR("Pavel Cheblakov <P.B.Cheblakov@inp.nsk.su>");
 MODULE_DESCRIPTION("Socket-CAN driver for PLX90xx PCI-bridge cards with "
                   "the SJA1000 chips");
-MODULE_SUPPORTED_DEVICE("Adlink PCI-7841/cPCI-7841, "
-                       "Adlink PCI-7841/cPCI-7841 SE, "
-                       "Marathon CAN-bus-PCI, "
-                       "Marathon CAN-bus-PCIe, "
-                       "TEWS TECHNOLOGIES TPMC810, "
-                       "esd CAN-PCI/CPCI/PCI104/200, "
-                       "esd CAN-PCI/PMC/266, "
-                       "esd CAN-PCIe/2000, "
-                       "Connect Tech Inc. CANpro/104-Plus Opto (CRG001), "
-                       "IXXAT PC-I 04/PCI, "
-                       "ELCUS CAN-200-PCI, "
-                       "ASEM DUAL CAN-RAW")
 MODULE_LICENSE("GPL v2");
 
 #define PLX_PCI_MAX_CHAN 2
index 3c5b929..799e9d5 100644 (file)
@@ -335,8 +335,6 @@ static void mcp251xfd_ring_init(struct mcp251xfd_priv *priv)
        u8 len;
        int i, j;
 
-       netdev_reset_queue(priv->ndev);
-
        /* TEF */
        tef_ring = priv->tef;
        tef_ring->head = 0;
@@ -1249,8 +1247,7 @@ mcp251xfd_handle_tefif_recover(const struct mcp251xfd_priv *priv, const u32 seq)
 
 static int
 mcp251xfd_handle_tefif_one(struct mcp251xfd_priv *priv,
-                          const struct mcp251xfd_hw_tef_obj *hw_tef_obj,
-                          unsigned int *frame_len_ptr)
+                          const struct mcp251xfd_hw_tef_obj *hw_tef_obj)
 {
        struct net_device_stats *stats = &priv->ndev->stats;
        u32 seq, seq_masked, tef_tail_masked;
@@ -1272,8 +1269,7 @@ mcp251xfd_handle_tefif_one(struct mcp251xfd_priv *priv,
        stats->tx_bytes +=
                can_rx_offload_get_echo_skb(&priv->offload,
                                            mcp251xfd_get_tef_tail(priv),
-                                           hw_tef_obj->ts,
-                                           frame_len_ptr);
+                                           hw_tef_obj->ts, NULL);
        stats->tx_packets++;
        priv->tef->tail++;
 
@@ -1331,7 +1327,6 @@ mcp251xfd_tef_obj_read(const struct mcp251xfd_priv *priv,
 static int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv)
 {
        struct mcp251xfd_hw_tef_obj hw_tef_obj[MCP251XFD_TX_OBJ_NUM_MAX];
-       unsigned int total_frame_len = 0;
        u8 tef_tail, len, l;
        int err, i;
 
@@ -1353,9 +1348,7 @@ static int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv)
        }
 
        for (i = 0; i < len; i++) {
-               unsigned int frame_len;
-
-               err = mcp251xfd_handle_tefif_one(priv, &hw_tef_obj[i], &frame_len);
+               err = mcp251xfd_handle_tefif_one(priv, &hw_tef_obj[i]);
                /* -EAGAIN means the Sequence Number in the TEF
                 * doesn't match our tef_tail. This can happen if we
                 * read the TEF objects too early. Leave loop let the
@@ -1365,8 +1358,6 @@ static int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv)
                        goto out_netif_wake_queue;
                if (err)
                        return err;
-
-               total_frame_len += frame_len;
        }
 
  out_netif_wake_queue:
@@ -1397,7 +1388,6 @@ static int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv)
                        return err;
 
                tx_ring->tail += len;
-               netdev_completed_queue(priv->ndev, len, total_frame_len);
 
                err = mcp251xfd_check_tef_tail(priv);
                if (err)
@@ -2443,7 +2433,6 @@ static netdev_tx_t mcp251xfd_start_xmit(struct sk_buff *skb,
        struct mcp251xfd_priv *priv = netdev_priv(ndev);
        struct mcp251xfd_tx_ring *tx_ring = priv->tx;
        struct mcp251xfd_tx_obj *tx_obj;
-       unsigned int frame_len;
        u8 tx_head;
        int err;
 
@@ -2462,9 +2451,7 @@ static netdev_tx_t mcp251xfd_start_xmit(struct sk_buff *skb,
        if (mcp251xfd_get_tx_free(tx_ring) == 0)
                netif_stop_queue(ndev);
 
-       frame_len = can_skb_get_frame_len(skb);
-       can_put_echo_skb(skb, ndev, tx_head, frame_len);
-       netdev_sent_queue(priv->ndev, frame_len);
+       can_put_echo_skb(skb, ndev, tx_head, 0);
 
        err = mcp251xfd_tx_obj_write(priv, tx_obj);
        if (err)
index e6c1e5d..e393e84 100644 (file)
@@ -18,8 +18,6 @@
 
 #include "pcan_usb_core.h"
 
-MODULE_SUPPORTED_DEVICE("PEAK-System PCAN-USB adapter");
-
 /* PCAN-USB Endpoints */
 #define PCAN_USB_EP_CMDOUT             1
 #define PCAN_USB_EP_CMDIN              (PCAN_USB_EP_CMDOUT | USB_DIR_IN)
index f347ecc..bae0785 100644 (file)
@@ -16,9 +16,6 @@
 #include "pcan_usb_core.h"
 #include "pcan_usb_pro.h"
 
-MODULE_SUPPORTED_DEVICE("PEAK-System PCAN-USB FD adapter");
-MODULE_SUPPORTED_DEVICE("PEAK-System PCAN-USB Pro FD adapter");
-
 #define PCAN_USBPROFD_CHANNEL_COUNT    2
 #define PCAN_USBFD_CHANNEL_COUNT       1
 
index 275087c..18fa180 100644 (file)
@@ -17,8 +17,6 @@
 #include "pcan_usb_core.h"
 #include "pcan_usb_pro.h"
 
-MODULE_SUPPORTED_DEVICE("PEAK-System PCAN-USB Pro adapter");
-
 #define PCAN_USBPRO_CHANNEL_COUNT      2
 
 /* PCAN-USB Pro adapter internal clock (MHz) */
index 5ee8103..f277df9 100644 (file)
@@ -406,7 +406,7 @@ static int bcm_sf2_sw_rst(struct bcm_sf2_priv *priv)
        /* The watchdog reset does not work on 7278, we need to hit the
         * "external" reset line through the reset controller.
         */
-       if (priv->type == BCM7278_DEVICE_ID && !IS_ERR(priv->rcdev)) {
+       if (priv->type == BCM7278_DEVICE_ID) {
                ret = reset_control_assert(priv->rcdev);
                if (ret)
                        return ret;
@@ -1265,7 +1265,7 @@ static int bcm_sf2_sw_probe(struct platform_device *pdev)
 
        priv->rcdev = devm_reset_control_get_optional_exclusive(&pdev->dev,
                                                                "switch");
-       if (PTR_ERR(priv->rcdev) == -EPROBE_DEFER)
+       if (IS_ERR(priv->rcdev))
                return PTR_ERR(priv->rcdev);
 
        /* Auto-detection using standard registers will not work, so
@@ -1426,7 +1426,7 @@ static int bcm_sf2_sw_remove(struct platform_device *pdev)
        bcm_sf2_mdio_unregister(priv);
        clk_disable_unprepare(priv->clk_mdiv);
        clk_disable_unprepare(priv->clk);
-       if (priv->type == BCM7278_DEVICE_ID && !IS_ERR(priv->rcdev))
+       if (priv->type == BCM7278_DEVICE_ID)
                reset_control_assert(priv->rcdev);
 
        return 0;
index c17de2b..f06f5fa 100644 (file)
@@ -1624,6 +1624,7 @@ mtk_get_tag_protocol(struct dsa_switch *ds, int port,
        }
 }
 
+#ifdef CONFIG_GPIOLIB
 static inline u32
 mt7530_gpio_to_bit(unsigned int offset)
 {
@@ -1726,6 +1727,7 @@ mt7530_setup_gpio(struct mt7530_priv *priv)
 
        return devm_gpiochip_add_data(dev, gc, priv);
 }
+#endif /* CONFIG_GPIOLIB */
 
 static int
 mt7530_setup(struct dsa_switch *ds)
@@ -1868,11 +1870,13 @@ mt7530_setup(struct dsa_switch *ds)
                }
        }
 
+#ifdef CONFIG_GPIOLIB
        if (of_property_read_bool(priv->dev->of_node, "gpio-controller")) {
                ret = mt7530_setup_gpio(priv);
                if (ret)
                        return ret;
        }
+#endif /* CONFIG_GPIOLIB */
 
        mt7530_setup_port5(ds, interface);
 
index 7692338..51ea104 100644 (file)
@@ -1922,7 +1922,7 @@ out_unlock_ptp:
                                speed = SPEED_1000;
                        else if (bmcr & BMCR_SPEED100)
                                speed = SPEED_100;
-                       else if (bmcr & BMCR_SPEED10)
+                       else
                                speed = SPEED_10;
 
                        sja1105_sgmii_pcs_force_speed(priv, speed);
@@ -3369,14 +3369,14 @@ static int sja1105_port_ucast_bcast_flood(struct sja1105_private *priv, int to,
                if (flags.val & BR_FLOOD)
                        priv->ucast_egress_floods |= BIT(to);
                else
-                       priv->ucast_egress_floods |= BIT(to);
+                       priv->ucast_egress_floods &= ~BIT(to);
        }
 
        if (flags.mask & BR_BCAST_FLOOD) {
                if (flags.val & BR_BCAST_FLOOD)
                        priv->bcast_egress_floods |= BIT(to);
                else
-                       priv->bcast_egress_floods |= BIT(to);
+                       priv->bcast_egress_floods &= ~BIT(to);
        }
 
        return sja1105_manage_flood_domains(priv);
index f025f96..fde6e99 100644 (file)
@@ -528,7 +528,10 @@ static int xrs700x_hsr_join(struct dsa_switch *ds, int port,
                return -EOPNOTSUPP;
 
        dsa_hsr_foreach_port(dp, ds, hsr) {
-               partner = dp;
+               if (dp->index != port) {
+                       partner = dp;
+                       break;
+               }
        }
 
        /* We can't enable redundancy on the switch until both
@@ -582,7 +585,10 @@ static int xrs700x_hsr_leave(struct dsa_switch *ds, int port,
        unsigned int val;
 
        dsa_hsr_foreach_port(dp, ds, hsr) {
-               partner = dp;
+               if (dp->index != port) {
+                       partner = dp;
+                       break;
+               }
        }
 
        if (!partner)
index 9b7f1af..9e02f88 100644 (file)
@@ -1894,13 +1894,16 @@ static int alx_resume(struct device *dev)
 
        if (!netif_running(alx->dev))
                return 0;
-       netif_device_attach(alx->dev);
 
        rtnl_lock();
        err = __alx_open(alx, true);
        rtnl_unlock();
+       if (err)
+               return err;
 
-       return err;
+       netif_device_attach(alx->dev);
+
+       return 0;
 }
 
 static SIMPLE_DEV_PM_OPS(alx_pm_ops, alx_suspend, alx_resume);
index 0b70e9e..98cf82d 100644 (file)
@@ -592,6 +592,9 @@ static int bcm4908_enet_poll(struct napi_struct *napi, int weight)
                bcm4908_enet_intrs_on(enet);
        }
 
+       /* Hardware could disable ring if it run out of descriptors */
+       bcm4908_enet_dma_rx_ring_enable(enet, &enet->rx_ring);
+
        return handled;
 }
 
index a680fd9..b53a0d8 100644 (file)
@@ -8556,10 +8556,18 @@ static void bnxt_setup_inta(struct bnxt *bp)
        bp->irq_tbl[0].handler = bnxt_inta;
 }
 
+static int bnxt_init_int_mode(struct bnxt *bp);
+
 static int bnxt_setup_int_mode(struct bnxt *bp)
 {
        int rc;
 
+       if (!bp->irq_tbl) {
+               rc = bnxt_init_int_mode(bp);
+               if (rc || !bp->irq_tbl)
+                       return rc ?: -ENODEV;
+       }
+
        if (bp->flags & BNXT_FLAG_USING_MSIX)
                bnxt_setup_msix(bp);
        else
@@ -8744,7 +8752,7 @@ static int bnxt_init_inta(struct bnxt *bp)
 
 static int bnxt_init_int_mode(struct bnxt *bp)
 {
-       int rc = 0;
+       int rc = -ENODEV;
 
        if (bp->flags & BNXT_FLAG_MSIX_CAP)
                rc = bnxt_init_msix(bp);
@@ -9514,7 +9522,8 @@ static int bnxt_hwrm_if_change(struct bnxt *bp, bool up)
 {
        struct hwrm_func_drv_if_change_output *resp = bp->hwrm_cmd_resp_addr;
        struct hwrm_func_drv_if_change_input req = {0};
-       bool resc_reinit = false, fw_reset = false;
+       bool fw_reset = !bp->irq_tbl;
+       bool resc_reinit = false;
        int rc, retry = 0;
        u32 flags = 0;
 
@@ -9557,6 +9566,7 @@ static int bnxt_hwrm_if_change(struct bnxt *bp, bool up)
 
        if (test_bit(BNXT_STATE_IN_FW_RESET, &bp->state) && !fw_reset) {
                netdev_err(bp->dev, "RESET_DONE not set during FW reset.\n");
+               set_bit(BNXT_STATE_ABORT_ERR, &bp->state);
                return -ENODEV;
        }
        if (resc_reinit || fw_reset) {
@@ -9890,6 +9900,9 @@ static int bnxt_reinit_after_abort(struct bnxt *bp)
        if (test_bit(BNXT_STATE_IN_FW_RESET, &bp->state))
                return -EBUSY;
 
+       if (bp->dev->reg_state == NETREG_UNREGISTERED)
+               return -ENODEV;
+
        rc = bnxt_fw_init_one(bp);
        if (!rc) {
                bnxt_clear_int_mode(bp);
index 472bf8f..15362d0 100644 (file)
@@ -3954,6 +3954,13 @@ static int macb_init(struct platform_device *pdev)
        return 0;
 }
 
+static const struct macb_usrio_config macb_default_usrio = {
+       .mii = MACB_BIT(MII),
+       .rmii = MACB_BIT(RMII),
+       .rgmii = GEM_BIT(RGMII),
+       .refclk = MACB_BIT(CLKEN),
+};
+
 #if defined(CONFIG_OF)
 /* 1518 rounded up */
 #define AT91ETHER_MAX_RBUFF_SZ 0x600
@@ -4439,13 +4446,6 @@ static int fu540_c000_init(struct platform_device *pdev)
        return macb_init(pdev);
 }
 
-static const struct macb_usrio_config macb_default_usrio = {
-       .mii = MACB_BIT(MII),
-       .rmii = MACB_BIT(RMII),
-       .rgmii = GEM_BIT(RGMII),
-       .refclk = MACB_BIT(CLKEN),
-};
-
 static const struct macb_usrio_config sama7g5_usrio = {
        .mii = 0,
        .rmii = 1,
@@ -4594,6 +4594,7 @@ static const struct macb_config default_gem_config = {
        .dma_burst_length = 16,
        .clk_init = macb_clk_init,
        .init = macb_init,
+       .usrio = &macb_default_usrio,
        .jumbo_max_len = 10240,
 };
 
index 46a809f..169e10c 100644 (file)
@@ -672,7 +672,7 @@ static int chcr_ktls_cpl_act_open_rpl(struct adapter *adap,
        if (tx_info->pending_close) {
                spin_unlock(&tx_info->lock);
                if (!status) {
-                       /* it's a late success, tcb status is establised,
+                       /* it's a late success, tcb status is established,
                         * mark it close.
                         */
                        chcr_ktls_mark_tcb_close(tx_info);
@@ -930,7 +930,7 @@ chcr_ktls_get_tx_flits(u32 nr_frags, unsigned int key_ctx_len)
 }
 
 /*
- * chcr_ktls_check_tcp_options: To check if there is any TCP option availbale
+ * chcr_ktls_check_tcp_options: To check if there is any TCP option available
  * other than timestamp.
  * @skb - skb contains partial record..
  * return: 1 / 0
@@ -1115,7 +1115,7 @@ static int chcr_ktls_xmit_wr_complete(struct sk_buff *skb,
        }
 
        if (unlikely(credits < ETHTXQ_STOP_THRES)) {
-               /* Credits are below the threshold vaues, stop the queue after
+               /* Credits are below the threshold values, stop the queue after
                 * injecting the Work Request for this packet.
                 */
                chcr_eth_txq_stop(q);
@@ -2006,7 +2006,7 @@ static int chcr_ktls_xmit(struct sk_buff *skb, struct net_device *dev)
 
        /* TCP segments can be in received either complete or partial.
         * chcr_end_part_handler will handle cases if complete record or end
-        * part of the record is received. Incase of partial end part of record,
+        * part of the record is received. In case of partial end part of record,
         * we will send the complete record again.
         */
 
index 3fdc70d..252adfa 100644 (file)
@@ -133,6 +133,8 @@ struct board_info {
        u32             wake_state;
 
        int             ip_summed;
+
+       struct regulator *power_supply;
 };
 
 /* debug code */
@@ -1449,7 +1451,7 @@ dm9000_probe(struct platform_device *pdev)
                if (ret) {
                        dev_err(dev, "failed to request reset gpio %d: %d\n",
                                reset_gpios, ret);
-                       return -ENODEV;
+                       goto out_regulator_disable;
                }
 
                /* According to manual PWRST# Low Period Min 1ms */
@@ -1461,8 +1463,10 @@ dm9000_probe(struct platform_device *pdev)
 
        if (!pdata) {
                pdata = dm9000_parse_dt(&pdev->dev);
-               if (IS_ERR(pdata))
-                       return PTR_ERR(pdata);
+               if (IS_ERR(pdata)) {
+                       ret = PTR_ERR(pdata);
+                       goto out_regulator_disable;
+               }
        }
 
        /* Init network device */
@@ -1479,6 +1483,8 @@ dm9000_probe(struct platform_device *pdev)
 
        db->dev = &pdev->dev;
        db->ndev = ndev;
+       if (!IS_ERR(power))
+               db->power_supply = power;
 
        spin_lock_init(&db->lock);
        mutex_init(&db->addr_lock);
@@ -1501,7 +1507,7 @@ dm9000_probe(struct platform_device *pdev)
                goto out;
        }
 
-       db->irq_wake = platform_get_irq(pdev, 1);
+       db->irq_wake = platform_get_irq_optional(pdev, 1);
        if (db->irq_wake >= 0) {
                dev_dbg(db->dev, "wakeup irq %d\n", db->irq_wake);
 
@@ -1703,6 +1709,10 @@ out:
        dm9000_release_board(pdev, db);
        free_netdev(ndev);
 
+out_regulator_disable:
+       if (!IS_ERR(power))
+               regulator_disable(power);
+
        return ret;
 }
 
@@ -1760,10 +1770,13 @@ static int
 dm9000_drv_remove(struct platform_device *pdev)
 {
        struct net_device *ndev = platform_get_drvdata(pdev);
+       struct board_info *dm = to_dm9000_board(ndev);
 
        unregister_netdev(ndev);
-       dm9000_release_board(pdev, netdev_priv(ndev));
+       dm9000_release_board(pdev, dm);
        free_netdev(ndev);              /* free device structure */
+       if (dm->power_supply)
+               regulator_disable(dm->power_supply);
 
        dev_dbg(&pdev->dev, "released and freed device\n");
        return 0;
index c78d122..0947132 100644 (file)
@@ -281,6 +281,8 @@ static int enetc_poll(struct napi_struct *napi, int budget)
        int work_done;
        int i;
 
+       enetc_lock_mdio();
+
        for (i = 0; i < v->count_tx_rings; i++)
                if (!enetc_clean_tx_ring(&v->tx_ring[i], budget))
                        complete = false;
@@ -291,8 +293,10 @@ static int enetc_poll(struct napi_struct *napi, int budget)
        if (work_done)
                v->rx_napi_work = true;
 
-       if (!complete)
+       if (!complete) {
+               enetc_unlock_mdio();
                return budget;
+       }
 
        napi_complete_done(napi, work_done);
 
@@ -301,8 +305,6 @@ static int enetc_poll(struct napi_struct *napi, int budget)
 
        v->rx_napi_work = false;
 
-       enetc_lock_mdio();
-
        /* enable interrupts */
        enetc_wr_reg_hot(v->rbier, ENETC_RBIER_RXTIE);
 
@@ -327,8 +329,8 @@ static void enetc_get_tx_tstamp(struct enetc_hw *hw, union enetc_tx_bd *txbd,
 {
        u32 lo, hi, tstamp_lo;
 
-       lo = enetc_rd(hw, ENETC_SICTR0);
-       hi = enetc_rd(hw, ENETC_SICTR1);
+       lo = enetc_rd_hot(hw, ENETC_SICTR0);
+       hi = enetc_rd_hot(hw, ENETC_SICTR1);
        tstamp_lo = le32_to_cpu(txbd->wb.tstamp);
        if (lo <= tstamp_lo)
                hi -= 1;
@@ -342,6 +344,12 @@ static void enetc_tstamp_tx(struct sk_buff *skb, u64 tstamp)
        if (skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS) {
                memset(&shhwtstamps, 0, sizeof(shhwtstamps));
                shhwtstamps.hwtstamp = ns_to_ktime(tstamp);
+               /* Ensure skb_mstamp_ns, which might have been populated with
+                * the txtime, is not mistaken for a software timestamp,
+                * because this will prevent the dispatch of our hardware
+                * timestamp to the socket.
+                */
+               skb->tstamp = ktime_set(0, 0);
                skb_tstamp_tx(skb, &shhwtstamps);
        }
 }
@@ -358,9 +366,7 @@ static bool enetc_clean_tx_ring(struct enetc_bdr *tx_ring, int napi_budget)
        i = tx_ring->next_to_clean;
        tx_swbd = &tx_ring->tx_swbd[i];
 
-       enetc_lock_mdio();
        bds_to_clean = enetc_bd_ready_count(tx_ring, i);
-       enetc_unlock_mdio();
 
        do_tstamp = false;
 
@@ -403,8 +409,6 @@ static bool enetc_clean_tx_ring(struct enetc_bdr *tx_ring, int napi_budget)
                        tx_swbd = tx_ring->tx_swbd;
                }
 
-               enetc_lock_mdio();
-
                /* BD iteration loop end */
                if (is_eof) {
                        tx_frm_cnt++;
@@ -415,8 +419,6 @@ static bool enetc_clean_tx_ring(struct enetc_bdr *tx_ring, int napi_budget)
 
                if (unlikely(!bds_to_clean))
                        bds_to_clean = enetc_bd_ready_count(tx_ring, i);
-
-               enetc_unlock_mdio();
        }
 
        tx_ring->next_to_clean = i;
@@ -527,9 +529,8 @@ static void enetc_get_rx_tstamp(struct net_device *ndev,
 static void enetc_get_offloads(struct enetc_bdr *rx_ring,
                               union enetc_rx_bd *rxbd, struct sk_buff *skb)
 {
-#ifdef CONFIG_FSL_ENETC_PTP_CLOCK
        struct enetc_ndev_priv *priv = netdev_priv(rx_ring->ndev);
-#endif
+
        /* TODO: hashing */
        if (rx_ring->ndev->features & NETIF_F_RXCSUM) {
                u16 inet_csum = le16_to_cpu(rxbd->r.inet_csum);
@@ -538,12 +539,31 @@ static void enetc_get_offloads(struct enetc_bdr *rx_ring,
                skb->ip_summed = CHECKSUM_COMPLETE;
        }
 
-       /* copy VLAN to skb, if one is extracted, for now we assume it's a
-        * standard TPID, but HW also supports custom values
-        */
-       if (le16_to_cpu(rxbd->r.flags) & ENETC_RXBD_FLAG_VLAN)
-               __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
-                                      le16_to_cpu(rxbd->r.vlan_opt));
+       if (le16_to_cpu(rxbd->r.flags) & ENETC_RXBD_FLAG_VLAN) {
+               __be16 tpid = 0;
+
+               switch (le16_to_cpu(rxbd->r.flags) & ENETC_RXBD_FLAG_TPID) {
+               case 0:
+                       tpid = htons(ETH_P_8021Q);
+                       break;
+               case 1:
+                       tpid = htons(ETH_P_8021AD);
+                       break;
+               case 2:
+                       tpid = htons(enetc_port_rd(&priv->si->hw,
+                                                  ENETC_PCVLANR1));
+                       break;
+               case 3:
+                       tpid = htons(enetc_port_rd(&priv->si->hw,
+                                                  ENETC_PCVLANR2));
+                       break;
+               default:
+                       break;
+               }
+
+               __vlan_hwaccel_put_tag(skb, tpid, le16_to_cpu(rxbd->r.vlan_opt));
+       }
+
 #ifdef CONFIG_FSL_ENETC_PTP_CLOCK
        if (priv->active_offloads & ENETC_F_RX_TSTAMP)
                enetc_get_rx_tstamp(rx_ring->ndev, rxbd, skb);
@@ -660,8 +680,6 @@ static int enetc_clean_rx_ring(struct enetc_bdr *rx_ring,
                u32 bd_status;
                u16 size;
 
-               enetc_lock_mdio();
-
                if (cleaned_cnt >= ENETC_RXBD_BUNDLE) {
                        int count = enetc_refill_rx_ring(rx_ring, cleaned_cnt);
 
@@ -672,19 +690,15 @@ static int enetc_clean_rx_ring(struct enetc_bdr *rx_ring,
 
                rxbd = enetc_rxbd(rx_ring, i);
                bd_status = le32_to_cpu(rxbd->r.lstatus);
-               if (!bd_status) {
-                       enetc_unlock_mdio();
+               if (!bd_status)
                        break;
-               }
 
                enetc_wr_reg_hot(rx_ring->idr, BIT(rx_ring->index));
                dma_rmb(); /* for reading other rxbd fields */
                size = le16_to_cpu(rxbd->r.buf_len);
                skb = enetc_map_rx_buff_to_skb(rx_ring, i, size);
-               if (!skb) {
-                       enetc_unlock_mdio();
+               if (!skb)
                        break;
-               }
 
                enetc_get_offloads(rx_ring, rxbd, skb);
 
@@ -696,7 +710,6 @@ static int enetc_clean_rx_ring(struct enetc_bdr *rx_ring,
 
                if (unlikely(bd_status &
                             ENETC_RXBD_LSTATUS(ENETC_RXBD_ERR_MASK))) {
-                       enetc_unlock_mdio();
                        dev_kfree_skb(skb);
                        while (!(bd_status & ENETC_RXBD_LSTATUS_F)) {
                                dma_rmb();
@@ -736,8 +749,6 @@ static int enetc_clean_rx_ring(struct enetc_bdr *rx_ring,
 
                enetc_process_skb(rx_ring, skb);
 
-               enetc_unlock_mdio();
-
                napi_gro_receive(napi, skb);
 
                rx_frm_cnt++;
@@ -984,7 +995,7 @@ static void enetc_free_rxtx_rings(struct enetc_ndev_priv *priv)
                enetc_free_tx_ring(priv->tx_ring[i]);
 }
 
-static int enetc_alloc_cbdr(struct device *dev, struct enetc_cbdr *cbdr)
+int enetc_alloc_cbdr(struct device *dev, struct enetc_cbdr *cbdr)
 {
        int size = cbdr->bd_count * sizeof(struct enetc_cbd);
 
@@ -1005,7 +1016,7 @@ static int enetc_alloc_cbdr(struct device *dev, struct enetc_cbdr *cbdr)
        return 0;
 }
 
-static void enetc_free_cbdr(struct device *dev, struct enetc_cbdr *cbdr)
+void enetc_free_cbdr(struct device *dev, struct enetc_cbdr *cbdr)
 {
        int size = cbdr->bd_count * sizeof(struct enetc_cbd);
 
@@ -1013,7 +1024,7 @@ static void enetc_free_cbdr(struct device *dev, struct enetc_cbdr *cbdr)
        cbdr->bd_base = NULL;
 }
 
-static void enetc_setup_cbdr(struct enetc_hw *hw, struct enetc_cbdr *cbdr)
+void enetc_setup_cbdr(struct enetc_hw *hw, struct enetc_cbdr *cbdr)
 {
        /* set CBDR cache attributes */
        enetc_wr(hw, ENETC_SICAR2,
@@ -1033,7 +1044,7 @@ static void enetc_setup_cbdr(struct enetc_hw *hw, struct enetc_cbdr *cbdr)
        cbdr->cir = hw->reg + ENETC_SICBDRCIR;
 }
 
-static void enetc_clear_cbdr(struct enetc_hw *hw)
+void enetc_clear_cbdr(struct enetc_hw *hw)
 {
        enetc_wr(hw, ENETC_SICBDRMR, 0);
 }
@@ -1058,13 +1069,12 @@ static int enetc_setup_default_rss_table(struct enetc_si *si, int num_groups)
        return 0;
 }
 
-static int enetc_configure_si(struct enetc_ndev_priv *priv)
+int enetc_configure_si(struct enetc_ndev_priv *priv)
 {
        struct enetc_si *si = priv->si;
        struct enetc_hw *hw = &si->hw;
        int err;
 
-       enetc_setup_cbdr(hw, &si->cbd_ring);
        /* set SI cache attributes */
        enetc_wr(hw, ENETC_SICAR0,
                 ENETC_SICAR_RD_COHERENT | ENETC_SICAR_WR_COHERENT);
@@ -1112,6 +1122,8 @@ int enetc_alloc_si_resources(struct enetc_ndev_priv *priv)
        if (err)
                return err;
 
+       enetc_setup_cbdr(&si->hw, &si->cbd_ring);
+
        priv->cls_rules = kcalloc(si->num_fs_entries, sizeof(*priv->cls_rules),
                                  GFP_KERNEL);
        if (!priv->cls_rules) {
@@ -1119,14 +1131,8 @@ int enetc_alloc_si_resources(struct enetc_ndev_priv *priv)
                goto err_alloc_cls;
        }
 
-       err = enetc_configure_si(priv);
-       if (err)
-               goto err_config_si;
-
        return 0;
 
-err_config_si:
-       kfree(priv->cls_rules);
 err_alloc_cls:
        enetc_clear_cbdr(&si->hw);
        enetc_free_cbdr(priv->dev, &si->cbd_ring);
@@ -1212,7 +1218,8 @@ static void enetc_setup_rxbdr(struct enetc_hw *hw, struct enetc_bdr *rx_ring)
        rx_ring->idr = hw->reg + ENETC_SIRXIDR;
 
        enetc_refill_rx_ring(rx_ring, enetc_bd_unused(rx_ring));
-       enetc_wr(hw, ENETC_SIRXIDR, rx_ring->next_to_use);
+       /* update ENETC's consumer index */
+       enetc_rxbdr_wr(hw, idx, ENETC_RBCIR, rx_ring->next_to_use);
 
        /* enable ring */
        enetc_rxbdr_wr(hw, idx, ENETC_RBMR, rbmr);
index 8532d23..8b380fc 100644 (file)
@@ -292,6 +292,7 @@ void enetc_get_si_caps(struct enetc_si *si);
 void enetc_init_si_rings_params(struct enetc_ndev_priv *priv);
 int enetc_alloc_si_resources(struct enetc_ndev_priv *priv);
 void enetc_free_si_resources(struct enetc_ndev_priv *priv);
+int enetc_configure_si(struct enetc_ndev_priv *priv);
 
 int enetc_open(struct net_device *ndev);
 int enetc_close(struct net_device *ndev);
@@ -309,6 +310,10 @@ int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
 void enetc_set_ethtool_ops(struct net_device *ndev);
 
 /* control buffer descriptor ring (CBDR) */
+int enetc_alloc_cbdr(struct device *dev, struct enetc_cbdr *cbdr);
+void enetc_free_cbdr(struct device *dev, struct enetc_cbdr *cbdr);
+void enetc_setup_cbdr(struct enetc_hw *hw, struct enetc_cbdr *cbdr);
+void enetc_clear_cbdr(struct enetc_hw *hw);
 int enetc_set_mac_flt_entry(struct enetc_si *si, int index,
                            char *mac_addr, int si_map);
 int enetc_clear_mac_flt_entry(struct enetc_si *si, int index);
index c71fe8d..00938f7 100644 (file)
@@ -172,6 +172,8 @@ enum enetc_bdr_type {TX, RX};
 #define ENETC_PSIPMAR0(n)      (0x0100 + (n) * 0x8) /* n = SI index */
 #define ENETC_PSIPMAR1(n)      (0x0104 + (n) * 0x8)
 #define ENETC_PVCLCTR          0x0208
+#define ENETC_PCVLANR1         0x0210
+#define ENETC_PCVLANR2         0x0214
 #define ENETC_VLAN_TYPE_C      BIT(0)
 #define ENETC_VLAN_TYPE_S      BIT(1)
 #define ENETC_PVCLCTR_OVTPIDL(bmp)     ((bmp) & 0xff) /* VLAN_TYPE */
@@ -232,14 +234,23 @@ enum enetc_bdr_type {TX, RX};
 #define ENETC_PM0_MAXFRM       0x8014
 #define ENETC_SET_TX_MTU(val)  ((val) << 16)
 #define ENETC_SET_MAXFRM(val)  ((val) & 0xffff)
+#define ENETC_PM0_RX_FIFO      0x801c
+#define ENETC_PM0_RX_FIFO_VAL  1
 
 #define ENETC_PM_IMDIO_BASE    0x8030
 
 #define ENETC_PM0_IF_MODE      0x8300
-#define ENETC_PMO_IFM_RG       BIT(2)
+#define ENETC_PM0_IFM_RG       BIT(2)
 #define ENETC_PM0_IFM_RLP      (BIT(5) | BIT(11))
-#define ENETC_PM0_IFM_RGAUTO   (BIT(15) | ENETC_PMO_IFM_RG | BIT(1))
-#define ENETC_PM0_IFM_XGMII    BIT(12)
+#define ENETC_PM0_IFM_EN_AUTO  BIT(15)
+#define ENETC_PM0_IFM_SSP_MASK GENMASK(14, 13)
+#define ENETC_PM0_IFM_SSP_1000 (2 << 13)
+#define ENETC_PM0_IFM_SSP_100  (0 << 13)
+#define ENETC_PM0_IFM_SSP_10   (1 << 13)
+#define ENETC_PM0_IFM_FULL_DPX BIT(12)
+#define ENETC_PM0_IFM_IFMODE_MASK GENMASK(1, 0)
+#define ENETC_PM0_IFM_IFMODE_XGMII 0
+#define ENETC_PM0_IFM_IFMODE_GMII 2
 #define ENETC_PSIDCAPR         0x1b08
 #define ENETC_PSIDCAPR_MSK     GENMASK(15, 0)
 #define ENETC_PSFCAPR          0x1b18
@@ -453,6 +464,8 @@ static inline u64 _enetc_rd_reg64_wa(void __iomem *reg)
 #define enetc_wr_reg(reg, val)         _enetc_wr_reg_wa((reg), (val))
 #define enetc_rd(hw, off)              enetc_rd_reg((hw)->reg + (off))
 #define enetc_wr(hw, off, val)         enetc_wr_reg((hw)->reg + (off), val)
+#define enetc_rd_hot(hw, off)          enetc_rd_reg_hot((hw)->reg + (off))
+#define enetc_wr_hot(hw, off, val)     enetc_wr_reg_hot((hw)->reg + (off), val)
 #define enetc_rd64(hw, off)            _enetc_rd_reg64_wa((hw)->reg + (off))
 /* port register accessors - PF only */
 #define enetc_port_rd(hw, off)         enetc_rd_reg((hw)->port + (off))
@@ -568,6 +581,7 @@ union enetc_rx_bd {
 #define ENETC_RXBD_LSTATUS(flags)      ((flags) << 16)
 #define ENETC_RXBD_FLAG_VLAN   BIT(9)
 #define ENETC_RXBD_FLAG_TSTMP  BIT(10)
+#define ENETC_RXBD_FLAG_TPID   GENMASK(1, 0)
 
 #define ENETC_MAC_ADDR_FILT_CNT        8 /* # of supported entries per port */
 #define EMETC_MAC_ADDR_FILT_RES        3 /* # of reserved entries at the beginning */
index 515c5b2..224fc37 100644 (file)
@@ -190,7 +190,6 @@ static void enetc_pf_set_rx_mode(struct net_device *ndev)
 {
        struct enetc_ndev_priv *priv = netdev_priv(ndev);
        struct enetc_pf *pf = enetc_si_priv(priv->si);
-       char vlan_promisc_simap = pf->vlan_promisc_simap;
        struct enetc_hw *hw = &priv->si->hw;
        bool uprom = false, mprom = false;
        struct enetc_mac_filter *filter;
@@ -203,16 +202,12 @@ static void enetc_pf_set_rx_mode(struct net_device *ndev)
                psipmr = ENETC_PSIPMR_SET_UP(0) | ENETC_PSIPMR_SET_MP(0);
                uprom = true;
                mprom = true;
-               /* Enable VLAN promiscuous mode for SI0 (PF) */
-               vlan_promisc_simap |= BIT(0);
        } else if (ndev->flags & IFF_ALLMULTI) {
                /* enable multi cast promisc mode for SI0 (PF) */
                psipmr = ENETC_PSIPMR_SET_MP(0);
                mprom = true;
        }
 
-       enetc_set_vlan_promisc(&pf->si->hw, vlan_promisc_simap);
-
        /* first 2 filter entries belong to PF */
        if (!uprom) {
                /* Update unicast filters */
@@ -320,7 +315,7 @@ static void enetc_set_loopback(struct net_device *ndev, bool en)
        u32 reg;
 
        reg = enetc_port_rd(hw, ENETC_PM0_IF_MODE);
-       if (reg & ENETC_PMO_IFM_RG) {
+       if (reg & ENETC_PM0_IFM_RG) {
                /* RGMII mode */
                reg = (reg & ~ENETC_PM0_IFM_RLP) |
                      (en ? ENETC_PM0_IFM_RLP : 0);
@@ -495,17 +490,30 @@ static void enetc_configure_port_mac(struct enetc_hw *hw)
 
        enetc_port_wr(hw, ENETC_PM1_CMD_CFG, ENETC_PM0_CMD_PHY_TX_EN |
                      ENETC_PM0_CMD_TXP | ENETC_PM0_PROMISC);
+
+       /* On LS1028A, the MAC RX FIFO defaults to 2, which is too high
+        * and may lead to RX lock-up under traffic. Set it to 1 instead,
+        * as recommended by the hardware team.
+        */
+       enetc_port_wr(hw, ENETC_PM0_RX_FIFO, ENETC_PM0_RX_FIFO_VAL);
 }
 
 static void enetc_mac_config(struct enetc_hw *hw, phy_interface_t phy_mode)
 {
-       /* set auto-speed for RGMII */
-       if (enetc_port_rd(hw, ENETC_PM0_IF_MODE) & ENETC_PMO_IFM_RG ||
-           phy_interface_mode_is_rgmii(phy_mode))
-               enetc_port_wr(hw, ENETC_PM0_IF_MODE, ENETC_PM0_IFM_RGAUTO);
+       u32 val;
+
+       if (phy_interface_mode_is_rgmii(phy_mode)) {
+               val = enetc_port_rd(hw, ENETC_PM0_IF_MODE);
+               val &= ~ENETC_PM0_IFM_EN_AUTO;
+               val &= ENETC_PM0_IFM_IFMODE_MASK;
+               val |= ENETC_PM0_IFM_IFMODE_GMII | ENETC_PM0_IFM_RG;
+               enetc_port_wr(hw, ENETC_PM0_IF_MODE, val);
+       }
 
-       if (phy_mode == PHY_INTERFACE_MODE_USXGMII)
-               enetc_port_wr(hw, ENETC_PM0_IF_MODE, ENETC_PM0_IFM_XGMII);
+       if (phy_mode == PHY_INTERFACE_MODE_USXGMII) {
+               val = ENETC_PM0_IFM_FULL_DPX | ENETC_PM0_IFM_IFMODE_XGMII;
+               enetc_port_wr(hw, ENETC_PM0_IF_MODE, val);
+       }
 }
 
 static void enetc_mac_enable(struct enetc_hw *hw, bool en)
@@ -937,6 +945,34 @@ static void enetc_pl_mac_config(struct phylink_config *config,
                phylink_set_pcs(priv->phylink, &pf->pcs->pcs);
 }
 
+static void enetc_force_rgmii_mac(struct enetc_hw *hw, int speed, int duplex)
+{
+       u32 old_val, val;
+
+       old_val = val = enetc_port_rd(hw, ENETC_PM0_IF_MODE);
+
+       if (speed == SPEED_1000) {
+               val &= ~ENETC_PM0_IFM_SSP_MASK;
+               val |= ENETC_PM0_IFM_SSP_1000;
+       } else if (speed == SPEED_100) {
+               val &= ~ENETC_PM0_IFM_SSP_MASK;
+               val |= ENETC_PM0_IFM_SSP_100;
+       } else if (speed == SPEED_10) {
+               val &= ~ENETC_PM0_IFM_SSP_MASK;
+               val |= ENETC_PM0_IFM_SSP_10;
+       }
+
+       if (duplex == DUPLEX_FULL)
+               val |= ENETC_PM0_IFM_FULL_DPX;
+       else
+               val &= ~ENETC_PM0_IFM_FULL_DPX;
+
+       if (val == old_val)
+               return;
+
+       enetc_port_wr(hw, ENETC_PM0_IF_MODE, val);
+}
+
 static void enetc_pl_mac_link_up(struct phylink_config *config,
                                 struct phy_device *phy, unsigned int mode,
                                 phy_interface_t interface, int speed,
@@ -949,6 +985,10 @@ static void enetc_pl_mac_link_up(struct phylink_config *config,
        if (priv->active_offloads & ENETC_F_QBV)
                enetc_sched_speed_set(priv, speed);
 
+       if (!phylink_autoneg_inband(mode) &&
+           phy_interface_mode_is_rgmii(interface))
+               enetc_force_rgmii_mac(&pf->si->hw, speed, duplex);
+
        enetc_mac_enable(&pf->si->hw, true);
 }
 
@@ -1041,6 +1081,26 @@ static int enetc_init_port_rss_memory(struct enetc_si *si)
        return err;
 }
 
+static void enetc_init_unused_port(struct enetc_si *si)
+{
+       struct device *dev = &si->pdev->dev;
+       struct enetc_hw *hw = &si->hw;
+       int err;
+
+       si->cbd_ring.bd_count = ENETC_CBDR_DEFAULT_SIZE;
+       err = enetc_alloc_cbdr(dev, &si->cbd_ring);
+       if (err)
+               return;
+
+       enetc_setup_cbdr(hw, &si->cbd_ring);
+
+       enetc_init_port_rfs_memory(si);
+       enetc_init_port_rss_memory(si);
+
+       enetc_clear_cbdr(hw);
+       enetc_free_cbdr(dev, &si->cbd_ring);
+}
+
 static int enetc_pf_probe(struct pci_dev *pdev,
                          const struct pci_device_id *ent)
 {
@@ -1051,11 +1111,6 @@ static int enetc_pf_probe(struct pci_dev *pdev,
        struct enetc_pf *pf;
        int err;
 
-       if (node && !of_device_is_available(node)) {
-               dev_info(&pdev->dev, "device is disabled, skipping\n");
-               return -ENODEV;
-       }
-
        err = enetc_pci_probe(pdev, KBUILD_MODNAME, sizeof(*pf));
        if (err) {
                dev_err(&pdev->dev, "PCI probing failed\n");
@@ -1069,6 +1124,13 @@ static int enetc_pf_probe(struct pci_dev *pdev,
                goto err_map_pf_space;
        }
 
+       if (node && !of_device_is_available(node)) {
+               enetc_init_unused_port(si);
+               dev_info(&pdev->dev, "device is disabled, skipping\n");
+               err = -ENODEV;
+               goto err_device_disabled;
+       }
+
        pf = enetc_si_priv(si);
        pf->si = si;
        pf->total_vfs = pci_sriov_get_totalvfs(pdev);
@@ -1108,6 +1170,12 @@ static int enetc_pf_probe(struct pci_dev *pdev,
                goto err_init_port_rss;
        }
 
+       err = enetc_configure_si(priv);
+       if (err) {
+               dev_err(&pdev->dev, "Failed to configure SI\n");
+               goto err_config_si;
+       }
+
        err = enetc_alloc_msix(priv);
        if (err) {
                dev_err(&pdev->dev, "MSIX alloc failed\n");
@@ -1136,6 +1204,7 @@ err_phylink_create:
        enetc_mdiobus_destroy(pf);
 err_mdiobus_create:
        enetc_free_msix(priv);
+err_config_si:
 err_init_port_rss:
 err_init_port_rfs:
 err_alloc_msix:
@@ -1144,6 +1213,7 @@ err_alloc_si_res:
        si->ndev = NULL;
        free_netdev(ndev);
 err_alloc_netdev:
+err_device_disabled:
 err_map_pf_space:
        enetc_pci_remove(pdev);
 
index 39c1a09..9b755a8 100644 (file)
@@ -171,6 +171,12 @@ static int enetc_vf_probe(struct pci_dev *pdev,
                goto err_alloc_si_res;
        }
 
+       err = enetc_configure_si(priv);
+       if (err) {
+               dev_err(&pdev->dev, "Failed to configure SI\n");
+               goto err_config_si;
+       }
+
        err = enetc_alloc_msix(priv);
        if (err) {
                dev_err(&pdev->dev, "MSIX alloc failed\n");
@@ -187,6 +193,7 @@ static int enetc_vf_probe(struct pci_dev *pdev,
 
 err_reg_netdev:
        enetc_free_msix(priv);
+err_config_si:
 err_alloc_msix:
        enetc_free_si_resources(priv);
 err_alloc_si_res:
index 2e344aa..1753807 100644 (file)
@@ -377,9 +377,16 @@ static int fec_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
        u64 ns;
        unsigned long flags;
 
+       mutex_lock(&adapter->ptp_clk_mutex);
+       /* Check the ptp clock */
+       if (!adapter->ptp_clk_on) {
+               mutex_unlock(&adapter->ptp_clk_mutex);
+               return -EINVAL;
+       }
        spin_lock_irqsave(&adapter->tmreg_lock, flags);
        ns = timecounter_read(&adapter->tc);
        spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
+       mutex_unlock(&adapter->ptp_clk_mutex);
 
        *ts = ns_to_timespec64(ns);
 
index 541de32..1cf8ef7 100644 (file)
@@ -2390,6 +2390,10 @@ static bool gfar_add_rx_frag(struct gfar_rx_buff *rxb, u32 lstatus,
                if (lstatus & BD_LFLAG(RXBD_LAST))
                        size -= skb->len;
 
+               WARN(size < 0, "gianfar: rx fragment size underflow");
+               if (size < 0)
+                       return false;
+
                skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
                                rxb->page_offset + RXBUF_ALIGNMENT,
                                size, GFAR_RXB_TRUESIZE);
@@ -2552,6 +2556,17 @@ static int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue,
                if (lstatus & BD_LFLAG(RXBD_EMPTY))
                        break;
 
+               /* lost RXBD_LAST descriptor due to overrun */
+               if (skb &&
+                   (lstatus & BD_LFLAG(RXBD_FIRST))) {
+                       /* discard faulty buffer */
+                       dev_kfree_skb(skb);
+                       skb = NULL;
+                       rx_queue->stats.rx_dropped++;
+
+                       /* can continue normally */
+               }
+
                /* order rx buffer descriptor reads */
                rmb();
 
index 5d7824d..c66a7a5 100644 (file)
@@ -1663,8 +1663,10 @@ static int hns_nic_clear_all_rx_fetch(struct net_device *ndev)
                        for (j = 0; j < fetch_num; j++) {
                                /* alloc one skb and init */
                                skb = hns_assemble_skb(ndev);
-                               if (!skb)
+                               if (!skb) {
+                                       ret = -ENOMEM;
                                        goto out;
+                               }
                                rd = &tx_ring_data(priv, skb->queue_mapping);
                                hns_nic_net_xmit_hw(ndev, skb, rd);
 
index ff52a65..057dda7 100644 (file)
@@ -1053,16 +1053,16 @@ struct hclge_fd_tcam_config_3_cmd {
 #define HCLGE_FD_AD_DROP_B             0
 #define HCLGE_FD_AD_DIRECT_QID_B       1
 #define HCLGE_FD_AD_QID_S              2
-#define HCLGE_FD_AD_QID_M              GENMASK(12, 2)
+#define HCLGE_FD_AD_QID_M              GENMASK(11, 2)
 #define HCLGE_FD_AD_USE_COUNTER_B      12
 #define HCLGE_FD_AD_COUNTER_NUM_S      13
 #define HCLGE_FD_AD_COUNTER_NUM_M      GENMASK(20, 13)
 #define HCLGE_FD_AD_NXT_STEP_B         20
 #define HCLGE_FD_AD_NXT_KEY_S          21
-#define HCLGE_FD_AD_NXT_KEY_M          GENMASK(26, 21)
+#define HCLGE_FD_AD_NXT_KEY_M          GENMASK(25, 21)
 #define HCLGE_FD_AD_WR_RULE_ID_B       0
 #define HCLGE_FD_AD_RULE_ID_S          1
-#define HCLGE_FD_AD_RULE_ID_M          GENMASK(13, 1)
+#define HCLGE_FD_AD_RULE_ID_M          GENMASK(12, 1)
 #define HCLGE_FD_AD_TC_OVRD_B          16
 #define HCLGE_FD_AD_TC_SIZE_S          17
 #define HCLGE_FD_AD_TC_SIZE_M          GENMASK(20, 17)
index 34b744d..e3f81c7 100644 (file)
@@ -5245,9 +5245,9 @@ static bool hclge_fd_convert_tuple(u32 tuple_bit, u8 *key_x, u8 *key_y,
        case BIT(INNER_SRC_MAC):
                for (i = 0; i < ETH_ALEN; i++) {
                        calc_x(key_x[ETH_ALEN - 1 - i], rule->tuples.src_mac[i],
-                              rule->tuples.src_mac[i]);
+                              rule->tuples_mask.src_mac[i]);
                        calc_y(key_y[ETH_ALEN - 1 - i], rule->tuples.src_mac[i],
-                              rule->tuples.src_mac[i]);
+                              rule->tuples_mask.src_mac[i]);
                }
 
                return true;
@@ -6330,8 +6330,7 @@ static void hclge_fd_get_ext_info(struct ethtool_rx_flow_spec *fs,
                fs->h_ext.vlan_tci = cpu_to_be16(rule->tuples.vlan_tag1);
                fs->m_ext.vlan_tci =
                                rule->unused_tuple & BIT(INNER_VLAN_TAG_FST) ?
-                               cpu_to_be16(VLAN_VID_MASK) :
-                               cpu_to_be16(rule->tuples_mask.vlan_tag1);
+                               0 : cpu_to_be16(rule->tuples_mask.vlan_tag1);
        }
 
        if (fs->flow_type & FLOW_MAC_EXT) {
index c3ec9ce..7fea9ae 100644 (file)
@@ -1758,7 +1758,7 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
        return 0;
 }
 
-static int ibmveth_remove(struct vio_dev *dev)
+static void ibmveth_remove(struct vio_dev *dev)
 {
        struct net_device *netdev = dev_get_drvdata(&dev->dev);
        struct ibmveth_adapter *adapter = netdev_priv(netdev);
@@ -1771,8 +1771,6 @@ static int ibmveth_remove(struct vio_dev *dev)
 
        free_netdev(netdev);
        dev_set_drvdata(&dev->dev, NULL);
-
-       return 0;
 }
 
 static struct attribute veth_active_attr;
index 118a4bd..9c6438d 100644 (file)
@@ -78,7 +78,6 @@ MODULE_LICENSE("GPL");
 MODULE_VERSION(IBMVNIC_DRIVER_VERSION);
 
 static int ibmvnic_version = IBMVNIC_INITIAL_VERSION;
-static int ibmvnic_remove(struct vio_dev *);
 static void release_sub_crqs(struct ibmvnic_adapter *, bool);
 static int ibmvnic_reset_crq(struct ibmvnic_adapter *);
 static int ibmvnic_send_crq_init(struct ibmvnic_adapter *);
@@ -1906,10 +1905,9 @@ static int ibmvnic_set_mac(struct net_device *netdev, void *p)
        if (!is_valid_ether_addr(addr->sa_data))
                return -EADDRNOTAVAIL;
 
-       if (adapter->state != VNIC_PROBED) {
-               ether_addr_copy(adapter->mac_addr, addr->sa_data);
+       ether_addr_copy(adapter->mac_addr, addr->sa_data);
+       if (adapter->state != VNIC_PROBED)
                rc = __ibmvnic_set_mac(netdev, addr->sa_data);
-       }
 
        return rc;
 }
@@ -5219,16 +5217,14 @@ static int ibmvnic_reset_init(struct ibmvnic_adapter *adapter, bool reset)
 {
        struct device *dev = &adapter->vdev->dev;
        unsigned long timeout = msecs_to_jiffies(20000);
-       u64 old_num_rx_queues, old_num_tx_queues;
+       u64 old_num_rx_queues = adapter->req_rx_queues;
+       u64 old_num_tx_queues = adapter->req_tx_queues;
        int rc;
 
        adapter->from_passive_init = false;
 
-       if (reset) {
-               old_num_rx_queues = adapter->req_rx_queues;
-               old_num_tx_queues = adapter->req_tx_queues;
+       if (reset)
                reinit_completion(&adapter->init_done);
-       }
 
        adapter->init_done_rc = 0;
        rc = ibmvnic_send_crq_init(adapter);
@@ -5396,7 +5392,7 @@ ibmvnic_init_fail:
        return rc;
 }
 
-static int ibmvnic_remove(struct vio_dev *dev)
+static void ibmvnic_remove(struct vio_dev *dev)
 {
        struct net_device *netdev = dev_get_drvdata(&dev->dev);
        struct ibmvnic_adapter *adapter = netdev_priv(netdev);
@@ -5411,9 +5407,9 @@ static int ibmvnic_remove(struct vio_dev *dev)
         * after setting state, so __ibmvnic_reset() which is called
         * from the flush_work() below, can make progress.
         */
-       spin_lock_irqsave(&adapter->rwi_lock, flags);
+       spin_lock(&adapter->rwi_lock);
        adapter->state = VNIC_REMOVING;
-       spin_unlock_irqrestore(&adapter->rwi_lock, flags);
+       spin_unlock(&adapter->rwi_lock);
 
        spin_unlock_irqrestore(&adapter->state_lock, flags);
 
@@ -5437,8 +5433,6 @@ static int ibmvnic_remove(struct vio_dev *dev)
        device_remove_file(&dev->dev, &dev_attr_failover);
        free_netdev(netdev);
        dev_set_drvdata(&dev->dev, NULL);
-
-       return 0;
 }
 
 static ssize_t failover_store(struct device *dev, struct device_attribute *attr,
index 0a867d6..dc5b3c0 100644 (file)
@@ -1776,7 +1776,8 @@ static int iavf_init_get_resources(struct iavf_adapter *adapter)
                goto err_alloc;
        }
 
-       if (iavf_process_config(adapter))
+       err = iavf_process_config(adapter);
+       if (err)
                goto err_alloc;
        adapter->current_op = VIRTCHNL_OP_UNKNOWN;
 
index eca7352..54d4726 100644 (file)
@@ -575,6 +575,11 @@ static int ixgbe_ipsec_add_sa(struct xfrm_state *xs)
                return -EINVAL;
        }
 
+       if (xs->props.mode != XFRM_MODE_TRANSPORT) {
+               netdev_err(dev, "Unsupported mode for ipsec offload\n");
+               return -EINVAL;
+       }
+
        if (ixgbe_ipsec_check_mgmt_ip(xs)) {
                netdev_err(dev, "IPsec IP addr clash with mgmt filters\n");
                return -EINVAL;
index fae8420..9f3f12e 100644 (file)
@@ -9565,8 +9565,10 @@ static int ixgbe_configure_clsu32(struct ixgbe_adapter *adapter,
        ixgbe_atr_compute_perfect_hash_82599(&input->filter, mask);
        err = ixgbe_fdir_write_perfect_filter_82599(hw, &input->filter,
                                                    input->sw_idx, queue);
-       if (!err)
-               ixgbe_update_ethtool_fdir_entry(adapter, input, input->sw_idx);
+       if (err)
+               goto err_out_w_lock;
+
+       ixgbe_update_ethtool_fdir_entry(adapter, input, input->sw_idx);
        spin_unlock(&adapter->fdir_perfect_lock);
 
        if ((uhtid != 0x800) && (adapter->jump_tables[uhtid]))
index 5170dd9..caaea2c 100644 (file)
@@ -272,6 +272,11 @@ static int ixgbevf_ipsec_add_sa(struct xfrm_state *xs)
                return -EINVAL;
        }
 
+       if (xs->props.mode != XFRM_MODE_TRANSPORT) {
+               netdev_err(dev, "Unsupported mode for ipsec offload\n");
+               return -EINVAL;
+       }
+
        if (xs->xso.flags & XFRM_OFFLOAD_INBOUND) {
                struct rx_sa rsa;
 
index 9caa375..68deae5 100644 (file)
@@ -56,7 +56,9 @@ static bool is_dev_rpm(void *cgxd)
 
 bool is_lmac_valid(struct cgx *cgx, int lmac_id)
 {
-       return cgx && test_bit(lmac_id, &cgx->lmac_bmap);
+       if (!cgx || lmac_id < 0 || lmac_id >= MAX_LMAC_PER_CGX)
+               return false;
+       return test_bit(lmac_id, &cgx->lmac_bmap);
 }
 
 struct mac_ops *get_mac_ops(void *cgxd)
index a8641a4..96d2891 100644 (file)
@@ -1225,8 +1225,6 @@ static int mtk_star_receive_packet(struct mtk_star_priv *priv)
                goto push_new_skb;
        }
 
-       desc_data.dma_addr = new_dma_addr;
-
        /* We can't fail anymore at this point: it's safe to unmap the skb. */
        mtk_star_dma_unmap_rx(priv, &desc_data);
 
@@ -1236,6 +1234,9 @@ static int mtk_star_receive_packet(struct mtk_star_priv *priv)
        desc_data.skb->dev = ndev;
        netif_receive_skb(desc_data.skb);
 
+       /* update dma_addr for new skb */
+       desc_data.dma_addr = new_dma_addr;
+
 push_new_skb:
        desc_data.len = skb_tailroom(new_skb);
        desc_data.skb = new_skb;
index 23849f2..1434df6 100644 (file)
@@ -47,7 +47,7 @@
 #define EN_ETHTOOL_SHORT_MASK cpu_to_be16(0xffff)
 #define EN_ETHTOOL_WORD_MASK  cpu_to_be32(0xffffffff)
 
-static int mlx4_en_moderation_update(struct mlx4_en_priv *priv)
+int mlx4_en_moderation_update(struct mlx4_en_priv *priv)
 {
        int i, t;
        int err = 0;
index 51b9700..5d0c9c6 100644 (file)
@@ -3554,6 +3554,8 @@ int mlx4_en_reset_config(struct net_device *dev,
                        en_err(priv, "Failed starting port\n");
        }
 
+       if (!err)
+               err = mlx4_en_moderation_update(priv);
 out:
        mutex_unlock(&mdev->state_lock);
        kfree(tmp);
index e8ed231..f3d1a20 100644 (file)
@@ -775,6 +775,7 @@ void mlx4_en_ptp_overflow_check(struct mlx4_en_dev *mdev);
 #define DEV_FEATURE_CHANGED(dev, new_features, feature) \
        ((dev->features & feature) ^ (new_features & feature))
 
+int mlx4_en_moderation_update(struct mlx4_en_priv *priv);
 int mlx4_en_reset_config(struct net_device *dev,
                         struct hwtstamp_config ts_config,
                         netdev_features_t new_features);
index 16e2df6..c4adc7f 100644 (file)
@@ -4430,6 +4430,7 @@ MLXSW_ITEM32(reg, ptys, ext_eth_proto_cap, 0x08, 0, 32);
 #define MLXSW_REG_PTYS_ETH_SPEED_100GBASE_CR4          BIT(20)
 #define MLXSW_REG_PTYS_ETH_SPEED_100GBASE_SR4          BIT(21)
 #define MLXSW_REG_PTYS_ETH_SPEED_100GBASE_KR4          BIT(22)
+#define MLXSW_REG_PTYS_ETH_SPEED_100GBASE_LR4_ER4      BIT(23)
 #define MLXSW_REG_PTYS_ETH_SPEED_25GBASE_CR            BIT(27)
 #define MLXSW_REG_PTYS_ETH_SPEED_25GBASE_KR            BIT(28)
 #define MLXSW_REG_PTYS_ETH_SPEED_25GBASE_SR            BIT(29)
index bd7f873..0bd6416 100644 (file)
@@ -1169,6 +1169,11 @@ static const struct mlxsw_sp1_port_link_mode mlxsw_sp1_port_link_mode[] = {
                .mask_ethtool   = ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
                .speed          = SPEED_100000,
        },
+       {
+               .mask           = MLXSW_REG_PTYS_ETH_SPEED_100GBASE_LR4_ER4,
+               .mask_ethtool   = ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
+               .speed          = SPEED_100000,
+       },
 };
 
 #define MLXSW_SP1_PORT_LINK_MODE_LEN ARRAY_SIZE(mlxsw_sp1_port_link_mode)
index 9ce9084..eda99d8 100644 (file)
@@ -5951,6 +5951,10 @@ mlxsw_sp_router_fib4_replace(struct mlxsw_sp *mlxsw_sp,
        if (mlxsw_sp->router->aborted)
                return 0;
 
+       if (fen_info->fi->nh &&
+           !mlxsw_sp_nexthop_obj_group_lookup(mlxsw_sp, fen_info->fi->nh->id))
+               return 0;
+
        fib_node = mlxsw_sp_fib_node_get(mlxsw_sp, fen_info->tb_id,
                                         &fen_info->dst, sizeof(fen_info->dst),
                                         fen_info->dst_len,
@@ -6601,6 +6605,9 @@ static int mlxsw_sp_router_fib6_replace(struct mlxsw_sp *mlxsw_sp,
        if (mlxsw_sp_fib6_rt_should_ignore(rt))
                return 0;
 
+       if (rt->nh && !mlxsw_sp_nexthop_obj_group_lookup(mlxsw_sp, rt->nh->id))
+               return 0;
+
        fib_node = mlxsw_sp_fib_node_get(mlxsw_sp, rt->fib6_table->tb6_id,
                                         &rt->fib6_dst.addr,
                                         sizeof(rt->fib6_dst.addr),
index 40e2e79..131b2a5 100644 (file)
@@ -613,7 +613,8 @@ static const struct mlxsw_sx_port_link_mode mlxsw_sx_port_link_mode[] = {
        {
                .mask           = MLXSW_REG_PTYS_ETH_SPEED_100GBASE_CR4 |
                                  MLXSW_REG_PTYS_ETH_SPEED_100GBASE_SR4 |
-                                 MLXSW_REG_PTYS_ETH_SPEED_100GBASE_KR4,
+                                 MLXSW_REG_PTYS_ETH_SPEED_100GBASE_KR4 |
+                                 MLXSW_REG_PTYS_ETH_SPEED_100GBASE_LR4_ER4,
                .speed          = 100000,
        },
 };
index dbdfabf..1c3e204 100644 (file)
@@ -2040,7 +2040,7 @@ lan743x_rx_trim_skb(struct sk_buff *skb, int frame_length)
                dev_kfree_skb_irq(skb);
                return NULL;
        }
-       frame_length = max_t(int, 0, frame_length - RX_HEAD_PADDING - 2);
+       frame_length = max_t(int, 0, frame_length - RX_HEAD_PADDING - 4);
        if (skb->len > frame_length) {
                skb->tail -= skb->len - frame_length;
                skb->len = frame_length;
index c0ede0c..05cb040 100644 (file)
@@ -13,6 +13,7 @@ if NET_VENDOR_MICROSEMI
 
 # Users should depend on NET_SWITCHDEV, HAS_IOMEM
 config MSCC_OCELOT_SWITCH_LIB
+       select NET_DEVLINK
        select REGMAP_MMIO
        select PACKING
        select PHYLIB
index c3ac026..a41b458 100644 (file)
@@ -540,13 +540,14 @@ ocelot_flower_parse_key(struct ocelot *ocelot, int port, bool ingress,
                        return -EOPNOTSUPP;
                }
 
+               flow_rule_match_ipv4_addrs(rule, &match);
+
                if (filter->block_id == VCAP_IS1 && *(u32 *)&match.mask->dst) {
                        NL_SET_ERR_MSG_MOD(extack,
                                           "Key type S1_NORMAL cannot match on destination IP");
                        return -EOPNOTSUPP;
                }
 
-               flow_rule_match_ipv4_addrs(rule, &match);
                tmp = &filter->key.ipv4.sip.value.addr[0];
                memcpy(tmp, &match.key->src, 4);
 
index f704da3..7aad0ba 100644 (file)
@@ -767,7 +767,7 @@ static void r8168fp_adjust_ocp_cmd(struct rtl8169_private *tp, u32 *cmd, int typ
        if (type == ERIAR_OOB &&
            (tp->mac_version == RTL_GIGA_MAC_VER_52 ||
             tp->mac_version == RTL_GIGA_MAC_VER_53))
-               *cmd |= 0x7f0 << 18;
+               *cmd |= 0xf70 << 18;
 }
 
 DECLARE_RTL_COND(rtl_eriar_cond)
index 590b088..f029c7c 100644 (file)
@@ -560,6 +560,8 @@ static struct sh_eth_cpu_data r7s72100_data = {
                          EESR_TDE,
        .fdr_value      = 0x0000070f,
 
+       .trscer_err_mask = DESC_I_RINT8 | DESC_I_RINT5,
+
        .no_psr         = 1,
        .apr            = 1,
        .mpr            = 1,
@@ -780,6 +782,8 @@ static struct sh_eth_cpu_data r7s9210_data = {
 
        .fdr_value      = 0x0000070f,
 
+       .trscer_err_mask = DESC_I_RINT8 | DESC_I_RINT5,
+
        .apr            = 1,
        .mpr            = 1,
        .tpauser        = 1,
@@ -1089,6 +1093,9 @@ static struct sh_eth_cpu_data sh771x_data = {
                          EESIPR_CEEFIP | EESIPR_CELFIP |
                          EESIPR_RRFIP | EESIPR_RTLFIP | EESIPR_RTSFIP |
                          EESIPR_PREIP | EESIPR_CERFIP,
+
+       .trscer_err_mask = DESC_I_RINT8,
+
        .tsu            = 1,
        .dual_port      = 1,
 };
index 751dfde..0b64f77 100644 (file)
@@ -233,6 +233,7 @@ static void common_default_data(struct plat_stmmacenet_data *plat)
 static int intel_mgbe_common_data(struct pci_dev *pdev,
                                  struct plat_stmmacenet_data *plat)
 {
+       char clk_name[20];
        int ret;
        int i;
 
@@ -301,8 +302,10 @@ static int intel_mgbe_common_data(struct pci_dev *pdev,
        plat->eee_usecs_rate = plat->clk_ptp_rate;
 
        /* Set system clock */
+       sprintf(clk_name, "%s-%s", "stmmac", pci_name(pdev));
+
        plat->stmmac_clk = clk_register_fixed_rate(&pdev->dev,
-                                                  "stmmac-clk", NULL, 0,
+                                                  clk_name, NULL, 0,
                                                   plat->clk_ptp_rate);
 
        if (IS_ERR(plat->stmmac_clk)) {
@@ -446,8 +449,8 @@ static int tgl_common_data(struct pci_dev *pdev,
        return intel_mgbe_common_data(pdev, plat);
 }
 
-static int tgl_sgmii_data(struct pci_dev *pdev,
-                         struct plat_stmmacenet_data *plat)
+static int tgl_sgmii_phy0_data(struct pci_dev *pdev,
+                              struct plat_stmmacenet_data *plat)
 {
        plat->bus_id = 1;
        plat->phy_interface = PHY_INTERFACE_MODE_SGMII;
@@ -456,12 +459,26 @@ static int tgl_sgmii_data(struct pci_dev *pdev,
        return tgl_common_data(pdev, plat);
 }
 
-static struct stmmac_pci_info tgl_sgmii1g_info = {
-       .setup = tgl_sgmii_data,
+static struct stmmac_pci_info tgl_sgmii1g_phy0_info = {
+       .setup = tgl_sgmii_phy0_data,
 };
 
-static int adls_sgmii_data(struct pci_dev *pdev,
-                          struct plat_stmmacenet_data *plat)
+static int tgl_sgmii_phy1_data(struct pci_dev *pdev,
+                              struct plat_stmmacenet_data *plat)
+{
+       plat->bus_id = 2;
+       plat->phy_interface = PHY_INTERFACE_MODE_SGMII;
+       plat->serdes_powerup = intel_serdes_powerup;
+       plat->serdes_powerdown = intel_serdes_powerdown;
+       return tgl_common_data(pdev, plat);
+}
+
+static struct stmmac_pci_info tgl_sgmii1g_phy1_info = {
+       .setup = tgl_sgmii_phy1_data,
+};
+
+static int adls_sgmii_phy0_data(struct pci_dev *pdev,
+                               struct plat_stmmacenet_data *plat)
 {
        plat->bus_id = 1;
        plat->phy_interface = PHY_INTERFACE_MODE_SGMII;
@@ -471,10 +488,24 @@ static int adls_sgmii_data(struct pci_dev *pdev,
        return tgl_common_data(pdev, plat);
 }
 
-static struct stmmac_pci_info adls_sgmii1g_info = {
-       .setup = adls_sgmii_data,
+static struct stmmac_pci_info adls_sgmii1g_phy0_info = {
+       .setup = adls_sgmii_phy0_data,
 };
 
+static int adls_sgmii_phy1_data(struct pci_dev *pdev,
+                               struct plat_stmmacenet_data *plat)
+{
+       plat->bus_id = 2;
+       plat->phy_interface = PHY_INTERFACE_MODE_SGMII;
+
+       /* SerDes power up and power down are done in BIOS for ADL */
+
+       return tgl_common_data(pdev, plat);
+}
+
+static struct stmmac_pci_info adls_sgmii1g_phy1_info = {
+       .setup = adls_sgmii_phy1_data,
+};
 static const struct stmmac_pci_func_data galileo_stmmac_func_data[] = {
        {
                .func = 6,
@@ -756,11 +787,11 @@ static const struct pci_device_id intel_eth_pci_id_table[] = {
        { PCI_DEVICE_DATA(INTEL, EHL_PSE1_RGMII1G_ID, &ehl_pse1_rgmii1g_info) },
        { PCI_DEVICE_DATA(INTEL, EHL_PSE1_SGMII1G_ID, &ehl_pse1_sgmii1g_info) },
        { PCI_DEVICE_DATA(INTEL, EHL_PSE1_SGMII2G5_ID, &ehl_pse1_sgmii1g_info) },
-       { PCI_DEVICE_DATA(INTEL, TGL_SGMII1G_ID, &tgl_sgmii1g_info) },
-       { PCI_DEVICE_DATA(INTEL, TGLH_SGMII1G_0_ID, &tgl_sgmii1g_info) },
-       { PCI_DEVICE_DATA(INTEL, TGLH_SGMII1G_1_ID, &tgl_sgmii1g_info) },
-       { PCI_DEVICE_DATA(INTEL, ADLS_SGMII1G_0_ID, &adls_sgmii1g_info) },
-       { PCI_DEVICE_DATA(INTEL, ADLS_SGMII1G_1_ID, &adls_sgmii1g_info) },
+       { PCI_DEVICE_DATA(INTEL, TGL_SGMII1G_ID, &tgl_sgmii1g_phy0_info) },
+       { PCI_DEVICE_DATA(INTEL, TGLH_SGMII1G_0_ID, &tgl_sgmii1g_phy0_info) },
+       { PCI_DEVICE_DATA(INTEL, TGLH_SGMII1G_1_ID, &tgl_sgmii1g_phy1_info) },
+       { PCI_DEVICE_DATA(INTEL, ADLS_SGMII1G_0_ID, &adls_sgmii1g_phy0_info) },
+       { PCI_DEVICE_DATA(INTEL, ADLS_SGMII1G_1_ID, &adls_sgmii1g_phy1_info) },
        {}
 };
 MODULE_DEVICE_TABLE(pci, intel_eth_pci_id_table);
index c6540b0..cbf4429 100644 (file)
@@ -402,19 +402,53 @@ static void dwmac4_rd_set_tx_ic(struct dma_desc *p)
        p->des2 |= cpu_to_le32(TDES2_INTERRUPT_ON_COMPLETION);
 }
 
-static void dwmac4_display_ring(void *head, unsigned int size, bool rx)
+static void dwmac4_display_ring(void *head, unsigned int size, bool rx,
+                               dma_addr_t dma_rx_phy, unsigned int desc_size)
 {
-       struct dma_desc *p = (struct dma_desc *)head;
+       dma_addr_t dma_addr;
        int i;
 
        pr_info("%s descriptor ring:\n", rx ? "RX" : "TX");
 
-       for (i = 0; i < size; i++) {
-               pr_info("%03d [0x%x]: 0x%x 0x%x 0x%x 0x%x\n",
-                       i, (unsigned int)virt_to_phys(p),
-                       le32_to_cpu(p->des0), le32_to_cpu(p->des1),
-                       le32_to_cpu(p->des2), le32_to_cpu(p->des3));
-               p++;
+       if (desc_size == sizeof(struct dma_desc)) {
+               struct dma_desc *p = (struct dma_desc *)head;
+
+               for (i = 0; i < size; i++) {
+                       dma_addr = dma_rx_phy + i * sizeof(*p);
+                       pr_info("%03d [%pad]: 0x%x 0x%x 0x%x 0x%x\n",
+                               i, &dma_addr,
+                               le32_to_cpu(p->des0), le32_to_cpu(p->des1),
+                               le32_to_cpu(p->des2), le32_to_cpu(p->des3));
+                       p++;
+               }
+       } else if (desc_size == sizeof(struct dma_extended_desc)) {
+               struct dma_extended_desc *extp = (struct dma_extended_desc *)head;
+
+               for (i = 0; i < size; i++) {
+                       dma_addr = dma_rx_phy + i * sizeof(*extp);
+                       pr_info("%03d [%pad]: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+                               i, &dma_addr,
+                               le32_to_cpu(extp->basic.des0), le32_to_cpu(extp->basic.des1),
+                               le32_to_cpu(extp->basic.des2), le32_to_cpu(extp->basic.des3),
+                               le32_to_cpu(extp->des4), le32_to_cpu(extp->des5),
+                               le32_to_cpu(extp->des6), le32_to_cpu(extp->des7));
+                       extp++;
+               }
+       } else if (desc_size == sizeof(struct dma_edesc)) {
+               struct dma_edesc *ep = (struct dma_edesc *)head;
+
+               for (i = 0; i < size; i++) {
+                       dma_addr = dma_rx_phy + i * sizeof(*ep);
+                       pr_info("%03d [%pad]: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+                               i, &dma_addr,
+                               le32_to_cpu(ep->des4), le32_to_cpu(ep->des5),
+                               le32_to_cpu(ep->des6), le32_to_cpu(ep->des7),
+                               le32_to_cpu(ep->basic.des0), le32_to_cpu(ep->basic.des1),
+                               le32_to_cpu(ep->basic.des2), le32_to_cpu(ep->basic.des3));
+                       ep++;
+               }
+       } else {
+               pr_err("unsupported descriptor!");
        }
 }
 
@@ -499,10 +533,15 @@ static void dwmac4_get_rx_header_len(struct dma_desc *p, unsigned int *len)
        *len = le32_to_cpu(p->des2) & RDES2_HL;
 }
 
-static void dwmac4_set_sec_addr(struct dma_desc *p, dma_addr_t addr)
+static void dwmac4_set_sec_addr(struct dma_desc *p, dma_addr_t addr, bool buf2_valid)
 {
        p->des2 = cpu_to_le32(lower_32_bits(addr));
-       p->des3 = cpu_to_le32(upper_32_bits(addr) | RDES3_BUFFER2_VALID_ADDR);
+       p->des3 = cpu_to_le32(upper_32_bits(addr));
+
+       if (buf2_valid)
+               p->des3 |= cpu_to_le32(RDES3_BUFFER2_VALID_ADDR);
+       else
+               p->des3 &= cpu_to_le32(~RDES3_BUFFER2_VALID_ADDR);
 }
 
 static void dwmac4_set_tbs(struct dma_edesc *p, u32 sec, u32 nsec)
index bb29bfc..62aa0e9 100644 (file)
@@ -124,6 +124,23 @@ static void dwmac4_dma_init_channel(void __iomem *ioaddr,
               ioaddr + DMA_CHAN_INTR_ENA(chan));
 }
 
+static void dwmac410_dma_init_channel(void __iomem *ioaddr,
+                                     struct stmmac_dma_cfg *dma_cfg, u32 chan)
+{
+       u32 value;
+
+       /* common channel control register config */
+       value = readl(ioaddr + DMA_CHAN_CONTROL(chan));
+       if (dma_cfg->pblx8)
+               value = value | DMA_BUS_MODE_PBL;
+
+       writel(value, ioaddr + DMA_CHAN_CONTROL(chan));
+
+       /* Mask interrupts by writing to CSR7 */
+       writel(DMA_CHAN_INTR_DEFAULT_MASK_4_10,
+              ioaddr + DMA_CHAN_INTR_ENA(chan));
+}
+
 static void dwmac4_dma_init(void __iomem *ioaddr,
                            struct stmmac_dma_cfg *dma_cfg, int atds)
 {
@@ -523,7 +540,7 @@ const struct stmmac_dma_ops dwmac4_dma_ops = {
 const struct stmmac_dma_ops dwmac410_dma_ops = {
        .reset = dwmac4_dma_reset,
        .init = dwmac4_dma_init,
-       .init_chan = dwmac4_dma_init_channel,
+       .init_chan = dwmac410_dma_init_channel,
        .init_rx_chan = dwmac4_dma_init_rx_chan,
        .init_tx_chan = dwmac4_dma_init_tx_chan,
        .axi = dwmac4_dma_axi,
index 0b4ee2d..71e5075 100644 (file)
@@ -53,10 +53,6 @@ void dwmac4_dma_stop_tx(void __iomem *ioaddr, u32 chan)
 
        value &= ~DMA_CONTROL_ST;
        writel(value, ioaddr + DMA_CHAN_TX_CONTROL(chan));
-
-       value = readl(ioaddr + GMAC_CONFIG);
-       value &= ~GMAC_CONFIG_TE;
-       writel(value, ioaddr + GMAC_CONFIG);
 }
 
 void dwmac4_dma_start_rx(void __iomem *ioaddr, u32 chan)
index 0aaf19a..ccfb010 100644 (file)
@@ -292,7 +292,7 @@ static void dwxgmac2_get_rx_header_len(struct dma_desc *p, unsigned int *len)
                *len = le32_to_cpu(p->des2) & XGMAC_RDES2_HL;
 }
 
-static void dwxgmac2_set_sec_addr(struct dma_desc *p, dma_addr_t addr)
+static void dwxgmac2_set_sec_addr(struct dma_desc *p, dma_addr_t addr, bool is_valid)
 {
        p->des2 = cpu_to_le32(lower_32_bits(addr));
        p->des3 = cpu_to_le32(upper_32_bits(addr));
index d02cec2..6650edf 100644 (file)
@@ -417,19 +417,22 @@ static int enh_desc_get_rx_timestamp_status(void *desc, void *next_desc,
        }
 }
 
-static void enh_desc_display_ring(void *head, unsigned int size, bool rx)
+static void enh_desc_display_ring(void *head, unsigned int size, bool rx,
+                                 dma_addr_t dma_rx_phy, unsigned int desc_size)
 {
        struct dma_extended_desc *ep = (struct dma_extended_desc *)head;
+       dma_addr_t dma_addr;
        int i;
 
        pr_info("Extended %s descriptor ring:\n", rx ? "RX" : "TX");
 
        for (i = 0; i < size; i++) {
                u64 x;
+               dma_addr = dma_rx_phy + i * sizeof(*ep);
 
                x = *(u64 *)ep;
-               pr_info("%03d [0x%x]: 0x%x 0x%x 0x%x 0x%x\n",
-                       i, (unsigned int)virt_to_phys(ep),
+               pr_info("%03d [%pad]: 0x%x 0x%x 0x%x 0x%x\n",
+                       i, &dma_addr,
                        (unsigned int)x, (unsigned int)(x >> 32),
                        ep->basic.des2, ep->basic.des3);
                ep++;
index b40b2e0..979ac9f 100644 (file)
@@ -78,7 +78,8 @@ struct stmmac_desc_ops {
        /* get rx timestamp status */
        int (*get_rx_timestamp_status)(void *desc, void *next_desc, u32 ats);
        /* Display ring */
-       void (*display_ring)(void *head, unsigned int size, bool rx);
+       void (*display_ring)(void *head, unsigned int size, bool rx,
+                            dma_addr_t dma_rx_phy, unsigned int desc_size);
        /* set MSS via context descriptor */
        void (*set_mss)(struct dma_desc *p, unsigned int mss);
        /* get descriptor skbuff address */
@@ -91,7 +92,7 @@ struct stmmac_desc_ops {
        int (*get_rx_hash)(struct dma_desc *p, u32 *hash,
                           enum pkt_hash_types *type);
        void (*get_rx_header_len)(struct dma_desc *p, unsigned int *len);
-       void (*set_sec_addr)(struct dma_desc *p, dma_addr_t addr);
+       void (*set_sec_addr)(struct dma_desc *p, dma_addr_t addr, bool buf2_valid);
        void (*set_sarc)(struct dma_desc *p, u32 sarc_type);
        void (*set_vlan_tag)(struct dma_desc *p, u16 tag, u16 inner_tag,
                             u32 inner_type);
index f083360..98ef43f 100644 (file)
@@ -269,19 +269,22 @@ static int ndesc_get_rx_timestamp_status(void *desc, void *next_desc, u32 ats)
                return 1;
 }
 
-static void ndesc_display_ring(void *head, unsigned int size, bool rx)
+static void ndesc_display_ring(void *head, unsigned int size, bool rx,
+                              dma_addr_t dma_rx_phy, unsigned int desc_size)
 {
        struct dma_desc *p = (struct dma_desc *)head;
+       dma_addr_t dma_addr;
        int i;
 
        pr_info("%s descriptor ring:\n", rx ? "RX" : "TX");
 
        for (i = 0; i < size; i++) {
                u64 x;
+               dma_addr = dma_rx_phy + i * sizeof(*p);
 
                x = *(u64 *)p;
-               pr_info("%03d [0x%x]: 0x%x 0x%x 0x%x 0x%x",
-                       i, (unsigned int)virt_to_phys(p),
+               pr_info("%03d [%pad]: 0x%x 0x%x 0x%x 0x%x",
+                       i, &dma_addr,
                        (unsigned int)x, (unsigned int)(x >> 32),
                        p->des2, p->des3);
                p++;
index 26b971c..208cae3 100644 (file)
@@ -1133,6 +1133,7 @@ static int stmmac_phy_setup(struct stmmac_priv *priv)
 static void stmmac_display_rx_rings(struct stmmac_priv *priv)
 {
        u32 rx_cnt = priv->plat->rx_queues_to_use;
+       unsigned int desc_size;
        void *head_rx;
        u32 queue;
 
@@ -1142,19 +1143,24 @@ static void stmmac_display_rx_rings(struct stmmac_priv *priv)
 
                pr_info("\tRX Queue %u rings\n", queue);
 
-               if (priv->extend_desc)
+               if (priv->extend_desc) {
                        head_rx = (void *)rx_q->dma_erx;
-               else
+                       desc_size = sizeof(struct dma_extended_desc);
+               } else {
                        head_rx = (void *)rx_q->dma_rx;
+                       desc_size = sizeof(struct dma_desc);
+               }
 
                /* Display RX ring */
-               stmmac_display_ring(priv, head_rx, priv->dma_rx_size, true);
+               stmmac_display_ring(priv, head_rx, priv->dma_rx_size, true,
+                                   rx_q->dma_rx_phy, desc_size);
        }
 }
 
 static void stmmac_display_tx_rings(struct stmmac_priv *priv)
 {
        u32 tx_cnt = priv->plat->tx_queues_to_use;
+       unsigned int desc_size;
        void *head_tx;
        u32 queue;
 
@@ -1164,14 +1170,19 @@ static void stmmac_display_tx_rings(struct stmmac_priv *priv)
 
                pr_info("\tTX Queue %d rings\n", queue);
 
-               if (priv->extend_desc)
+               if (priv->extend_desc) {
                        head_tx = (void *)tx_q->dma_etx;
-               else if (tx_q->tbs & STMMAC_TBS_AVAIL)
+                       desc_size = sizeof(struct dma_extended_desc);
+               } else if (tx_q->tbs & STMMAC_TBS_AVAIL) {
                        head_tx = (void *)tx_q->dma_entx;
-               else
+                       desc_size = sizeof(struct dma_edesc);
+               } else {
                        head_tx = (void *)tx_q->dma_tx;
+                       desc_size = sizeof(struct dma_desc);
+               }
 
-               stmmac_display_ring(priv, head_tx, priv->dma_tx_size, false);
+               stmmac_display_ring(priv, head_tx, priv->dma_tx_size, false,
+                                   tx_q->dma_tx_phy, desc_size);
        }
 }
 
@@ -1303,9 +1314,10 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p,
                        return -ENOMEM;
 
                buf->sec_addr = page_pool_get_dma_addr(buf->sec_page);
-               stmmac_set_desc_sec_addr(priv, p, buf->sec_addr);
+               stmmac_set_desc_sec_addr(priv, p, buf->sec_addr, true);
        } else {
                buf->sec_page = NULL;
+               stmmac_set_desc_sec_addr(priv, p, buf->sec_addr, false);
        }
 
        buf->addr = page_pool_get_dma_addr(buf->page);
@@ -1367,6 +1379,88 @@ static void stmmac_free_tx_buffer(struct stmmac_priv *priv, u32 queue, int i)
        }
 }
 
+/**
+ * stmmac_reinit_rx_buffers - reinit the RX descriptor buffer.
+ * @priv: driver private structure
+ * Description: this function is called to re-allocate a receive buffer, perform
+ * the DMA mapping and init the descriptor.
+ */
+static void stmmac_reinit_rx_buffers(struct stmmac_priv *priv)
+{
+       u32 rx_count = priv->plat->rx_queues_to_use;
+       u32 queue;
+       int i;
+
+       for (queue = 0; queue < rx_count; queue++) {
+               struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];
+
+               for (i = 0; i < priv->dma_rx_size; i++) {
+                       struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i];
+
+                       if (buf->page) {
+                               page_pool_recycle_direct(rx_q->page_pool, buf->page);
+                               buf->page = NULL;
+                       }
+
+                       if (priv->sph && buf->sec_page) {
+                               page_pool_recycle_direct(rx_q->page_pool, buf->sec_page);
+                               buf->sec_page = NULL;
+                       }
+               }
+       }
+
+       for (queue = 0; queue < rx_count; queue++) {
+               struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];
+
+               for (i = 0; i < priv->dma_rx_size; i++) {
+                       struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i];
+                       struct dma_desc *p;
+
+                       if (priv->extend_desc)
+                               p = &((rx_q->dma_erx + i)->basic);
+                       else
+                               p = rx_q->dma_rx + i;
+
+                       if (!buf->page) {
+                               buf->page = page_pool_dev_alloc_pages(rx_q->page_pool);
+                               if (!buf->page)
+                                       goto err_reinit_rx_buffers;
+
+                               buf->addr = page_pool_get_dma_addr(buf->page);
+                       }
+
+                       if (priv->sph && !buf->sec_page) {
+                               buf->sec_page = page_pool_dev_alloc_pages(rx_q->page_pool);
+                               if (!buf->sec_page)
+                                       goto err_reinit_rx_buffers;
+
+                               buf->sec_addr = page_pool_get_dma_addr(buf->sec_page);
+                       }
+
+                       stmmac_set_desc_addr(priv, p, buf->addr);
+                       if (priv->sph)
+                               stmmac_set_desc_sec_addr(priv, p, buf->sec_addr, true);
+                       else
+                               stmmac_set_desc_sec_addr(priv, p, buf->sec_addr, false);
+                       if (priv->dma_buf_sz == BUF_SIZE_16KiB)
+                               stmmac_init_desc3(priv, p);
+               }
+       }
+
+       return;
+
+err_reinit_rx_buffers:
+       do {
+               while (--i >= 0)
+                       stmmac_free_rx_buffer(priv, queue, i);
+
+               if (queue == 0)
+                       break;
+
+               i = priv->dma_rx_size;
+       } while (queue-- > 0);
+}
+
 /**
  * init_dma_rx_desc_rings - init the RX descriptor rings
  * @dev: net device structure
@@ -3648,7 +3742,10 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue)
                                           DMA_FROM_DEVICE);
 
                stmmac_set_desc_addr(priv, p, buf->addr);
-               stmmac_set_desc_sec_addr(priv, p, buf->sec_addr);
+               if (priv->sph)
+                       stmmac_set_desc_sec_addr(priv, p, buf->sec_addr, true);
+               else
+                       stmmac_set_desc_sec_addr(priv, p, buf->sec_addr, false);
                stmmac_refill_desc3(priv, rx_q, p);
 
                rx_q->rx_count_frames++;
@@ -3736,18 +3833,23 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
        unsigned int count = 0, error = 0, len = 0;
        int status = 0, coe = priv->hw->rx_csum;
        unsigned int next_entry = rx_q->cur_rx;
+       unsigned int desc_size;
        struct sk_buff *skb = NULL;
 
        if (netif_msg_rx_status(priv)) {
                void *rx_head;
 
                netdev_dbg(priv->dev, "%s: descriptor ring:\n", __func__);
-               if (priv->extend_desc)
+               if (priv->extend_desc) {
                        rx_head = (void *)rx_q->dma_erx;
-               else
+                       desc_size = sizeof(struct dma_extended_desc);
+               } else {
                        rx_head = (void *)rx_q->dma_rx;
+                       desc_size = sizeof(struct dma_desc);
+               }
 
-               stmmac_display_ring(priv, rx_head, priv->dma_rx_size, true);
+               stmmac_display_ring(priv, rx_head, priv->dma_rx_size, true,
+                                   rx_q->dma_rx_phy, desc_size);
        }
        while (count < limit) {
                unsigned int buf1_len = 0, buf2_len = 0;
@@ -4315,24 +4417,27 @@ static int stmmac_set_mac_address(struct net_device *ndev, void *addr)
 static struct dentry *stmmac_fs_dir;
 
 static void sysfs_display_ring(void *head, int size, int extend_desc,
-                              struct seq_file *seq)
+                              struct seq_file *seq, dma_addr_t dma_phy_addr)
 {
        int i;
        struct dma_extended_desc *ep = (struct dma_extended_desc *)head;
        struct dma_desc *p = (struct dma_desc *)head;
+       dma_addr_t dma_addr;
 
        for (i = 0; i < size; i++) {
                if (extend_desc) {
-                       seq_printf(seq, "%d [0x%x]: 0x%x 0x%x 0x%x 0x%x\n",
-                                  i, (unsigned int)virt_to_phys(ep),
+                       dma_addr = dma_phy_addr + i * sizeof(*ep);
+                       seq_printf(seq, "%d [%pad]: 0x%x 0x%x 0x%x 0x%x\n",
+                                  i, &dma_addr,
                                   le32_to_cpu(ep->basic.des0),
                                   le32_to_cpu(ep->basic.des1),
                                   le32_to_cpu(ep->basic.des2),
                                   le32_to_cpu(ep->basic.des3));
                        ep++;
                } else {
-                       seq_printf(seq, "%d [0x%x]: 0x%x 0x%x 0x%x 0x%x\n",
-                                  i, (unsigned int)virt_to_phys(p),
+                       dma_addr = dma_phy_addr + i * sizeof(*p);
+                       seq_printf(seq, "%d [%pad]: 0x%x 0x%x 0x%x 0x%x\n",
+                                  i, &dma_addr,
                                   le32_to_cpu(p->des0), le32_to_cpu(p->des1),
                                   le32_to_cpu(p->des2), le32_to_cpu(p->des3));
                        p++;
@@ -4360,11 +4465,11 @@ static int stmmac_rings_status_show(struct seq_file *seq, void *v)
                if (priv->extend_desc) {
                        seq_printf(seq, "Extended descriptor ring:\n");
                        sysfs_display_ring((void *)rx_q->dma_erx,
-                                          priv->dma_rx_size, 1, seq);
+                                          priv->dma_rx_size, 1, seq, rx_q->dma_rx_phy);
                } else {
                        seq_printf(seq, "Descriptor ring:\n");
                        sysfs_display_ring((void *)rx_q->dma_rx,
-                                          priv->dma_rx_size, 0, seq);
+                                          priv->dma_rx_size, 0, seq, rx_q->dma_rx_phy);
                }
        }
 
@@ -4376,11 +4481,11 @@ static int stmmac_rings_status_show(struct seq_file *seq, void *v)
                if (priv->extend_desc) {
                        seq_printf(seq, "Extended descriptor ring:\n");
                        sysfs_display_ring((void *)tx_q->dma_etx,
-                                          priv->dma_tx_size, 1, seq);
+                                          priv->dma_tx_size, 1, seq, tx_q->dma_tx_phy);
                } else if (!(tx_q->tbs & STMMAC_TBS_AVAIL)) {
                        seq_printf(seq, "Descriptor ring:\n");
                        sysfs_display_ring((void *)tx_q->dma_tx,
-                                          priv->dma_tx_size, 0, seq);
+                                          priv->dma_tx_size, 0, seq, tx_q->dma_tx_phy);
                }
        }
 
@@ -5144,13 +5249,16 @@ int stmmac_dvr_remove(struct device *dev)
        netdev_info(priv->dev, "%s: removing driver", __func__);
 
        stmmac_stop_all_dma(priv);
+       stmmac_mac_set(priv, priv->ioaddr, false);
+       netif_carrier_off(ndev);
+       unregister_netdev(ndev);
 
+       /* Serdes power down needs to happen after VLAN filter
+        * is deleted that is triggered by unregister_netdev().
+        */
        if (priv->plat->serdes_powerdown)
                priv->plat->serdes_powerdown(ndev, priv->plat->bsp_priv);
 
-       stmmac_mac_set(priv, priv->ioaddr, false);
-       netif_carrier_off(ndev);
-       unregister_netdev(ndev);
 #ifdef CONFIG_DEBUG_FS
        stmmac_exit_fs(ndev);
 #endif
@@ -5257,6 +5365,8 @@ static void stmmac_reset_queues_param(struct stmmac_priv *priv)
                tx_q->cur_tx = 0;
                tx_q->dirty_tx = 0;
                tx_q->mss = 0;
+
+               netdev_tx_reset_queue(netdev_get_tx_queue(priv->dev, queue));
        }
 }
 
@@ -5318,7 +5428,7 @@ int stmmac_resume(struct device *dev)
        mutex_lock(&priv->lock);
 
        stmmac_reset_queues_param(priv);
-
+       stmmac_reinit_rx_buffers(priv);
        stmmac_free_tx_skbufs(priv);
        stmmac_clear_descriptors(priv);
 
index 68695d4..707ccdd 100644 (file)
@@ -3931,8 +3931,6 @@ static void niu_xmac_interrupt(struct niu *np)
                mp->rx_mcasts += RXMAC_MC_FRM_CNT_COUNT;
        if (val & XRXMAC_STATUS_RXBCAST_CNT_EXP)
                mp->rx_bcasts += RXMAC_BC_FRM_CNT_COUNT;
-       if (val & XRXMAC_STATUS_RXBCAST_CNT_EXP)
-               mp->rx_bcasts += RXMAC_BC_FRM_CNT_COUNT;
        if (val & XRXMAC_STATUS_RXHIST1_CNT_EXP)
                mp->rx_hist_cnt1 += RXMAC_HIST_CNT1_COUNT;
        if (val & XRXMAC_STATUS_RXHIST2_CNT_EXP)
index b8f4f41..d054c6e 100644 (file)
@@ -2044,6 +2044,7 @@ bdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                /*bdx_hw_reset(priv); */
                if (bdx_read_mac(priv)) {
                        pr_err("load MAC address failed\n");
+                       err = -EFAULT;
                        goto err_out_iomap;
                }
                SET_NETDEV_DEV(ndev, &pdev->dev);
index 71d6629..9f5b561 100644 (file)
@@ -171,11 +171,6 @@ static void sp_encaps(struct sixpack *sp, unsigned char *icp, int len)
                goto out_drop;
        }
 
-       if (len > sp->mtu) {    /* sp->mtu = AX25_MTU = max. PACLEN = 256 */
-               msg = "oversized transmit packet!";
-               goto out_drop;
-       }
-
        if (p[0] > 5) {
                msg = "invalid KISS command";
                goto out_drop;
index 36eeb80..4690c6a 100644 (file)
@@ -2167,7 +2167,6 @@ static void __exit scc_cleanup_driver(void)
 
 MODULE_AUTHOR("Joerg Reuter <jreuter@yaina.de>");
 MODULE_DESCRIPTION("AX.25 Device Driver for Z8530 based HDLC cards");
-MODULE_SUPPORTED_DEVICE("Z8530 based SCC cards for Amateur Radio");
 MODULE_LICENSE("GPL");
 module_init(scc_init_driver);
 module_exit(scc_cleanup_driver);
index e1a497d..59ac04a 100644 (file)
@@ -229,7 +229,7 @@ int netvsc_send(struct net_device *net,
                bool xdp_tx);
 void netvsc_linkstatus_callback(struct net_device *net,
                                struct rndis_message *resp,
-                               void *data);
+                               void *data, u32 data_buflen);
 int netvsc_recv_callback(struct net_device *net,
                         struct netvsc_device *nvdev,
                         struct netvsc_channel *nvchan);
index 8176fa0..15f262b 100644 (file)
@@ -744,7 +744,7 @@ static netdev_tx_t netvsc_start_xmit(struct sk_buff *skb,
  */
 void netvsc_linkstatus_callback(struct net_device *net,
                                struct rndis_message *resp,
-                               void *data)
+                               void *data, u32 data_buflen)
 {
        struct rndis_indicate_status *indicate = &resp->msg.indicate_status;
        struct net_device_context *ndev_ctx = netdev_priv(net);
@@ -765,11 +765,16 @@ void netvsc_linkstatus_callback(struct net_device *net,
        if (indicate->status == RNDIS_STATUS_LINK_SPEED_CHANGE) {
                u32 speed;
 
-               /* Validate status_buf_offset */
+               /* Validate status_buf_offset and status_buflen.
+                *
+                * Certain (pre-Fe) implementations of Hyper-V's vSwitch didn't account
+                * for the status buffer field in resp->msg_len; perform the validation
+                * using data_buflen (>= resp->msg_len).
+                */
                if (indicate->status_buflen < sizeof(speed) ||
                    indicate->status_buf_offset < sizeof(*indicate) ||
-                   resp->msg_len - RNDIS_HEADER_SIZE < indicate->status_buf_offset ||
-                   resp->msg_len - RNDIS_HEADER_SIZE - indicate->status_buf_offset
+                   data_buflen - RNDIS_HEADER_SIZE < indicate->status_buf_offset ||
+                   data_buflen - RNDIS_HEADER_SIZE - indicate->status_buf_offset
                                < indicate->status_buflen) {
                        netdev_err(net, "invalid rndis_indicate_status packet\n");
                        return;
index 123cc9d..c0e89e1 100644 (file)
@@ -620,7 +620,7 @@ int rndis_filter_receive(struct net_device *ndev,
 
        case RNDIS_MSG_INDICATE:
                /* notification msgs */
-               netvsc_linkstatus_callback(ndev, rndis_msg, data);
+               netvsc_linkstatus_callback(ndev, rndis_msg, data, buflen);
                break;
        default:
                netdev_err(ndev,
index aec9244..659d3dc 100644 (file)
@@ -294,6 +294,7 @@ nsim_create(struct nsim_dev *nsim_dev, struct nsim_dev_port *nsim_dev_port)
        dev_net_set(dev, nsim_dev_net(nsim_dev));
        ns = netdev_priv(dev);
        ns->netdev = dev;
+       u64_stats_init(&ns->syncp);
        ns->nsim_dev = nsim_dev;
        ns->nsim_dev_port = nsim_dev_port;
        ns->nsim_bus_dev = nsim_dev->nsim_bus_dev;
index be1224b..f7a2ec1 100644 (file)
@@ -290,6 +290,7 @@ static int dp83822_config_intr(struct phy_device *phydev)
 
 static irqreturn_t dp83822_handle_interrupt(struct phy_device *phydev)
 {
+       bool trigger_machine = false;
        int irq_status;
 
        /* The MISR1 and MISR2 registers are holding the interrupt status in
@@ -305,7 +306,7 @@ static irqreturn_t dp83822_handle_interrupt(struct phy_device *phydev)
                return IRQ_NONE;
        }
        if (irq_status & ((irq_status & GENMASK(7, 0)) << 8))
-               goto trigger_machine;
+               trigger_machine = true;
 
        irq_status = phy_read(phydev, MII_DP83822_MISR2);
        if (irq_status < 0) {
@@ -313,11 +314,11 @@ static irqreturn_t dp83822_handle_interrupt(struct phy_device *phydev)
                return IRQ_NONE;
        }
        if (irq_status & ((irq_status & GENMASK(7, 0)) << 8))
-               goto trigger_machine;
+               trigger_machine = true;
 
-       return IRQ_NONE;
+       if (!trigger_machine)
+               return IRQ_NONE;
 
-trigger_machine:
        phy_trigger_machine(phydev);
 
        return IRQ_HANDLED;
index 688fadf..7ea32fb 100644 (file)
@@ -264,6 +264,7 @@ static int dp83811_config_intr(struct phy_device *phydev)
 
 static irqreturn_t dp83811_handle_interrupt(struct phy_device *phydev)
 {
+       bool trigger_machine = false;
        int irq_status;
 
        /* The INT_STAT registers 1, 2 and 3 are holding the interrupt status
@@ -279,7 +280,7 @@ static irqreturn_t dp83811_handle_interrupt(struct phy_device *phydev)
                return IRQ_NONE;
        }
        if (irq_status & ((irq_status & GENMASK(7, 0)) << 8))
-               goto trigger_machine;
+               trigger_machine = true;
 
        irq_status = phy_read(phydev, MII_DP83811_INT_STAT2);
        if (irq_status < 0) {
@@ -287,7 +288,7 @@ static irqreturn_t dp83811_handle_interrupt(struct phy_device *phydev)
                return IRQ_NONE;
        }
        if (irq_status & ((irq_status & GENMASK(7, 0)) << 8))
-               goto trigger_machine;
+               trigger_machine = true;
 
        irq_status = phy_read(phydev, MII_DP83811_INT_STAT3);
        if (irq_status < 0) {
@@ -295,11 +296,11 @@ static irqreturn_t dp83811_handle_interrupt(struct phy_device *phydev)
                return IRQ_NONE;
        }
        if (irq_status & ((irq_status & GENMASK(7, 0)) << 8))
-               goto trigger_machine;
+               trigger_machine = true;
 
-       return IRQ_NONE;
+       if (!trigger_machine)
+               return IRQ_NONE;
 
-trigger_machine:
        phy_trigger_machine(phydev);
 
        return IRQ_HANDLED;
index 1be07e4..fc2e7cb 100644 (file)
@@ -276,14 +276,16 @@ int phy_ethtool_ksettings_set(struct phy_device *phydev,
 
        phydev->autoneg = autoneg;
 
-       phydev->speed = speed;
+       if (autoneg == AUTONEG_DISABLE) {
+               phydev->speed = speed;
+               phydev->duplex = duplex;
+       }
 
        linkmode_copy(phydev->advertising, advertising);
 
        linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
                         phydev->advertising, autoneg == AUTONEG_ENABLE);
 
-       phydev->duplex = duplex;
        phydev->master_slave_set = cmd->base.master_slave_cfg;
        phydev->mdix_ctrl = cmd->base.eth_tp_mdix_ctrl;
 
index ce49547..cc38e32 100644 (file)
@@ -230,7 +230,6 @@ static struct phy_driver genphy_driver;
 static LIST_HEAD(phy_fixup_list);
 static DEFINE_MUTEX(phy_fixup_lock);
 
-#ifdef CONFIG_PM
 static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
 {
        struct device_driver *drv = phydev->mdio.dev.driver;
@@ -270,7 +269,7 @@ out:
        return !phydev->suspended;
 }
 
-static int mdio_bus_phy_suspend(struct device *dev)
+static __maybe_unused int mdio_bus_phy_suspend(struct device *dev)
 {
        struct phy_device *phydev = to_phy_device(dev);
 
@@ -290,7 +289,7 @@ static int mdio_bus_phy_suspend(struct device *dev)
        return phy_suspend(phydev);
 }
 
-static int mdio_bus_phy_resume(struct device *dev)
+static __maybe_unused int mdio_bus_phy_resume(struct device *dev)
 {
        struct phy_device *phydev = to_phy_device(dev);
        int ret;
@@ -316,7 +315,6 @@ no_resume:
 
 static SIMPLE_DEV_PM_OPS(mdio_bus_phy_pm_ops, mdio_bus_phy_suspend,
                         mdio_bus_phy_resume);
-#endif /* CONFIG_PM */
 
 /**
  * phy_register_fixup - creates a new phy_fixup and adds it to the list
index 4087c9e..8acf301 100644 (file)
@@ -851,17 +851,17 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
 
        /* check if we got everything */
        if (!ctx->data) {
-               dev_dbg(&intf->dev, "CDC Union missing and no IAD found\n");
+               dev_err(&intf->dev, "CDC Union missing and no IAD found\n");
                goto error;
        }
        if (cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting)) {
                if (!ctx->mbim_desc) {
-                       dev_dbg(&intf->dev, "MBIM functional descriptor missing\n");
+                       dev_err(&intf->dev, "MBIM functional descriptor missing\n");
                        goto error;
                }
        } else {
                if (!ctx->ether_desc || !ctx->func_desc) {
-                       dev_dbg(&intf->dev, "NCM or ECM functional descriptors missing\n");
+                       dev_err(&intf->dev, "NCM or ECM functional descriptors missing\n");
                        goto error;
                }
        }
@@ -870,7 +870,7 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
        if (ctx->data != ctx->control) {
                temp = usb_driver_claim_interface(driver, ctx->data, dev);
                if (temp) {
-                       dev_dbg(&intf->dev, "failed to claim data intf\n");
+                       dev_err(&intf->dev, "failed to claim data intf\n");
                        goto error;
                }
        }
@@ -926,7 +926,7 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
        if (ctx->ether_desc) {
                temp = usbnet_get_ethernet_addr(dev, ctx->ether_desc->iMACAddress);
                if (temp) {
-                       dev_dbg(&intf->dev, "failed to get mac address\n");
+                       dev_err(&intf->dev, "failed to get mac address\n");
                        goto error2;
                }
                dev_info(&intf->dev, "MAC-Address: %pM\n", dev->net->dev_addr);
index 17a0505..6700f19 100644 (file)
@@ -429,13 +429,6 @@ static ssize_t add_mux_store(struct device *d,  struct device_attribute *attr, c
                goto err;
        }
 
-       /* we don't want to modify a running netdev */
-       if (netif_running(dev->net)) {
-               netdev_err(dev->net, "Cannot change a running device\n");
-               ret = -EBUSY;
-               goto err;
-       }
-
        ret = qmimux_register_device(dev->net, mux_id);
        if (!ret) {
                info->flags |= QMI_WWAN_FLAG_MUX;
@@ -465,13 +458,6 @@ static ssize_t del_mux_store(struct device *d,  struct device_attribute *attr, c
        if (!rtnl_trylock())
                return restart_syscall();
 
-       /* we don't want to modify a running netdev */
-       if (netif_running(dev->net)) {
-               netdev_err(dev->net, "Cannot change a running device\n");
-               ret = -EBUSY;
-               goto err;
-       }
-
        del_dev = qmimux_find_dev(dev, mux_id);
        if (!del_dev) {
                netdev_err(dev->net, "mux_id not present\n");
index b246817..90f1c02 100644 (file)
@@ -3021,29 +3021,6 @@ static void __rtl_set_wol(struct r8152 *tp, u32 wolopts)
                device_set_wakeup_enable(&tp->udev->dev, false);
 }
 
-static void r8153_mac_clk_spd(struct r8152 *tp, bool enable)
-{
-       /* MAC clock speed down */
-       if (enable) {
-               ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL,
-                              ALDPS_SPDWN_RATIO);
-               ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2,
-                              EEE_SPDWN_RATIO);
-               ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3,
-                              PKT_AVAIL_SPDWN_EN | SUSPEND_SPDWN_EN |
-                              U1U2_SPDWN_EN | L1_SPDWN_EN);
-               ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4,
-                              PWRSAVE_SPDWN_EN | RXDV_SPDWN_EN | TX10MIDLE_EN |
-                              TP100_SPDWN_EN | TP500_SPDWN_EN | EEE_SPDWN_EN |
-                              TP1000_SPDWN_EN);
-       } else {
-               ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, 0);
-               ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, 0);
-               ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, 0);
-               ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4, 0);
-       }
-}
-
 static void r8153_u1u2en(struct r8152 *tp, bool enable)
 {
        u8 u1u2[8];
@@ -3338,11 +3315,9 @@ static void rtl8153_runtime_enable(struct r8152 *tp, bool enable)
        if (enable) {
                r8153_u1u2en(tp, false);
                r8153_u2p3en(tp, false);
-               r8153_mac_clk_spd(tp, true);
                rtl_runtime_suspend_enable(tp, true);
        } else {
                rtl_runtime_suspend_enable(tp, false);
-               r8153_mac_clk_spd(tp, false);
 
                switch (tp->version) {
                case RTL_VER_03:
@@ -4718,7 +4693,6 @@ static void r8153_first_init(struct r8152 *tp)
 {
        u32 ocp_data;
 
-       r8153_mac_clk_spd(tp, false);
        rxdy_gated_en(tp, true);
        r8153_teredo_off(tp);
 
@@ -4769,8 +4743,6 @@ static void r8153_enter_oob(struct r8152 *tp)
 {
        u32 ocp_data;
 
-       r8153_mac_clk_spd(tp, true);
-
        ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
        ocp_data &= ~NOW_IS_OOB;
        ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
@@ -5496,10 +5468,15 @@ static void r8153_init(struct r8152 *tp)
 
        ocp_write_word(tp, MCU_TYPE_USB, USB_CONNECT_TIMER, 0x0001);
 
+       /* MAC clock speed down */
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, 0);
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, 0);
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, 0);
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4, 0);
+
        r8153_power_cut_en(tp, false);
        rtl_runtime_suspend_enable(tp, false);
        r8153_u1u2en(tp, true);
-       r8153_mac_clk_spd(tp, false);
        usb_enable_lpm(tp->udev);
 
        ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CONFIG6);
index b4c8080..f4f37ec 100644 (file)
@@ -887,7 +887,7 @@ int usbnet_open (struct net_device *net)
 
        // insist peer be connected
        if (info->check_connect && (retval = info->check_connect (dev)) < 0) {
-               netif_dbg(dev, ifup, dev->net, "can't open; %d\n", retval);
+               netif_err(dev, ifup, dev->net, "can't open; %d\n", retval);
                goto done;
        }
 
index dca97cd..7eac6a3 100644 (file)
@@ -204,14 +204,18 @@ static int uhdlc_init(struct ucc_hdlc_private *priv)
        priv->rx_skbuff = kcalloc(priv->rx_ring_size,
                                  sizeof(*priv->rx_skbuff),
                                  GFP_KERNEL);
-       if (!priv->rx_skbuff)
+       if (!priv->rx_skbuff) {
+               ret = -ENOMEM;
                goto free_ucc_pram;
+       }
 
        priv->tx_skbuff = kcalloc(priv->tx_ring_size,
                                  sizeof(*priv->tx_skbuff),
                                  GFP_KERNEL);
-       if (!priv->tx_skbuff)
+       if (!priv->tx_skbuff) {
+               ret = -ENOMEM;
                goto free_rx_skbuff;
+       }
 
        priv->skb_curtx = 0;
        priv->skb_dirtytx = 0;
index 605fe55..c337249 100644 (file)
@@ -292,7 +292,6 @@ static int lapbeth_open(struct net_device *dev)
                return -ENODEV;
        }
 
-       netif_start_queue(dev);
        return 0;
 }
 
@@ -300,8 +299,6 @@ static int lapbeth_close(struct net_device *dev)
 {
        int err;
 
-       netif_stop_queue(dev);
-
        if ((err = lapb_unregister(dev)) != LAPB_OK)
                pr_err("lapb_unregister error: %d\n", err);
 
index c41e725..2db9c94 100644 (file)
@@ -28,7 +28,6 @@
 MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
 MODULE_AUTHOR("Jouni Malinen <j@w1.fi>");
 MODULE_DESCRIPTION("Driver for IEEE 802.11b wireless cards based on ADMtek ADM8211");
-MODULE_SUPPORTED_DEVICE("ADM8211");
 MODULE_LICENSE("GPL");
 
 static unsigned int tx_ring_size __read_mostly = 16;
index b391169..faa2e67 100644 (file)
@@ -5450,8 +5450,8 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
        }
 
        if (ab->hw_params.vdev_start_delay &&
-           (arvif->vdev_type == WMI_VDEV_TYPE_AP ||
-           arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)) {
+           arvif->vdev_type != WMI_VDEV_TYPE_AP &&
+           arvif->vdev_type != WMI_VDEV_TYPE_MONITOR) {
                param.vdev_id = arvif->vdev_id;
                param.peer_type = WMI_PEER_TYPE_DEFAULT;
                param.peer_addr = ar->mac_addr;
index 1aca841..7968fe4 100644 (file)
@@ -1687,8 +1687,8 @@ static int ath11k_qmi_respond_fw_mem_request(struct ath11k_base *ab)
                        req->mem_seg[i].size = ab->qmi.target_mem[i].size;
                        req->mem_seg[i].type = ab->qmi.target_mem[i].type;
                        ath11k_dbg(ab, ATH11K_DBG_QMI,
-                                  "qmi req mem_seg[%d] 0x%llx %u %u\n", i,
-                                   ab->qmi.target_mem[i].paddr,
+                                  "qmi req mem_seg[%d] %pad %u %u\n", i,
+                                   &ab->qmi.target_mem[i].paddr,
                                    ab->qmi.target_mem[i].size,
                                    ab->qmi.target_mem[i].type);
                }
index 4c6e57f..cef17f3 100644 (file)
@@ -90,7 +90,6 @@ MODULE_PARM_DESC(no_hw_rfkill_switch, "Ignore the GPIO RFKill switch state");
 MODULE_AUTHOR("Jiri Slaby");
 MODULE_AUTHOR("Nick Kossifidis");
 MODULE_DESCRIPTION("Support for 5xxx series of Atheros 802.11 wireless LAN cards.");
-MODULE_SUPPORTED_DEVICE("Atheros 5xxx WLAN cards");
 MODULE_LICENSE("Dual BSD/GPL");
 
 static int ath5k_init(struct ieee80211_hw *hw);
index 13b4f5f..ef6f5ea 100644 (file)
@@ -177,7 +177,8 @@ struct ath_frame_info {
        s8 txq;
        u8 keyix;
        u8 rtscts_rate;
-       u8 retries : 7;
+       u8 retries : 6;
+       u8 dyn_smps : 1;
        u8 baw_tracked : 1;
        u8 tx_power;
        enum ath9k_key_type keytype:2;
index b66eeb5..5abc2a5 100644 (file)
@@ -34,7 +34,6 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type);
 
 MODULE_AUTHOR("Atheros Communications");
 MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards.");
-MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards");
 MODULE_LICENSE("Dual BSD/GPL");
 
 static void ath9k_hw_set_clockrate(struct ath_hw *ah)
index 42a2087..01f9c26 100644 (file)
@@ -37,7 +37,6 @@ static char *dev_info = "ath9k";
 
 MODULE_AUTHOR("Atheros Communications");
 MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards.");
-MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards");
 MODULE_LICENSE("Dual BSD/GPL");
 
 static unsigned int ath9k_debug = ATH_DBG_DEFAULT;
index e60d473..5691bd6 100644 (file)
@@ -1271,6 +1271,11 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
                                 is_40, is_sgi, is_sp);
                        if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
                                info->rates[i].RateFlags |= ATH9K_RATESERIES_STBC;
+                       if (rix >= 8 && fi->dyn_smps) {
+                               info->rates[i].RateFlags |=
+                                       ATH9K_RATESERIES_RTS_CTS;
+                               info->flags |= ATH9K_TXDESC_CTSENA;
+                       }
 
                        info->txpower[i] = ath_get_rate_txpower(sc, bf, rix,
                                                                is_40, false);
@@ -2114,6 +2119,7 @@ static void setup_frame_info(struct ieee80211_hw *hw,
                fi->keyix = an->ps_key;
        else
                fi->keyix = ATH9K_TXKEYIX_INVALID;
+       fi->dyn_smps = sta && sta->smps_mode == IEEE80211_SMPS_DYNAMIC;
        fi->keytype = keytype;
        fi->framelen = framelen;
        fi->tx_power = txpower;
index 707fe66..febce4e 100644 (file)
@@ -75,7 +75,6 @@
 MODULE_AUTHOR("Simon Kelley");
 MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards.");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("Atmel at76c50x wireless cards");
 
 /* The name of the firmware file to be loaded
    over-rides any automatic selection */
index 368eebe..453bb84 100644 (file)
@@ -57,7 +57,6 @@
 MODULE_AUTHOR("Simon Kelley");
 MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards.");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("Atmel at76c50x PCMCIA cards");
 
 /*====================================================================*/
 
index 47f7ccb..f428dc7 100644 (file)
@@ -16,7 +16,6 @@
 MODULE_AUTHOR("Simon Kelley");
 MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards.");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("Atmel at76c506 PCI wireless cards");
 
 static const struct pci_device_id card_ids[] = {
        { 0x1114, 0x0506, PCI_ANY_ID, PCI_ANY_ID },
index 818e523..39f3af2 100644 (file)
@@ -87,7 +87,6 @@ static int n_adapters_found;
 
 MODULE_AUTHOR("Broadcom Corporation");
 MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver.");
-MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN cards");
 MODULE_LICENSE("Dual BSD/GPL");
 /* This needs to be adjusted when brcms_firmwares changes */
 MODULE_FIRMWARE("brcm/bcm43xx-0.fw");
index 4c84c30..e87e68c 100644 (file)
@@ -12,7 +12,6 @@
 
 MODULE_AUTHOR("Broadcom Corporation");
 MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver utilities.");
-MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN cards");
 MODULE_LICENSE("Dual BSD/GPL");
 
 struct sk_buff *brcmu_pkt_buf_get_skb(uint len)
index e35e138..60db38c 100644 (file)
@@ -251,7 +251,6 @@ MODULE_AUTHOR("Benjamin Reed");
 MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet cards.  "
                   "Direct support for ISA/PCI/MPI cards and support for PCMCIA when used with airo_cs.");
 MODULE_LICENSE("Dual BSD/GPL");
-MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340/350");
 module_param_hw_array(io, int, ioport, NULL, 0);
 module_param_hw_array(irq, int, irq, NULL, 0);
 module_param_array(rates, int, NULL, 0);
index 3718f95..fcfe4c6 100644 (file)
@@ -47,7 +47,6 @@ MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet "
                   "cards.  This is the module that links the PCMCIA card "
                   "with the airo module.");
 MODULE_LICENSE("Dual BSD/GPL");
-MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340 PCMCIA cards");
 
 /*====================================================================*/
 
index fd070ca..40f2109 100644 (file)
@@ -271,12 +271,12 @@ static int iwl_pnvm_get_from_efi(struct iwl_trans *trans,
        err = efivar_entry_get(pnvm_efivar, NULL, &package_size, package);
        if (err) {
                IWL_DEBUG_FW(trans,
-                            "PNVM UEFI variable not found %d (len %zd)\n",
+                            "PNVM UEFI variable not found %d (len %lu)\n",
                             err, package_size);
                goto out;
        }
 
-       IWL_DEBUG_FW(trans, "Read PNVM fro UEFI with size %zd\n", package_size);
+       IWL_DEBUG_FW(trans, "Read PNVM fro UEFI with size %lu\n", package_size);
 
        *data = kmemdup(package->data, *len, GFP_KERNEL);
        if (!*data)
index 868da7e..e6d2e09 100644 (file)
@@ -205,6 +205,8 @@ static inline void iwl_op_mode_time_point(struct iwl_op_mode *op_mode,
                                          enum iwl_fw_ini_time_point tp_id,
                                          union iwl_dbg_tlv_tp_data *tp_data)
 {
+       if (!op_mode || !op_mode->ops || !op_mode->ops->time_point)
+               return;
        op_mode->ops->time_point(op_mode, tp_id, tp_data);
 }
 
index 15e2773..5ee64f7 100644 (file)
@@ -1083,6 +1083,7 @@ static const struct dmi_system_id dmi_ppag_approved_list[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTek COMPUTER INC."),
                },
        },
+       {}
 };
 
 static int iwl_mvm_ppag_init(struct iwl_mvm *mvm)
index 314fec4..ffaf973 100644 (file)
@@ -1106,6 +1106,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                }
        }
 
+#if IS_ENABLED(CONFIG_IWLMVM)
+
        /*
         * Workaround for problematic SnJ device: sometimes when
         * certain RF modules are connected to SnJ, the device ID
@@ -1116,7 +1118,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (CSR_HW_REV_TYPE(iwl_trans->hw_rev) == IWL_CFG_MAC_TYPE_SNJ)
                iwl_trans->trans_cfg = &iwl_so_trans_cfg;
 
-#if IS_ENABLED(CONFIG_IWLMVM)
        /*
         * special-case 7265D, it has the same PCI IDs.
         *
index 42426e2..2bec971 100644 (file)
@@ -1129,6 +1129,8 @@ static int _iwl_pcie_rx_init(struct iwl_trans *trans)
 
                iwl_pcie_rx_init_rxb_lists(rxq);
 
+               spin_unlock_bh(&rxq->lock);
+
                if (!rxq->napi.poll) {
                        int (*poll)(struct napi_struct *, int) = iwl_pcie_napi_poll;
 
@@ -1149,7 +1151,6 @@ static int _iwl_pcie_rx_init(struct iwl_trans *trans)
                        napi_enable(&rxq->napi);
                }
 
-               spin_unlock_bh(&rxq->lock);
        }
 
        /* move the pool to the default queue and allocator ownerships */
index 1a74867..ec7db2b 100644 (file)
@@ -26,7 +26,6 @@ static char *dev_info = "hostap_cs";
 MODULE_AUTHOR("Jouni Malinen");
 MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN "
                   "cards (PC Card).");
-MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PC Card)");
 MODULE_LICENSE("GPL");
 
 
index 101887e..52d7750 100644 (file)
@@ -27,7 +27,6 @@ static char *dev_info = "hostap_pci";
 MODULE_AUTHOR("Jouni Malinen");
 MODULE_DESCRIPTION("Support for Intersil Prism2.5-based 802.11 wireless LAN "
                   "PCI cards.");
-MODULE_SUPPORTED_DEVICE("Intersil Prism2.5-based WLAN PCI cards");
 MODULE_LICENSE("GPL");
 
 
index 841cfc6..5824729 100644 (file)
@@ -30,7 +30,6 @@ static char *dev_info = "hostap_plx";
 MODULE_AUTHOR("Jouni Malinen");
 MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN "
                   "cards (PLX).");
-MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PLX)");
 MODULE_LICENSE("GPL");
 
 
index 19098b8..2f27c43 100644 (file)
@@ -345,7 +345,6 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q,
        };
        struct ieee80211_hw *hw;
        int len, n = 0, ret = -ENOMEM;
-       struct mt76_queue_entry e;
        struct mt76_txwi_cache *t;
        struct sk_buff *iter;
        dma_addr_t addr;
@@ -387,6 +386,11 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q,
        }
        tx_info.nbuf = n;
 
+       if (q->queued + (tx_info.nbuf + 1) / 2 >= q->ndesc - 1) {
+               ret = -ENOMEM;
+               goto unmap;
+       }
+
        dma_sync_single_for_cpu(dev->dev, t->dma_addr, dev->drv->txwi_size,
                                DMA_TO_DEVICE);
        ret = dev->drv->tx_prepare_skb(dev, txwi, q->qid, wcid, sta, &tx_info);
@@ -395,11 +399,6 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q,
        if (ret < 0)
                goto unmap;
 
-       if (q->queued + (tx_info.nbuf + 1) / 2 >= q->ndesc - 1) {
-               ret = -ENOMEM;
-               goto unmap;
-       }
-
        return mt76_dma_add_buf(dev, q, tx_info.buf, tx_info.nbuf,
                                tx_info.info, tx_info.skb, t);
 
@@ -419,9 +418,7 @@ free:
        }
 #endif
 
-       e.skb = tx_info.skb;
-       e.txwi = t;
-       dev->drv->tx_complete_skb(dev, &e);
+       dev_kfree_skb(tx_info.skb);
        mt76_put_txwi(dev, t);
        return ret;
 }
@@ -515,13 +512,13 @@ mt76_add_fragment(struct mt76_dev *dev, struct mt76_queue *q, void *data,
 {
        struct sk_buff *skb = q->rx_head;
        struct skb_shared_info *shinfo = skb_shinfo(skb);
+       int nr_frags = shinfo->nr_frags;
 
-       if (shinfo->nr_frags < ARRAY_SIZE(shinfo->frags)) {
+       if (nr_frags < ARRAY_SIZE(shinfo->frags)) {
                struct page *page = virt_to_head_page(data);
                int offset = data - page_address(page) + q->buf_offset;
 
-               skb_add_rx_frag(skb, shinfo->nr_frags, page, offset, len,
-                               q->buf_size);
+               skb_add_rx_frag(skb, nr_frags, page, offset, len, q->buf_size);
        } else {
                skb_free_frag(data);
        }
@@ -530,7 +527,10 @@ mt76_add_fragment(struct mt76_dev *dev, struct mt76_queue *q, void *data,
                return;
 
        q->rx_head = NULL;
-       dev->drv->rx_skb(dev, q - dev->q_rx, skb);
+       if (nr_frags < ARRAY_SIZE(shinfo->frags))
+               dev->drv->rx_skb(dev, q - dev->q_rx, skb);
+       else
+               dev_kfree_skb(skb);
 }
 
 static int
index eb889f8..e5a2589 100644 (file)
@@ -967,11 +967,6 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
        }
        txp->nbuf = nbuf;
 
-       /* pass partial skb header to fw */
-       tx_info->buf[1].len = MT_CT_PARSE_LEN;
-       tx_info->buf[1].skip_unmap = true;
-       tx_info->nbuf = MT_CT_DMA_BUF_NUM;
-
        txp->flags = cpu_to_le16(MT_CT_INFO_APPLY_TXD | MT_CT_INFO_FROM_HOST);
 
        if (!key)
@@ -1009,6 +1004,11 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
                txp->rept_wds_wcid = cpu_to_le16(0x3ff);
        tx_info->skb = DMA_DUMMY_DATA;
 
+       /* pass partial skb header to fw */
+       tx_info->buf[1].len = MT_CT_PARSE_LEN;
+       tx_info->buf[1].skip_unmap = true;
+       tx_info->nbuf = MT_CT_DMA_BUF_NUM;
+
        return 0;
 }
 
index 7fb2170..bd798df 100644 (file)
@@ -543,7 +543,7 @@ mt7915_tm_set_tx_cont(struct mt7915_phy *phy, bool en)
                tx_cont->bw = CMD_CBW_20MHZ;
                break;
        default:
-               break;
+               return -EINVAL;
        }
 
        if (!en) {
@@ -591,7 +591,7 @@ mt7915_tm_set_tx_cont(struct mt7915_phy *phy, bool en)
                mode = MT_PHY_TYPE_HE_MU;
                break;
        default:
-               break;
+               return -EINVAL;
        }
 
        rateval =  mode << 6 | rate_idx;
index db125cd..b5cc72e 100644 (file)
@@ -405,10 +405,8 @@ mt7921_mcu_tx_rate_report(struct mt7921_dev *dev, struct sk_buff *skb,
        if (wlan_idx >= MT76_N_WCIDS)
                return;
        wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]);
-       if (!wcid) {
-               stats->tx_rate = rate;
+       if (!wcid)
                return;
-       }
 
        msta = container_of(wcid, struct mt7921_sta, wcid);
        stats = &msta->stats;
index 8f860c1..dec6ffd 100644 (file)
@@ -1821,7 +1821,6 @@ static const struct pci_device_id rt2400pci_device_table[] = {
 MODULE_AUTHOR(DRV_PROJECT);
 MODULE_VERSION(DRV_VERSION);
 MODULE_DESCRIPTION("Ralink RT2400 PCI & PCMCIA Wireless LAN driver.");
-MODULE_SUPPORTED_DEVICE("Ralink RT2460 PCI & PCMCIA chipset based cards");
 MODULE_DEVICE_TABLE(pci, rt2400pci_device_table);
 MODULE_LICENSE("GPL");
 
index e940443..8faa0a8 100644 (file)
@@ -2119,7 +2119,6 @@ static const struct pci_device_id rt2500pci_device_table[] = {
 MODULE_AUTHOR(DRV_PROJECT);
 MODULE_VERSION(DRV_VERSION);
 MODULE_DESCRIPTION("Ralink RT2500 PCI & PCMCIA Wireless LAN driver.");
-MODULE_SUPPORTED_DEVICE("Ralink RT2560 PCI & PCMCIA chipset based cards");
 MODULE_DEVICE_TABLE(pci, rt2500pci_device_table);
 MODULE_LICENSE("GPL");
 
index fce05fc..bb5ed66 100644 (file)
@@ -1956,7 +1956,6 @@ static const struct usb_device_id rt2500usb_device_table[] = {
 MODULE_AUTHOR(DRV_PROJECT);
 MODULE_VERSION(DRV_VERSION);
 MODULE_DESCRIPTION("Ralink RT2500 USB Wireless LAN driver.");
-MODULE_SUPPORTED_DEVICE("Ralink RT2570 USB chipset based cards");
 MODULE_DEVICE_TABLE(usb, rt2500usb_device_table);
 MODULE_LICENSE("GPL");
 
index 9a33baa..1fde0e7 100644 (file)
@@ -439,7 +439,6 @@ static const struct pci_device_id rt2800pci_device_table[] = {
 MODULE_AUTHOR(DRV_PROJECT);
 MODULE_VERSION(DRV_VERSION);
 MODULE_DESCRIPTION("Ralink RT2800 PCI & PCMCIA Wireless LAN driver.");
-MODULE_SUPPORTED_DEVICE("Ralink RT2860 PCI & PCMCIA chipset based cards");
 MODULE_FIRMWARE(FIRMWARE_RT2860);
 MODULE_DEVICE_TABLE(pci, rt2800pci_device_table);
 MODULE_LICENSE("GPL");
index 36ac18c..b5c67f6 100644 (file)
@@ -1248,7 +1248,6 @@ static const struct usb_device_id rt2800usb_device_table[] = {
 MODULE_AUTHOR(DRV_PROJECT);
 MODULE_VERSION(DRV_VERSION);
 MODULE_DESCRIPTION("Ralink RT2800 USB Wireless LAN driver.");
-MODULE_SUPPORTED_DEVICE("Ralink RT2870 USB chipset based cards");
 MODULE_DEVICE_TABLE(usb, rt2800usb_device_table);
 MODULE_FIRMWARE(FIRMWARE_RT2870);
 MODULE_LICENSE("GPL");
index 02da5dd..82cfc2a 100644 (file)
@@ -2993,8 +2993,6 @@ static const struct pci_device_id rt61pci_device_table[] = {
 MODULE_AUTHOR(DRV_PROJECT);
 MODULE_VERSION(DRV_VERSION);
 MODULE_DESCRIPTION("Ralink RT61 PCI & PCMCIA Wireless LAN driver.");
-MODULE_SUPPORTED_DEVICE("Ralink RT2561, RT2561s & RT2661 "
-                       "PCI & PCMCIA chipset based cards");
 MODULE_DEVICE_TABLE(pci, rt61pci_device_table);
 MODULE_FIRMWARE(FIRMWARE_RT2561);
 MODULE_FIRMWARE(FIRMWARE_RT2561s);
index e697937..5ff2c74 100644 (file)
@@ -2513,7 +2513,6 @@ static const struct usb_device_id rt73usb_device_table[] = {
 MODULE_AUTHOR(DRV_PROJECT);
 MODULE_VERSION(DRV_VERSION);
 MODULE_DESCRIPTION("Ralink RT73 USB Wireless LAN driver.");
-MODULE_SUPPORTED_DEVICE("Ralink RT2571W & RT2671 USB chipset based cards");
 MODULE_DEVICE_TABLE(usb, rt73usb_device_table);
 MODULE_FIRMWARE(FIRMWARE_RT2571);
 MODULE_LICENSE("GPL");
index 9a3d243..d984832 100644 (file)
@@ -441,6 +441,5 @@ module_init(rsi_91x_hal_module_init);
 module_exit(rsi_91x_hal_module_exit);
 MODULE_AUTHOR("Redpine Signals Inc");
 MODULE_DESCRIPTION("Station driver for RSI 91x devices");
-MODULE_SUPPORTED_DEVICE("RSI-91x");
 MODULE_VERSION("0.1");
 MODULE_LICENSE("Dual BSD/GPL");
index 592e9da..fe0287b 100644 (file)
@@ -1571,7 +1571,6 @@ module_exit(rsi_module_exit);
 
 MODULE_AUTHOR("Redpine Signals Inc");
 MODULE_DESCRIPTION("Common SDIO layer for RSI drivers");
-MODULE_SUPPORTED_DEVICE("RSI-91x");
 MODULE_DEVICE_TABLE(sdio, rsi_dev_table);
 MODULE_FIRMWARE(FIRMWARE_RSI9113);
 MODULE_VERSION("0.1");
index a4a533c..3fbe2a3 100644 (file)
@@ -928,7 +928,6 @@ module_usb_driver(rsi_driver);
 
 MODULE_AUTHOR("Redpine Signals Inc");
 MODULE_DESCRIPTION("Common USB layer for RSI drivers");
-MODULE_SUPPORTED_DEVICE("RSI-91x");
 MODULE_DEVICE_TABLE(usb, rsi_dev_table);
 MODULE_FIRMWARE(FIRMWARE_RSI9113);
 MODULE_VERSION("0.1");
index 6afb5ca..39a01c2 100644 (file)
@@ -557,8 +557,8 @@ check_frags:
        }
 
        if (skb_has_frag_list(skb) && !first_shinfo) {
-               first_shinfo = skb_shinfo(skb);
-               shinfo = skb_shinfo(skb_shinfo(skb)->frag_list);
+               first_shinfo = shinfo;
+               shinfo = skb_shinfo(shinfo->frag_list);
                nr_frags = shinfo->nr_frags;
 
                goto check_frags;
index e68a8c4..0896e21 100644 (file)
@@ -380,6 +380,7 @@ bool nvme_cancel_request(struct request *req, void *data, bool reserved)
                return true;
 
        nvme_req(req)->status = NVME_SC_HOST_ABORTED_CMD;
+       nvme_req(req)->flags |= NVME_REQ_CANCELLED;
        blk_mq_complete_request(req);
        return true;
 }
@@ -1225,28 +1226,12 @@ static void nvme_keep_alive_end_io(struct request *rq, blk_status_t status)
                queue_delayed_work(nvme_wq, &ctrl->ka_work, ctrl->kato * HZ);
 }
 
-static int nvme_keep_alive(struct nvme_ctrl *ctrl)
-{
-       struct request *rq;
-
-       rq = nvme_alloc_request(ctrl->admin_q, &ctrl->ka_cmd,
-                       BLK_MQ_REQ_RESERVED);
-       if (IS_ERR(rq))
-               return PTR_ERR(rq);
-
-       rq->timeout = ctrl->kato * HZ;
-       rq->end_io_data = ctrl;
-
-       blk_execute_rq_nowait(NULL, rq, 0, nvme_keep_alive_end_io);
-
-       return 0;
-}
-
 static void nvme_keep_alive_work(struct work_struct *work)
 {
        struct nvme_ctrl *ctrl = container_of(to_delayed_work(work),
                        struct nvme_ctrl, ka_work);
        bool comp_seen = ctrl->comp_seen;
+       struct request *rq;
 
        if ((ctrl->ctratt & NVME_CTRL_ATTR_TBKAS) && comp_seen) {
                dev_dbg(ctrl->device,
@@ -1256,12 +1241,18 @@ static void nvme_keep_alive_work(struct work_struct *work)
                return;
        }
 
-       if (nvme_keep_alive(ctrl)) {
+       rq = nvme_alloc_request(ctrl->admin_q, &ctrl->ka_cmd,
+                               BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT);
+       if (IS_ERR(rq)) {
                /* allocation failure, reset the controller */
-               dev_err(ctrl->device, "keep-alive failed\n");
+               dev_err(ctrl->device, "keep-alive failed: %ld\n", PTR_ERR(rq));
                nvme_reset_ctrl(ctrl);
                return;
        }
+
+       rq->timeout = ctrl->kato * HZ;
+       rq->end_io_data = ctrl;
+       blk_execute_rq_nowait(NULL, rq, 0, nvme_keep_alive_end_io);
 }
 
 static void nvme_start_keep_alive(struct nvme_ctrl *ctrl)
@@ -1440,7 +1431,7 @@ static int nvme_identify_ns(struct nvme_ctrl *ctrl, unsigned nsid,
                goto out_free_id;
        }
 
-       error = -ENODEV;
+       error = NVME_SC_INVALID_NS | NVME_SC_DNR;
        if ((*id)->ncap == 0) /* namespace not allocated or attached */
                goto out_free_id;
 
@@ -1963,30 +1954,18 @@ static void nvme_config_discard(struct gendisk *disk, struct nvme_ns *ns)
                blk_queue_max_write_zeroes_sectors(queue, UINT_MAX);
 }
 
-static void nvme_config_write_zeroes(struct gendisk *disk, struct nvme_ns *ns)
+/*
+ * Even though NVMe spec explicitly states that MDTS is not applicable to the
+ * write-zeroes, we are cautious and limit the size to the controllers
+ * max_hw_sectors value, which is based on the MDTS field and possibly other
+ * limiting factors.
+ */
+static void nvme_config_write_zeroes(struct request_queue *q,
+               struct nvme_ctrl *ctrl)
 {
-       u64 max_blocks;
-
-       if (!(ns->ctrl->oncs & NVME_CTRL_ONCS_WRITE_ZEROES) ||
-           (ns->ctrl->quirks & NVME_QUIRK_DISABLE_WRITE_ZEROES))
-               return;
-       /*
-        * Even though NVMe spec explicitly states that MDTS is not
-        * applicable to the write-zeroes:- "The restriction does not apply to
-        * commands that do not transfer data between the host and the
-        * controller (e.g., Write Uncorrectable ro Write Zeroes command).".
-        * In order to be more cautious use controller's max_hw_sectors value
-        * to configure the maximum sectors for the write-zeroes which is
-        * configured based on the controller's MDTS field in the
-        * nvme_init_identify() if available.
-        */
-       if (ns->ctrl->max_hw_sectors == UINT_MAX)
-               max_blocks = (u64)USHRT_MAX + 1;
-       else
-               max_blocks = ns->ctrl->max_hw_sectors + 1;
-
-       blk_queue_max_write_zeroes_sectors(disk->queue,
-                                          nvme_lba_to_sect(ns, max_blocks));
+       if ((ctrl->oncs & NVME_CTRL_ONCS_WRITE_ZEROES) &&
+           !(ctrl->quirks & NVME_QUIRK_DISABLE_WRITE_ZEROES))
+               blk_queue_max_write_zeroes_sectors(q, ctrl->max_hw_sectors);
 }
 
 static bool nvme_ns_ids_valid(struct nvme_ns_ids *ids)
@@ -2158,7 +2137,7 @@ static void nvme_update_disk_info(struct gendisk *disk,
        set_capacity_and_notify(disk, capacity);
 
        nvme_config_discard(disk, ns);
-       nvme_config_write_zeroes(disk, ns);
+       nvme_config_write_zeroes(disk->queue, ns->ctrl);
 
        set_disk_ro(disk, (id->nsattr & NVME_NS_ATTR_RO) ||
                test_bit(NVME_NS_FORCE_RO, &ns->flags));
@@ -4038,7 +4017,7 @@ static void nvme_ns_remove_by_nsid(struct nvme_ctrl *ctrl, u32 nsid)
 static void nvme_validate_ns(struct nvme_ns *ns, struct nvme_ns_ids *ids)
 {
        struct nvme_id_ns *id;
-       int ret = -ENODEV;
+       int ret = NVME_SC_INVALID_NS | NVME_SC_DNR;
 
        if (test_bit(NVME_NS_DEAD, &ns->flags))
                goto out;
@@ -4047,7 +4026,7 @@ static void nvme_validate_ns(struct nvme_ns *ns, struct nvme_ns_ids *ids)
        if (ret)
                goto out;
 
-       ret = -ENODEV;
+       ret = NVME_SC_INVALID_NS | NVME_SC_DNR;
        if (!nvme_ns_ids_equal(&ns->head->ids, ids)) {
                dev_err(ns->ctrl->device,
                        "identifiers changed for nsid %d\n", ns->head->ns_id);
@@ -4065,7 +4044,7 @@ out:
         *
         * TODO: we should probably schedule a delayed retry here.
         */
-       if (ret && ret != -ENOMEM && !(ret > 0 && !(ret & NVME_SC_DNR)))
+       if (ret > 0 && (ret & NVME_SC_DNR))
                nvme_ns_remove(ns);
 }
 
@@ -4095,6 +4074,12 @@ static void nvme_validate_or_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
                                nsid);
                        break;
                }
+               if (!nvme_multi_css(ctrl)) {
+                       dev_warn(ctrl->device,
+                               "command set not reported for nsid: %d\n",
+                               nsid);
+                       break;
+               }
                nvme_alloc_ns(ctrl, nsid, &ids);
                break;
        default:
index 733010d..888b108 100644 (file)
 /* default is -1: the fail fast mechanism is disabled  */
 #define NVMF_DEF_FAIL_FAST_TMO         -1
 
+/*
+ * Reserved one command for internal usage.  This command is used for sending
+ * the connect command, as well as for the keep alive command on the admin
+ * queue once live.
+ */
+#define NVMF_RESERVED_TAGS     1
+
 /*
  * Define a host as seen by the target.  We allocate one at boot, but also
  * allow the override it when creating controllers.  This is both to provide
index 20dadd8..6ffa8de 100644 (file)
@@ -1956,7 +1956,7 @@ nvme_fc_fcpio_done(struct nvmefc_fcp_req *req)
                                sizeof(op->rsp_iu), DMA_FROM_DEVICE);
 
        if (opstate == FCPOP_STATE_ABORTED)
-               status = cpu_to_le16(NVME_SC_HOST_PATH_ERROR << 1);
+               status = cpu_to_le16(NVME_SC_HOST_ABORTED_CMD << 1);
        else if (freq->status) {
                status = cpu_to_le16(NVME_SC_HOST_PATH_ERROR << 1);
                dev_info(ctrl->ctrl.device,
@@ -2055,7 +2055,7 @@ done:
                nvme_fc_complete_rq(rq);
 
 check_error:
-       if (terminate_assoc)
+       if (terminate_assoc && ctrl->ctrl.state != NVME_CTRL_RESETTING)
                queue_work(nvme_reset_wq, &ctrl->ioerr_work);
 }
 
@@ -2443,6 +2443,7 @@ nvme_fc_terminate_exchange(struct request *req, void *data, bool reserved)
        struct nvme_fc_ctrl *ctrl = to_fc_ctrl(nctrl);
        struct nvme_fc_fcp_op *op = blk_mq_rq_to_pdu(req);
 
+       op->nreq.flags |= NVME_REQ_CANCELLED;
        __nvme_fc_abort_op(ctrl, op);
        return true;
 }
@@ -2862,7 +2863,7 @@ nvme_fc_create_io_queues(struct nvme_fc_ctrl *ctrl)
        memset(&ctrl->tag_set, 0, sizeof(ctrl->tag_set));
        ctrl->tag_set.ops = &nvme_fc_mq_ops;
        ctrl->tag_set.queue_depth = ctrl->ctrl.opts->queue_size;
-       ctrl->tag_set.reserved_tags = 1; /* fabric connect */
+       ctrl->tag_set.reserved_tags = NVMF_RESERVED_TAGS;
        ctrl->tag_set.numa_node = ctrl->ctrl.numa_node;
        ctrl->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
        ctrl->tag_set.cmd_size =
@@ -3484,7 +3485,7 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts,
        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;
-       ctrl->admin_tag_set.reserved_tags = 2; /* fabric connect + Keep-Alive */
+       ctrl->admin_tag_set.reserved_tags = NVMF_RESERVED_TAGS;
        ctrl->admin_tag_set.numa_node = ctrl->ctrl.numa_node;
        ctrl->admin_tag_set.cmd_size =
                struct_size((struct nvme_fcp_op_w_sgl *)NULL, priv,
index 17ab332..7249ae7 100644 (file)
@@ -3246,6 +3246,7 @@ static const struct pci_device_id nvme_id_table[] = {
                .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, },
        { PCI_DEVICE(0x144d, 0xa822),   /* Samsung PM1725a */
                .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY |
+                               NVME_QUIRK_DISABLE_WRITE_ZEROES|
                                NVME_QUIRK_IGNORE_DEV_SUBNQN, },
        { PCI_DEVICE(0x1987, 0x5016),   /* Phison E16 */
                .driver_data = NVME_QUIRK_IGNORE_DEV_SUBNQN, },
index 53ac4d7..be905d4 100644 (file)
@@ -736,8 +736,11 @@ static int nvme_rdma_alloc_io_queues(struct nvme_rdma_ctrl *ctrl)
                return ret;
 
        ctrl->ctrl.queue_count = nr_io_queues + 1;
-       if (ctrl->ctrl.queue_count < 2)
-               return 0;
+       if (ctrl->ctrl.queue_count < 2) {
+               dev_err(ctrl->ctrl.device,
+                       "unable to set any I/O queues\n");
+               return -ENOMEM;
+       }
 
        dev_info(ctrl->ctrl.device,
                "creating %d I/O queues.\n", nr_io_queues);
@@ -798,7 +801,7 @@ static struct blk_mq_tag_set *nvme_rdma_alloc_tagset(struct nvme_ctrl *nctrl,
                memset(set, 0, sizeof(*set));
                set->ops = &nvme_rdma_admin_mq_ops;
                set->queue_depth = NVME_AQ_MQ_TAG_DEPTH;
-               set->reserved_tags = 2; /* connect + keep-alive */
+               set->reserved_tags = NVMF_RESERVED_TAGS;
                set->numa_node = nctrl->numa_node;
                set->cmd_size = sizeof(struct nvme_rdma_request) +
                                NVME_RDMA_DATA_SGL_SIZE;
@@ -811,7 +814,7 @@ static struct blk_mq_tag_set *nvme_rdma_alloc_tagset(struct nvme_ctrl *nctrl,
                memset(set, 0, sizeof(*set));
                set->ops = &nvme_rdma_mq_ops;
                set->queue_depth = nctrl->sqsize + 1;
-               set->reserved_tags = 1; /* fabric connect */
+               set->reserved_tags = NVMF_RESERVED_TAGS;
                set->numa_node = nctrl->numa_node;
                set->flags = BLK_MQ_F_SHOULD_MERGE;
                set->cmd_size = sizeof(struct nvme_rdma_request) +
index 69f59d2..a0f00cb 100644 (file)
@@ -287,7 +287,7 @@ static inline void nvme_tcp_queue_request(struct nvme_tcp_request *req,
         * directly, otherwise queue io_work. Also, only do that if we
         * are on the same cpu, so we don't introduce contention.
         */
-       if (queue->io_cpu == __smp_processor_id() &&
+       if (queue->io_cpu == raw_smp_processor_id() &&
            sync && empty && mutex_trylock(&queue->send_mutex)) {
                queue->more_requests = !last;
                nvme_tcp_send_all(queue);
@@ -568,6 +568,13 @@ static int nvme_tcp_setup_h2c_data_pdu(struct nvme_tcp_request *req,
        req->pdu_len = le32_to_cpu(pdu->r2t_length);
        req->pdu_sent = 0;
 
+       if (unlikely(!req->pdu_len)) {
+               dev_err(queue->ctrl->ctrl.device,
+                       "req %d r2t len is %u, probably a bug...\n",
+                       rq->tag, req->pdu_len);
+               return -EPROTO;
+       }
+
        if (unlikely(req->data_sent + req->pdu_len > req->data_len)) {
                dev_err(queue->ctrl->ctrl.device,
                        "req %d r2t len %u exceeded data len %u (%zu sent)\n",
@@ -1575,7 +1582,7 @@ static struct blk_mq_tag_set *nvme_tcp_alloc_tagset(struct nvme_ctrl *nctrl,
                memset(set, 0, sizeof(*set));
                set->ops = &nvme_tcp_admin_mq_ops;
                set->queue_depth = NVME_AQ_MQ_TAG_DEPTH;
-               set->reserved_tags = 2; /* connect + keep-alive */
+               set->reserved_tags = NVMF_RESERVED_TAGS;
                set->numa_node = nctrl->numa_node;
                set->flags = BLK_MQ_F_BLOCKING;
                set->cmd_size = sizeof(struct nvme_tcp_request);
@@ -1587,7 +1594,7 @@ static struct blk_mq_tag_set *nvme_tcp_alloc_tagset(struct nvme_ctrl *nctrl,
                memset(set, 0, sizeof(*set));
                set->ops = &nvme_tcp_mq_ops;
                set->queue_depth = nctrl->sqsize + 1;
-               set->reserved_tags = 1; /* fabric connect */
+               set->reserved_tags = NVMF_RESERVED_TAGS;
                set->numa_node = nctrl->numa_node;
                set->flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING;
                set->cmd_size = sizeof(struct nvme_tcp_request);
@@ -1745,8 +1752,11 @@ static int nvme_tcp_alloc_io_queues(struct nvme_ctrl *ctrl)
                return ret;
 
        ctrl->queue_count = nr_io_queues + 1;
-       if (ctrl->queue_count < 2)
-               return 0;
+       if (ctrl->queue_count < 2) {
+               dev_err(ctrl->device,
+                       "unable to set any I/O queues\n");
+               return -ENOMEM;
+       }
 
        dev_info(ctrl->device,
                "creating %d I/O queues.\n", nr_io_queues);
index c7e3ec5..bc2f344 100644 (file)
@@ -9,7 +9,13 @@
 
 int nvme_revalidate_zones(struct nvme_ns *ns)
 {
-       return blk_revalidate_disk_zones(ns->disk, NULL);
+       struct request_queue *q = ns->queue;
+       int ret;
+
+       ret = blk_revalidate_disk_zones(ns->disk, NULL);
+       if (!ret)
+               blk_queue_max_zone_append_sectors(q, ns->ctrl->max_zone_append);
+       return ret;
 }
 
 static int nvme_set_max_append(struct nvme_ctrl *ctrl)
@@ -107,7 +113,6 @@ int nvme_update_zone_info(struct nvme_ns *ns, unsigned lbaf)
        blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, q);
        blk_queue_max_open_zones(q, le32_to_cpu(id->mor) + 1);
        blk_queue_max_active_zones(q, le32_to_cpu(id->mar) + 1);
-       blk_queue_max_zone_append_sectors(q, ns->ctrl->max_zone_append);
 free_data:
        kfree(id);
        return status;
index be6fcda..a027433 100644 (file)
@@ -1118,9 +1118,20 @@ static void nvmet_start_ctrl(struct nvmet_ctrl *ctrl)
 {
        lockdep_assert_held(&ctrl->lock);
 
-       if (nvmet_cc_iosqes(ctrl->cc) != NVME_NVM_IOSQES ||
-           nvmet_cc_iocqes(ctrl->cc) != NVME_NVM_IOCQES ||
-           nvmet_cc_mps(ctrl->cc) != 0 ||
+       /*
+        * Only I/O controllers should verify iosqes,iocqes.
+        * Strictly speaking, the spec says a discovery controller
+        * should verify iosqes,iocqes are zeroed, however that
+        * would break backwards compatibility, so don't enforce it.
+        */
+       if (ctrl->subsys->type != NVME_NQN_DISC &&
+           (nvmet_cc_iosqes(ctrl->cc) != NVME_NVM_IOSQES ||
+            nvmet_cc_iocqes(ctrl->cc) != NVME_NVM_IOCQES)) {
+               ctrl->csts = NVME_CSTS_CFS;
+               return;
+       }
+
+       if (nvmet_cc_mps(ctrl->cc) != 0 ||
            nvmet_cc_ams(ctrl->cc) != 0 ||
            nvmet_cc_css(ctrl->cc) != 0) {
                ctrl->csts = NVME_CSTS_CFS;
index cb6f865..3e189e7 100644 (file)
@@ -349,7 +349,7 @@ static int nvme_loop_configure_admin_queue(struct nvme_loop_ctrl *ctrl)
        memset(&ctrl->admin_tag_set, 0, sizeof(ctrl->admin_tag_set));
        ctrl->admin_tag_set.ops = &nvme_loop_admin_mq_ops;
        ctrl->admin_tag_set.queue_depth = NVME_AQ_MQ_TAG_DEPTH;
-       ctrl->admin_tag_set.reserved_tags = 2; /* connect + keep-alive */
+       ctrl->admin_tag_set.reserved_tags = NVMF_RESERVED_TAGS;
        ctrl->admin_tag_set.numa_node = ctrl->ctrl.numa_node;
        ctrl->admin_tag_set.cmd_size = sizeof(struct nvme_loop_iod) +
                NVME_INLINE_SG_CNT * sizeof(struct scatterlist);
@@ -520,7 +520,7 @@ static int nvme_loop_create_io_queues(struct nvme_loop_ctrl *ctrl)
        memset(&ctrl->tag_set, 0, sizeof(ctrl->tag_set));
        ctrl->tag_set.ops = &nvme_loop_mq_ops;
        ctrl->tag_set.queue_depth = ctrl->ctrl.opts->queue_size;
-       ctrl->tag_set.reserved_tags = 1; /* fabric connect */
+       ctrl->tag_set.reserved_tags = NVMF_RESERVED_TAGS;
        ctrl->tag_set.numa_node = ctrl->ctrl.numa_node;
        ctrl->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
        ctrl->tag_set.cmd_size = sizeof(struct nvme_loop_iod) +
index 26c587c..2798944 100644 (file)
@@ -50,9 +50,9 @@ static u16 nvmet_passthru_override_id_ctrl(struct nvmet_req *req)
 
        /*
         * nvmet_passthru_map_sg is limitted to using a single bio so limit
-        * the mdts based on BIO_MAX_PAGES as well
+        * the mdts based on BIO_MAX_VECS as well
         */
-       max_hw_sectors = min_not_zero(BIO_MAX_PAGES << (PAGE_SHIFT - 9),
+       max_hw_sectors = min_not_zero(BIO_MAX_VECS << (PAGE_SHIFT - 9),
                                      max_hw_sectors);
 
        page_shift = NVME_CAP_MPSMIN(ctrl->cap) + 12;
@@ -191,7 +191,7 @@ static int nvmet_passthru_map_sg(struct nvmet_req *req, struct request *rq)
        struct bio *bio;
        int i;
 
-       if (req->sg_cnt > BIO_MAX_PAGES)
+       if (req->sg_cnt > BIO_MAX_VECS)
                return -EINVAL;
 
        if (req->transfer_len <= NVMET_MAX_INLINE_DATA_LEN) {
index 06b6b74..6c1f3ab 100644 (file)
@@ -802,9 +802,8 @@ static void nvmet_rdma_write_data_done(struct ib_cq *cq, struct ib_wc *wc)
                nvmet_req_uninit(&rsp->req);
                nvmet_rdma_release_rsp(rsp);
                if (wc->status != IB_WC_WR_FLUSH_ERR) {
-                       pr_info("RDMA WRITE for CQE 0x%p failed with status %s (%d).\n",
-                               wc->wr_cqe, ib_wc_status_msg(wc->status),
-                               wc->status);
+                       pr_info("RDMA WRITE for CQE failed with status %s (%d).\n",
+                               ib_wc_status_msg(wc->status), wc->status);
                        nvmet_rdma_error_comp(queue);
                }
                return;
index 8b0485a..d658c6e 100644 (file)
@@ -1098,11 +1098,11 @@ static int nvmet_tcp_try_recv_data(struct nvmet_tcp_queue *queue)
                cmd->rbytes_done += ret;
        }
 
+       nvmet_tcp_unmap_pdu_iovec(cmd);
        if (queue->data_digest) {
                nvmet_tcp_prep_recv_ddgst(cmd);
                return 0;
        }
-       nvmet_tcp_unmap_pdu_iovec(cmd);
 
        if (!(cmd->flags & NVMET_TCP_F_INIT_FAILED) &&
            cmd->rbytes_done == cmd->req.transfer_len) {
index c268938..1556998 100644 (file)
@@ -1492,7 +1492,11 @@ static struct dev_pm_opp *_opp_get_next(struct opp_table *opp_table,
 
        mutex_lock(&opp_table->lock);
        list_for_each_entry(temp, &opp_table->opp_list, node) {
-               if (dynamic == temp->dynamic) {
+               /*
+                * Refcount must be dropped only once for each OPP by OPP core,
+                * do that with help of "removed" flag.
+                */
+               if (!temp->removed && dynamic == temp->dynamic) {
                        opp = temp;
                        break;
                }
@@ -1502,10 +1506,27 @@ static struct dev_pm_opp *_opp_get_next(struct opp_table *opp_table,
        return opp;
 }
 
-bool _opp_remove_all_static(struct opp_table *opp_table)
+/*
+ * Can't call dev_pm_opp_put() from under the lock as debugfs removal needs to
+ * happen lock less to avoid circular dependency issues. This routine must be
+ * called without the opp_table->lock held.
+ */
+static void _opp_remove_all(struct opp_table *opp_table, bool dynamic)
 {
        struct dev_pm_opp *opp;
 
+       while ((opp = _opp_get_next(opp_table, dynamic))) {
+               opp->removed = true;
+               dev_pm_opp_put(opp);
+
+               /* Drop the references taken by dev_pm_opp_add() */
+               if (dynamic)
+                       dev_pm_opp_put_opp_table(opp_table);
+       }
+}
+
+bool _opp_remove_all_static(struct opp_table *opp_table)
+{
        mutex_lock(&opp_table->lock);
 
        if (!opp_table->parsed_static_opps) {
@@ -1520,13 +1541,7 @@ bool _opp_remove_all_static(struct opp_table *opp_table)
 
        mutex_unlock(&opp_table->lock);
 
-       /*
-        * Can't remove the OPP from under the lock, debugfs removal needs to
-        * happen lock less to avoid circular dependency issues.
-        */
-       while ((opp = _opp_get_next(opp_table, false)))
-               dev_pm_opp_put(opp);
-
+       _opp_remove_all(opp_table, false);
        return true;
 }
 
@@ -1539,25 +1554,12 @@ bool _opp_remove_all_static(struct opp_table *opp_table)
 void dev_pm_opp_remove_all_dynamic(struct device *dev)
 {
        struct opp_table *opp_table;
-       struct dev_pm_opp *opp;
-       int count = 0;
 
        opp_table = _find_opp_table(dev);
        if (IS_ERR(opp_table))
                return;
 
-       /*
-        * Can't remove the OPP from under the lock, debugfs removal needs to
-        * happen lock less to avoid circular dependency issues.
-        */
-       while ((opp = _opp_get_next(opp_table, true))) {
-               dev_pm_opp_put(opp);
-               count++;
-       }
-
-       /* Drop the references taken by dev_pm_opp_add() */
-       while (count--)
-               dev_pm_opp_put_opp_table(opp_table);
+       _opp_remove_all(opp_table, true);
 
        /* Drop the reference taken by _find_opp_table() */
        dev_pm_opp_put_opp_table(opp_table);
index 50fb9dc..407c3bf 100644 (file)
@@ -56,6 +56,7 @@ extern struct list_head opp_tables, lazy_opp_tables;
  * @dynamic:   not-created from static DT entries.
  * @turbo:     true if turbo (boost) OPP
  * @suspend:   true if suspend OPP
+ * @removed:   flag indicating that OPP's reference is dropped by OPP core.
  * @pstate: Device's power domain's performance state.
  * @rate:      Frequency in hertz
  * @level:     Performance level
@@ -78,6 +79,7 @@ struct dev_pm_opp {
        bool dynamic;
        bool turbo;
        bool suspend;
+       bool removed;
        unsigned int pstate;
        unsigned long rate;
        unsigned int level;
index 1e88bcf..84d5701 100644 (file)
@@ -241,6 +241,5 @@ module_platform_driver_probe(amiga_parallel_driver, amiga_parallel_probe);
 
 MODULE_AUTHOR("Joerg Dorchain <joerg@dorchain.net>");
 MODULE_DESCRIPTION("Parport Driver for Amiga builtin Port");
-MODULE_SUPPORTED_DEVICE("Amiga builtin Parallel Port");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:amiga-parallel");
index 2ff0fe0..1623f01 100644 (file)
@@ -218,7 +218,6 @@ static void __exit parport_atari_exit(void)
 
 MODULE_AUTHOR("Andreas Schwab");
 MODULE_DESCRIPTION("Parport Driver for Atari builtin Port");
-MODULE_SUPPORTED_DEVICE("Atari builtin Parallel Port");
 MODULE_LICENSE("GPL");
 
 module_init(parport_atari_init)
index 9228e8f..1e43b3f 100644 (file)
@@ -41,7 +41,6 @@
 
 MODULE_AUTHOR("Helge Deller <deller@gmx.de>");
 MODULE_DESCRIPTION("HP-PARISC PC-style parallel port driver");
-MODULE_SUPPORTED_DEVICE("integrated PC-style parallel port");
 MODULE_LICENSE("GPL");
 
 
index d6bbe84..f4d0da7 100644 (file)
@@ -359,7 +359,6 @@ static void __exit parport_mfc3_exit(void)
 
 MODULE_AUTHOR("Joerg Dorchain <joerg@dorchain.net>");
 MODULE_DESCRIPTION("Parport Driver for Multiface 3 expansion cards Parallel Port");
-MODULE_SUPPORTED_DEVICE("Multiface 3 Parallel Port");
 MODULE_LICENSE("GPL");
 
 module_init(parport_mfc3_init)
index e840c1b..865fc41 100644 (file)
@@ -377,6 +377,5 @@ module_platform_driver(bpp_sbus_driver);
 
 MODULE_AUTHOR("Derrick J Brashear");
 MODULE_DESCRIPTION("Parport Driver for Sparc bidirectional Port");
-MODULE_SUPPORTED_DEVICE("Sparc Bidirectional Parallel Port");
 MODULE_VERSION("2.0");
 MODULE_LICENSE("GPL");
index cdbfa5d..dbfa0b5 100644 (file)
@@ -34,12 +34,11 @@ static ssize_t add_slot_store(struct kobject *kobj, struct kobj_attribute *attr,
        if (nbytes >= MAX_DRC_NAME_LEN)
                return 0;
 
-       memcpy(drc_name, buf, nbytes);
+       strscpy(drc_name, buf, nbytes + 1);
 
        end = strchr(drc_name, '\n');
-       if (!end)
-               end = &drc_name[nbytes];
-       *end = '\0';
+       if (end)
+               *end = '\0';
 
        rc = dlpar_add_slot(drc_name);
        if (rc)
@@ -65,12 +64,11 @@ static ssize_t remove_slot_store(struct kobject *kobj,
        if (nbytes >= MAX_DRC_NAME_LEN)
                return 0;
 
-       memcpy(drc_name, buf, nbytes);
+       strscpy(drc_name, buf, nbytes + 1);
 
        end = strchr(drc_name, '\n');
-       if (!end)
-               end = &drc_name[nbytes];
-       *end = '\0';
+       if (end)
+               *end = '\0';
 
        rc = dlpar_remove_slot(drc_name);
        if (rc)
index c9e790c..a047c42 100644 (file)
@@ -93,8 +93,9 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
                pci_dev_put(pdev);
                return -EBUSY;
        }
+       pci_dev_put(pdev);
 
-       zpci_remove_device(zdev);
+       zpci_remove_device(zdev, false);
 
        rc = zpci_disable_device(zdev);
        if (rc)
index c6fe0cf..2d75026 100644 (file)
@@ -26,7 +26,7 @@
 #include <xen/platform_pci.h>
 
 #include <asm/xen/swiotlb-xen.h>
-#define INVALID_GRANT_REF (0)
+
 #define INVALID_EVTCHN    (-1)
 
 struct pci_bus_entry {
@@ -42,7 +42,7 @@ struct pcifront_device {
        struct list_head root_buses;
 
        int evtchn;
-       int gnt_ref;
+       grant_ref_t gnt_ref;
 
        int irq;
 
index 66ad5b3..f2a8550 100644 (file)
@@ -681,6 +681,7 @@ static int dmc620_pmu_device_probe(struct platform_device *pdev)
        if (!name) {
                dev_err(&pdev->dev,
                          "Create name failed, PMU @%pa\n", &res->start);
+               ret = -ENOMEM;
                goto out_teardown_dev;
        }
 
index c8939fb..228e21f 100644 (file)
 #define PMT_XA_MAX             INT_MAX
 #define PMT_XA_LIMIT           XA_LIMIT(PMT_XA_START, PMT_XA_MAX)
 
+/*
+ * Early implementations of PMT on client platforms have some
+ * differences from the server platforms (which use the Out Of Band
+ * Management Services Module OOBMSM). This list tracks those
+ * platforms as needed to handle those differences. Newer client
+ * platforms are expected to be fully compatible with server.
+ */
+static const struct pci_device_id pmt_telem_early_client_pci_ids[] = {
+       { PCI_VDEVICE(INTEL, 0x467d) }, /* ADL */
+       { PCI_VDEVICE(INTEL, 0x490e) }, /* DG1 */
+       { PCI_VDEVICE(INTEL, 0x9a0d) }, /* TGL */
+       { }
+};
+
+bool intel_pmt_is_early_client_hw(struct device *dev)
+{
+       struct pci_dev *parent = to_pci_dev(dev->parent);
+
+       return !!pci_match_id(pmt_telem_early_client_pci_ids, parent);
+}
+EXPORT_SYMBOL_GPL(intel_pmt_is_early_client_hw);
+
 /*
  * sysfs
  */
@@ -147,6 +169,30 @@ static int intel_pmt_populate_entry(struct intel_pmt_entry *entry,
                 * base address = end of discovery region + base offset
                 */
                entry->base_addr = disc_res->end + 1 + header->base_offset;
+
+               /*
+                * Some hardware use a different calculation for the base address
+                * when access_type == ACCESS_LOCAL. On the these systems
+                * ACCCESS_LOCAL refers to an address in the same BAR as the
+                * header but at a fixed offset. But as the header address was
+                * supplied to the driver, we don't know which BAR it was in.
+                * So search for the bar whose range includes the header address.
+                */
+               if (intel_pmt_is_early_client_hw(dev)) {
+                       int i;
+
+                       entry->base_addr = 0;
+                       for (i = 0; i < 6; i++)
+                               if (disc_res->start >= pci_resource_start(pci_dev, i) &&
+                                  (disc_res->start <= pci_resource_end(pci_dev, i))) {
+                                       entry->base_addr = pci_resource_start(pci_dev, i) +
+                                                          header->base_offset;
+                                       break;
+                               }
+                       if (!entry->base_addr)
+                               return -EINVAL;
+               }
+
                break;
        case ACCESS_BARID:
                /*
index de8f813..1337019 100644 (file)
@@ -44,6 +44,7 @@ struct intel_pmt_namespace {
                                 struct device *dev);
 };
 
+bool intel_pmt_is_early_client_hw(struct device *dev);
 int intel_pmt_dev_create(struct intel_pmt_entry *entry,
                         struct intel_pmt_namespace *ns,
                         struct platform_device *pdev, int idx);
index f8a8761..9b95ef0 100644 (file)
@@ -34,26 +34,6 @@ struct pmt_telem_priv {
        struct intel_pmt_entry          entry[];
 };
 
-/*
- * Early implementations of PMT on client platforms have some
- * differences from the server platforms (which use the Out Of Band
- * Management Services Module OOBMSM). This list tracks those
- * platforms as needed to handle those differences. Newer client
- * platforms are expected to be fully compatible with server.
- */
-static const struct pci_device_id pmt_telem_early_client_pci_ids[] = {
-       { PCI_VDEVICE(INTEL, 0x9a0d) }, /* TGL */
-       { PCI_VDEVICE(INTEL, 0x467d) }, /* ADL */
-       { }
-};
-
-static bool intel_pmt_is_early_client_hw(struct device *dev)
-{
-       struct pci_dev *parent = to_pci_dev(dev->parent);
-
-       return !!pci_match_id(pmt_telem_early_client_pci_ids, parent);
-}
-
 static bool pmt_telem_region_overlaps(struct intel_pmt_entry *entry,
                                      struct device *dev)
 {
index 006b95e..a910571 100644 (file)
@@ -698,7 +698,7 @@ config BATTERY_GAUGE_LTC2941
 
 config AB8500_BM
        bool "AB8500 Battery Management Driver"
-       depends on AB8500_CORE && AB8500_GPADC && (IIO = y)
+       depends on AB8500_CORE && AB8500_GPADC && (IIO = y) && OF
        help
          Say Y to include support for AB8500 battery management.
 
diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h
new file mode 100644 (file)
index 0000000..41c69a4
--- /dev/null
@@ -0,0 +1,733 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _AB8500_CHARGER_H_
+#define _AB8500_CHARGER_H_
+
+#include <linux/kernel.h>
+
+/*
+ * System control 2 register offsets.
+ * bank = 0x02
+ */
+#define AB8500_MAIN_WDOG_CTRL_REG      0x01
+#define AB8500_LOW_BAT_REG             0x03
+#define AB8500_BATT_OK_REG             0x04
+/*
+ * USB/ULPI register offsets
+ * Bank : 0x5
+ */
+#define AB8500_USB_LINE_STAT_REG       0x80
+#define AB8500_USB_LINE_CTRL2_REG      0x82
+#define AB8500_USB_LINK1_STAT_REG      0x94
+
+/*
+ * Charger / status register offfsets
+ * Bank : 0x0B
+ */
+#define AB8500_CH_STATUS1_REG          0x00
+#define AB8500_CH_STATUS2_REG          0x01
+#define AB8500_CH_USBCH_STAT1_REG      0x02
+#define AB8500_CH_USBCH_STAT2_REG      0x03
+#define AB8540_CH_USBCH_STAT3_REG      0x04
+#define AB8500_CH_STAT_REG             0x05
+
+/*
+ * Charger / control register offfsets
+ * Bank : 0x0B
+ */
+#define AB8500_CH_VOLT_LVL_REG         0x40
+#define AB8500_CH_VOLT_LVL_MAX_REG     0x41  /*Only in Cut2.0*/
+#define AB8500_CH_OPT_CRNTLVL_REG      0x42
+#define AB8500_CH_OPT_CRNTLVL_MAX_REG  0x43  /*Only in Cut2.0*/
+#define AB8500_CH_WD_TIMER_REG         0x50
+#define AB8500_CHARG_WD_CTRL           0x51
+#define AB8500_BTEMP_HIGH_TH           0x52
+#define AB8500_LED_INDICATOR_PWM_CTRL  0x53
+#define AB8500_LED_INDICATOR_PWM_DUTY  0x54
+#define AB8500_BATT_OVV                        0x55
+#define AB8500_CHARGER_CTRL            0x56
+#define AB8500_BAT_CTRL_CURRENT_SOURCE 0x60  /*Only in Cut2.0*/
+
+/*
+ * Charger / main control register offsets
+ * Bank : 0x0B
+ */
+#define AB8500_MCH_CTRL1               0x80
+#define AB8500_MCH_CTRL2               0x81
+#define AB8500_MCH_IPT_CURLVL_REG      0x82
+#define AB8500_CH_WD_REG               0x83
+
+/*
+ * Charger / USB control register offsets
+ * Bank : 0x0B
+ */
+#define AB8500_USBCH_CTRL1_REG         0xC0
+#define AB8500_USBCH_CTRL2_REG         0xC1
+#define AB8500_USBCH_IPT_CRNTLVL_REG   0xC2
+#define AB8540_USB_PP_MODE_REG         0xC5
+#define AB8540_USB_PP_CHR_REG          0xC6
+
+/*
+ * Gas Gauge register offsets
+ * Bank : 0x0C
+ */
+#define AB8500_GASG_CC_CTRL_REG                0x00
+#define AB8500_GASG_CC_ACCU1_REG       0x01
+#define AB8500_GASG_CC_ACCU2_REG       0x02
+#define AB8500_GASG_CC_ACCU3_REG       0x03
+#define AB8500_GASG_CC_ACCU4_REG       0x04
+#define AB8500_GASG_CC_SMPL_CNTRL_REG  0x05
+#define AB8500_GASG_CC_SMPL_CNTRH_REG  0x06
+#define AB8500_GASG_CC_SMPL_CNVL_REG   0x07
+#define AB8500_GASG_CC_SMPL_CNVH_REG   0x08
+#define AB8500_GASG_CC_CNTR_AVGOFF_REG 0x09
+#define AB8500_GASG_CC_OFFSET_REG      0x0A
+#define AB8500_GASG_CC_NCOV_ACCU       0x10
+#define AB8500_GASG_CC_NCOV_ACCU_CTRL  0x11
+#define AB8500_GASG_CC_NCOV_ACCU_LOW   0x12
+#define AB8500_GASG_CC_NCOV_ACCU_MED   0x13
+#define AB8500_GASG_CC_NCOV_ACCU_HIGH  0x14
+
+/*
+ * Interrupt register offsets
+ * Bank : 0x0E
+ */
+#define AB8500_IT_SOURCE2_REG          0x01
+#define AB8500_IT_SOURCE21_REG         0x14
+
+/*
+ * RTC register offsets
+ * Bank: 0x0F
+ */
+#define AB8500_RTC_BACKUP_CHG_REG      0x0C
+#define AB8500_RTC_CC_CONF_REG         0x01
+#define AB8500_RTC_CTRL_REG            0x0B
+#define AB8500_RTC_CTRL1_REG           0x11
+
+/*
+ * OTP register offsets
+ * Bank : 0x15
+ */
+#define AB8500_OTP_CONF_15             0x0E
+
+/* GPADC constants from AB8500 spec, UM0836 */
+#define ADC_RESOLUTION                 1024
+#define ADC_CH_MAIN_MIN                        0
+#define ADC_CH_MAIN_MAX                        20030
+#define ADC_CH_VBUS_MIN                        0
+#define ADC_CH_VBUS_MAX                        20030
+#define ADC_CH_VBAT_MIN                        2300
+#define ADC_CH_VBAT_MAX                        4800
+#define ADC_CH_BKBAT_MIN               0
+#define ADC_CH_BKBAT_MAX               3200
+
+/* Main charge i/p current */
+#define MAIN_CH_IP_CUR_0P9A            0x80
+#define MAIN_CH_IP_CUR_1P0A            0x90
+#define MAIN_CH_IP_CUR_1P1A            0xA0
+#define MAIN_CH_IP_CUR_1P2A            0xB0
+#define MAIN_CH_IP_CUR_1P3A            0xC0
+#define MAIN_CH_IP_CUR_1P4A            0xD0
+#define MAIN_CH_IP_CUR_1P5A            0xE0
+
+/* ChVoltLevel */
+#define CH_VOL_LVL_3P5                 0x00
+#define CH_VOL_LVL_4P0                 0x14
+#define CH_VOL_LVL_4P05                        0x16
+#define CH_VOL_LVL_4P1                 0x1B
+#define CH_VOL_LVL_4P15                        0x20
+#define CH_VOL_LVL_4P2                 0x25
+#define CH_VOL_LVL_4P6                 0x4D
+
+/* ChOutputCurrentLevel */
+#define CH_OP_CUR_LVL_0P1              0x00
+#define CH_OP_CUR_LVL_0P2              0x01
+#define CH_OP_CUR_LVL_0P3              0x02
+#define CH_OP_CUR_LVL_0P4              0x03
+#define CH_OP_CUR_LVL_0P5              0x04
+#define CH_OP_CUR_LVL_0P6              0x05
+#define CH_OP_CUR_LVL_0P7              0x06
+#define CH_OP_CUR_LVL_0P8              0x07
+#define CH_OP_CUR_LVL_0P9              0x08
+#define CH_OP_CUR_LVL_1P4              0x0D
+#define CH_OP_CUR_LVL_1P5              0x0E
+#define CH_OP_CUR_LVL_1P6              0x0F
+#define CH_OP_CUR_LVL_2P               0x3F
+
+/* BTEMP High thermal limits */
+#define BTEMP_HIGH_TH_57_0             0x00
+#define BTEMP_HIGH_TH_52               0x01
+#define BTEMP_HIGH_TH_57_1             0x02
+#define BTEMP_HIGH_TH_62               0x03
+
+/* current is mA */
+#define USB_0P1A                       100
+#define USB_0P2A                       200
+#define USB_0P3A                       300
+#define USB_0P4A                       400
+#define USB_0P5A                       500
+
+#define LOW_BAT_3P1V                   0x20
+#define LOW_BAT_2P3V                   0x00
+#define LOW_BAT_RESET                  0x01
+#define LOW_BAT_ENABLE                 0x01
+
+/* Backup battery constants */
+#define BUP_ICH_SEL_50UA               0x00
+#define BUP_ICH_SEL_150UA              0x04
+#define BUP_ICH_SEL_300UA              0x08
+#define BUP_ICH_SEL_700UA              0x0C
+
+enum bup_vch_sel {
+       BUP_VCH_SEL_2P5V,
+       BUP_VCH_SEL_2P6V,
+       BUP_VCH_SEL_2P8V,
+       BUP_VCH_SEL_3P1V,
+       /*
+        * Note that the following 5 values 2.7v, 2.9v, 3.0v, 3.2v, 3.3v
+        * are only available on ab8540. You can't choose these 5
+        * voltage on ab8500/ab8505/ab9540.
+        */
+       BUP_VCH_SEL_2P7V,
+       BUP_VCH_SEL_2P9V,
+       BUP_VCH_SEL_3P0V,
+       BUP_VCH_SEL_3P2V,
+       BUP_VCH_SEL_3P3V,
+};
+
+#define BUP_VCH_RANGE          0x02
+#define VBUP33_VRTCN           0x01
+
+/* Battery OVV constants */
+#define BATT_OVV_ENA                   0x02
+#define BATT_OVV_TH_3P7                        0x00
+#define BATT_OVV_TH_4P75               0x01
+
+/* A value to indicate over voltage */
+#define BATT_OVV_VALUE                 4750
+
+/* VBUS OVV constants */
+#define VBUS_OVV_SELECT_MASK           0x78
+#define VBUS_OVV_SELECT_5P6V           0x00
+#define VBUS_OVV_SELECT_5P7V           0x08
+#define VBUS_OVV_SELECT_5P8V           0x10
+#define VBUS_OVV_SELECT_5P9V           0x18
+#define VBUS_OVV_SELECT_6P0V           0x20
+#define VBUS_OVV_SELECT_6P1V           0x28
+#define VBUS_OVV_SELECT_6P2V           0x30
+#define VBUS_OVV_SELECT_6P3V           0x38
+
+#define VBUS_AUTO_IN_CURR_LIM_ENA      0x04
+
+/* Fuel Gauge constants */
+#define RESET_ACCU                     0x02
+#define READ_REQ                       0x01
+#define CC_DEEP_SLEEP_ENA              0x02
+#define CC_PWR_UP_ENA                  0x01
+#define CC_SAMPLES_40                  0x28
+#define RD_NCONV_ACCU_REQ              0x01
+#define CC_CALIB                       0x08
+#define CC_INTAVGOFFSET_ENA            0x10
+#define CC_MUXOFFSET                   0x80
+#define CC_INT_CAL_N_AVG_MASK          0x60
+#define CC_INT_CAL_SAMPLES_16          0x40
+#define CC_INT_CAL_SAMPLES_8           0x20
+#define CC_INT_CAL_SAMPLES_4           0x00
+
+/* RTC constants */
+#define RTC_BUP_CH_ENA                 0x10
+
+/* BatCtrl Current Source Constants */
+#define BAT_CTRL_7U_ENA                        0x01
+#define BAT_CTRL_20U_ENA               0x02
+#define BAT_CTRL_18U_ENA               0x01
+#define BAT_CTRL_16U_ENA               0x02
+#define BAT_CTRL_CMP_ENA               0x04
+#define FORCE_BAT_CTRL_CMP_HIGH                0x08
+#define BAT_CTRL_PULL_UP_ENA           0x10
+
+/* Battery type */
+#define BATTERY_UNKNOWN                        00
+
+/* Registers for pcut feature in ab8505 and ab9540 */
+#define AB8505_RTC_PCUT_CTL_STATUS_REG 0x12
+#define AB8505_RTC_PCUT_TIME_REG       0x13
+#define AB8505_RTC_PCUT_MAX_TIME_REG   0x14
+#define AB8505_RTC_PCUT_FLAG_TIME_REG  0x15
+#define AB8505_RTC_PCUT_RESTART_REG    0x16
+#define AB8505_RTC_PCUT_DEBOUNCE_REG   0x17
+
+/* USB Power Path constants for ab8540 */
+#define BUS_VSYS_VOL_SELECT_MASK               0x06
+#define BUS_VSYS_VOL_SELECT_3P6V               0x00
+#define BUS_VSYS_VOL_SELECT_3P325V             0x02
+#define BUS_VSYS_VOL_SELECT_3P9V               0x04
+#define BUS_VSYS_VOL_SELECT_4P3V               0x06
+#define BUS_POWER_PATH_MODE_ENA                        0x01
+#define BUS_PP_PRECHG_CURRENT_MASK             0x0E
+#define BUS_POWER_PATH_PRECHG_ENA              0x01
+
+/*
+ * ADC for the battery thermistor.
+ * When using the ABx500_ADC_THERM_BATCTRL the battery ID resistor is combined
+ * with a NTC resistor to both identify the battery and to measure its
+ * temperature. Different phone manufactures uses different techniques to both
+ * identify the battery and to read its temperature.
+ */
+enum abx500_adc_therm {
+       ABx500_ADC_THERM_BATCTRL,
+       ABx500_ADC_THERM_BATTEMP,
+};
+
+/**
+ * struct abx500_res_to_temp - defines one point in a temp to res curve. To
+ * be used in battery packs that combines the identification resistor with a
+ * NTC resistor.
+ * @temp:                      battery pack temperature in Celsius
+ * @resist:                    NTC resistor net total resistance
+ */
+struct abx500_res_to_temp {
+       int temp;
+       int resist;
+};
+
+/**
+ * struct abx500_v_to_cap - Table for translating voltage to capacity
+ * @voltage:           Voltage in mV
+ * @capacity:          Capacity in percent
+ */
+struct abx500_v_to_cap {
+       int voltage;
+       int capacity;
+};
+
+/* Forward declaration */
+struct abx500_fg;
+
+/**
+ * struct abx500_fg_parameters - Fuel gauge algorithm parameters, in seconds
+ * if not specified
+ * @recovery_sleep_timer:      Time between measurements while recovering
+ * @recovery_total_time:       Total recovery time
+ * @init_timer:                        Measurement interval during startup
+ * @init_discard_time:         Time we discard voltage measurement at startup
+ * @init_total_time:           Total init time during startup
+ * @high_curr_time:            Time current has to be high to go to recovery
+ * @accu_charging:             FG accumulation time while charging
+ * @accu_high_curr:            FG accumulation time in high current mode
+ * @high_curr_threshold:       High current threshold, in mA
+ * @lowbat_threshold:          Low battery threshold, in mV
+ * @overbat_threshold:         Over battery threshold, in mV
+ * @battok_falling_th_sel0     Threshold in mV for battOk signal sel0
+ *                             Resolution in 50 mV step.
+ * @battok_raising_th_sel1     Threshold in mV for battOk signal sel1
+ *                             Resolution in 50 mV step.
+ * @user_cap_limit             Capacity reported from user must be within this
+ *                             limit to be considered as sane, in percentage
+ *                             points.
+ * @maint_thres                        This is the threshold where we stop reporting
+ *                             battery full while in maintenance, in per cent
+ * @pcut_enable:                       Enable power cut feature in ab8505
+ * @pcut_max_time:             Max time threshold
+ * @pcut_flag_time:            Flagtime threshold
+ * @pcut_max_restart:          Max number of restarts
+ * @pcut_debounce_time:                Sets battery debounce time
+ */
+struct abx500_fg_parameters {
+       int recovery_sleep_timer;
+       int recovery_total_time;
+       int init_timer;
+       int init_discard_time;
+       int init_total_time;
+       int high_curr_time;
+       int accu_charging;
+       int accu_high_curr;
+       int high_curr_threshold;
+       int lowbat_threshold;
+       int overbat_threshold;
+       int battok_falling_th_sel0;
+       int battok_raising_th_sel1;
+       int user_cap_limit;
+       int maint_thres;
+       bool pcut_enable;
+       u8 pcut_max_time;
+       u8 pcut_flag_time;
+       u8 pcut_max_restart;
+       u8 pcut_debounce_time;
+};
+
+/**
+ * struct abx500_charger_maximization - struct used by the board config.
+ * @use_maxi:          Enable maximization for this battery type
+ * @maxi_chg_curr:     Maximum charger current allowed
+ * @maxi_wait_cycles:  cycles to wait before setting charger current
+ * @charger_curr_step  delta between two charger current settings (mA)
+ */
+struct abx500_maxim_parameters {
+       bool ena_maxi;
+       int chg_curr;
+       int wait_cycles;
+       int charger_curr_step;
+};
+
+/**
+ * struct abx500_battery_type - different batteries supported
+ * @name:                      battery technology
+ * @resis_high:                        battery upper resistance limit
+ * @resis_low:                 battery lower resistance limit
+ * @charge_full_design:                Maximum battery capacity in mAh
+ * @nominal_voltage:           Nominal voltage of the battery in mV
+ * @termination_vol:           max voltage upto which battery can be charged
+ * @termination_curr           battery charging termination current in mA
+ * @recharge_cap               battery capacity limit that will trigger a new
+ *                             full charging cycle in the case where maintenan-
+ *                             -ce charging has been disabled
+ * @normal_cur_lvl:            charger current in normal state in mA
+ * @normal_vol_lvl:            charger voltage in normal state in mV
+ * @maint_a_cur_lvl:           charger current in maintenance A state in mA
+ * @maint_a_vol_lvl:           charger voltage in maintenance A state in mV
+ * @maint_a_chg_timer_h:       charge time in maintenance A state
+ * @maint_b_cur_lvl:           charger current in maintenance B state in mA
+ * @maint_b_vol_lvl:           charger voltage in maintenance B state in mV
+ * @maint_b_chg_timer_h:       charge time in maintenance B state
+ * @low_high_cur_lvl:          charger current in temp low/high state in mA
+ * @low_high_vol_lvl:          charger voltage in temp low/high state in mV'
+ * @battery_resistance:                battery inner resistance in mOhm.
+ * @n_r_t_tbl_elements:                number of elements in r_to_t_tbl
+ * @r_to_t_tbl:                        table containing resistance to temp points
+ * @n_v_cap_tbl_elements:      number of elements in v_to_cap_tbl
+ * @v_to_cap_tbl:              Voltage to capacity (in %) table
+ * @n_batres_tbl_elements      number of elements in the batres_tbl
+ * @batres_tbl                 battery internal resistance vs temperature table
+ */
+struct abx500_battery_type {
+       int name;
+       int resis_high;
+       int resis_low;
+       int charge_full_design;
+       int nominal_voltage;
+       int termination_vol;
+       int termination_curr;
+       int recharge_cap;
+       int normal_cur_lvl;
+       int normal_vol_lvl;
+       int maint_a_cur_lvl;
+       int maint_a_vol_lvl;
+       int maint_a_chg_timer_h;
+       int maint_b_cur_lvl;
+       int maint_b_vol_lvl;
+       int maint_b_chg_timer_h;
+       int low_high_cur_lvl;
+       int low_high_vol_lvl;
+       int battery_resistance;
+       int n_temp_tbl_elements;
+       const struct abx500_res_to_temp *r_to_t_tbl;
+       int n_v_cap_tbl_elements;
+       const struct abx500_v_to_cap *v_to_cap_tbl;
+       int n_batres_tbl_elements;
+       const struct batres_vs_temp *batres_tbl;
+};
+
+/**
+ * struct abx500_bm_capacity_levels - abx500 capacity level data
+ * @critical:          critical capacity level in percent
+ * @low:               low capacity level in percent
+ * @normal:            normal capacity level in percent
+ * @high:              high capacity level in percent
+ * @full:              full capacity level in percent
+ */
+struct abx500_bm_capacity_levels {
+       int critical;
+       int low;
+       int normal;
+       int high;
+       int full;
+};
+
+/**
+ * struct abx500_bm_charger_parameters - Charger specific parameters
+ * @usb_volt_max:      maximum allowed USB charger voltage in mV
+ * @usb_curr_max:      maximum allowed USB charger current in mA
+ * @ac_volt_max:       maximum allowed AC charger voltage in mV
+ * @ac_curr_max:       maximum allowed AC charger current in mA
+ */
+struct abx500_bm_charger_parameters {
+       int usb_volt_max;
+       int usb_curr_max;
+       int ac_volt_max;
+       int ac_curr_max;
+};
+
+/**
+ * struct abx500_bm_data - abx500 battery management data
+ * @temp_under         under this temp, charging is stopped
+ * @temp_low           between this temp and temp_under charging is reduced
+ * @temp_high          between this temp and temp_over charging is reduced
+ * @temp_over          over this temp, charging is stopped
+ * @temp_now           present battery temperature
+ * @temp_interval_chg  temperature measurement interval in s when charging
+ * @temp_interval_nochg        temperature measurement interval in s when not charging
+ * @main_safety_tmr_h  safety timer for main charger
+ * @usb_safety_tmr_h   safety timer for usb charger
+ * @bkup_bat_v         voltage which we charge the backup battery with
+ * @bkup_bat_i         current which we charge the backup battery with
+ * @no_maintenance     indicates that maintenance charging is disabled
+ * @capacity_scaling    indicates whether capacity scaling is to be used
+ * @abx500_adc_therm   placement of thermistor, batctrl or battemp adc
+ * @chg_unknown_bat    flag to enable charging of unknown batteries
+ * @enable_overshoot   flag to enable VBAT overshoot control
+ * @auto_trig          flag to enable auto adc trigger
+ * @fg_res             resistance of FG resistor in 0.1mOhm
+ * @n_btypes           number of elements in array bat_type
+ * @batt_id            index of the identified battery in array bat_type
+ * @interval_charging  charge alg cycle period time when charging (sec)
+ * @interval_not_charging charge alg cycle period time when not charging (sec)
+ * @temp_hysteresis    temperature hysteresis
+ * @gnd_lift_resistance        Battery ground to phone ground resistance (mOhm)
+ * @n_chg_out_curr             number of elements in array chg_output_curr
+ * @n_chg_in_curr              number of elements in array chg_input_curr
+ * @chg_output_curr    charger output current level map
+ * @chg_input_curr             charger input current level map
+ * @maxi               maximization parameters
+ * @cap_levels         capacity in percent for the different capacity levels
+ * @bat_type           table of supported battery types
+ * @chg_params         charger parameters
+ * @fg_params          fuel gauge parameters
+ */
+struct abx500_bm_data {
+       int temp_under;
+       int temp_low;
+       int temp_high;
+       int temp_over;
+       int temp_now;
+       int temp_interval_chg;
+       int temp_interval_nochg;
+       int main_safety_tmr_h;
+       int usb_safety_tmr_h;
+       int bkup_bat_v;
+       int bkup_bat_i;
+       bool autopower_cfg;
+       bool ac_enabled;
+       bool usb_enabled;
+       bool no_maintenance;
+       bool capacity_scaling;
+       bool chg_unknown_bat;
+       bool enable_overshoot;
+       bool auto_trig;
+       enum abx500_adc_therm adc_therm;
+       int fg_res;
+       int n_btypes;
+       int batt_id;
+       int interval_charging;
+       int interval_not_charging;
+       int temp_hysteresis;
+       int gnd_lift_resistance;
+       int n_chg_out_curr;
+       int n_chg_in_curr;
+       int *chg_output_curr;
+       int *chg_input_curr;
+       const struct abx500_maxim_parameters *maxi;
+       const struct abx500_bm_capacity_levels *cap_levels;
+       struct abx500_battery_type *bat_type;
+       const struct abx500_bm_charger_parameters *chg_params;
+       const struct abx500_fg_parameters *fg_params;
+};
+
+enum {
+       NTC_EXTERNAL = 0,
+       NTC_INTERNAL,
+};
+
+/**
+ * struct res_to_temp - defines one point in a temp to res curve. To
+ * be used in battery packs that combines the identification resistor with a
+ * NTC resistor.
+ * @temp:                      battery pack temperature in Celsius
+ * @resist:                    NTC resistor net total resistance
+ */
+struct res_to_temp {
+       int temp;
+       int resist;
+};
+
+/**
+ * struct batres_vs_temp - defines one point in a temp vs battery internal
+ * resistance curve.
+ * @temp:                      battery pack temperature in Celsius
+ * @resist:                    battery internal reistance in mOhm
+ */
+struct batres_vs_temp {
+       int temp;
+       int resist;
+};
+
+/* Forward declaration */
+struct ab8500_fg;
+
+/**
+ * struct ab8500_fg_parameters - Fuel gauge algorithm parameters, in seconds
+ * if not specified
+ * @recovery_sleep_timer:      Time between measurements while recovering
+ * @recovery_total_time:       Total recovery time
+ * @init_timer:                        Measurement interval during startup
+ * @init_discard_time:         Time we discard voltage measurement at startup
+ * @init_total_time:           Total init time during startup
+ * @high_curr_time:            Time current has to be high to go to recovery
+ * @accu_charging:             FG accumulation time while charging
+ * @accu_high_curr:            FG accumulation time in high current mode
+ * @high_curr_threshold:       High current threshold, in mA
+ * @lowbat_threshold:          Low battery threshold, in mV
+ * @battok_falling_th_sel0     Threshold in mV for battOk signal sel0
+ *                             Resolution in 50 mV step.
+ * @battok_raising_th_sel1     Threshold in mV for battOk signal sel1
+ *                             Resolution in 50 mV step.
+ * @user_cap_limit             Capacity reported from user must be within this
+ *                             limit to be considered as sane, in percentage
+ *                             points.
+ * @maint_thres                        This is the threshold where we stop reporting
+ *                             battery full while in maintenance, in per cent
+ * @pcut_enable:                       Enable power cut feature in ab8505
+ * @pcut_max_time:             Max time threshold
+ * @pcut_flag_time:            Flagtime threshold
+ * @pcut_max_restart:          Max number of restarts
+ * @pcut_debunce_time: Sets battery debounce time
+ */
+struct ab8500_fg_parameters {
+       int recovery_sleep_timer;
+       int recovery_total_time;
+       int init_timer;
+       int init_discard_time;
+       int init_total_time;
+       int high_curr_time;
+       int accu_charging;
+       int accu_high_curr;
+       int high_curr_threshold;
+       int lowbat_threshold;
+       int battok_falling_th_sel0;
+       int battok_raising_th_sel1;
+       int user_cap_limit;
+       int maint_thres;
+       bool pcut_enable;
+       u8 pcut_max_time;
+       u8 pcut_flag_time;
+       u8 pcut_max_restart;
+       u8 pcut_debunce_time;
+};
+
+/**
+ * struct ab8500_charger_maximization - struct used by the board config.
+ * @use_maxi:          Enable maximization for this battery type
+ * @maxi_chg_curr:     Maximum charger current allowed
+ * @maxi_wait_cycles:  cycles to wait before setting charger current
+ * @charger_curr_step  delta between two charger current settings (mA)
+ */
+struct ab8500_maxim_parameters {
+       bool ena_maxi;
+       int chg_curr;
+       int wait_cycles;
+       int charger_curr_step;
+};
+
+/**
+ * struct ab8500_bm_capacity_levels - ab8500 capacity level data
+ * @critical:          critical capacity level in percent
+ * @low:               low capacity level in percent
+ * @normal:            normal capacity level in percent
+ * @high:              high capacity level in percent
+ * @full:              full capacity level in percent
+ */
+struct ab8500_bm_capacity_levels {
+       int critical;
+       int low;
+       int normal;
+       int high;
+       int full;
+};
+
+/**
+ * struct ab8500_bm_charger_parameters - Charger specific parameters
+ * @usb_volt_max:      maximum allowed USB charger voltage in mV
+ * @usb_curr_max:      maximum allowed USB charger current in mA
+ * @ac_volt_max:       maximum allowed AC charger voltage in mV
+ * @ac_curr_max:       maximum allowed AC charger current in mA
+ */
+struct ab8500_bm_charger_parameters {
+       int usb_volt_max;
+       int usb_curr_max;
+       int ac_volt_max;
+       int ac_curr_max;
+};
+
+/**
+ * struct ab8500_bm_data - ab8500 battery management data
+ * @temp_under         under this temp, charging is stopped
+ * @temp_low           between this temp and temp_under charging is reduced
+ * @temp_high          between this temp and temp_over charging is reduced
+ * @temp_over          over this temp, charging is stopped
+ * @temp_interval_chg  temperature measurement interval in s when charging
+ * @temp_interval_nochg        temperature measurement interval in s when not charging
+ * @main_safety_tmr_h  safety timer for main charger
+ * @usb_safety_tmr_h   safety timer for usb charger
+ * @bkup_bat_v         voltage which we charge the backup battery with
+ * @bkup_bat_i         current which we charge the backup battery with
+ * @no_maintenance     indicates that maintenance charging is disabled
+ * @capacity_scaling    indicates whether capacity scaling is to be used
+ * @adc_therm          placement of thermistor, batctrl or battemp adc
+ * @chg_unknown_bat    flag to enable charging of unknown batteries
+ * @enable_overshoot   flag to enable VBAT overshoot control
+ * @fg_res             resistance of FG resistor in 0.1mOhm
+ * @n_btypes           number of elements in array bat_type
+ * @batt_id            index of the identified battery in array bat_type
+ * @interval_charging  charge alg cycle period time when charging (sec)
+ * @interval_not_charging charge alg cycle period time when not charging (sec)
+ * @temp_hysteresis    temperature hysteresis
+ * @gnd_lift_resistance        Battery ground to phone ground resistance (mOhm)
+ * @maxi:              maximization parameters
+ * @cap_levels         capacity in percent for the different capacity levels
+ * @bat_type           table of supported battery types
+ * @chg_params         charger parameters
+ * @fg_params          fuel gauge parameters
+ */
+struct ab8500_bm_data {
+       int temp_under;
+       int temp_low;
+       int temp_high;
+       int temp_over;
+       int temp_interval_chg;
+       int temp_interval_nochg;
+       int main_safety_tmr_h;
+       int usb_safety_tmr_h;
+       int bkup_bat_v;
+       int bkup_bat_i;
+       bool no_maintenance;
+       bool capacity_scaling;
+       bool chg_unknown_bat;
+       bool enable_overshoot;
+       enum abx500_adc_therm adc_therm;
+       int fg_res;
+       int n_btypes;
+       int batt_id;
+       int interval_charging;
+       int interval_not_charging;
+       int temp_hysteresis;
+       int gnd_lift_resistance;
+       const struct ab8500_maxim_parameters *maxi;
+       const struct ab8500_bm_capacity_levels *cap_levels;
+       const struct ab8500_bm_charger_parameters *chg_params;
+       const struct ab8500_fg_parameters *fg_params;
+};
+
+extern struct abx500_bm_data ab8500_bm_data;
+
+void ab8500_charger_usb_state_changed(u8 bm_usb_state, u16 mA);
+struct ab8500_fg *ab8500_fg_get(void);
+int ab8500_fg_inst_curr_blocking(struct ab8500_fg *dev);
+int ab8500_fg_inst_curr_start(struct ab8500_fg *di);
+int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res);
+int ab8500_fg_inst_curr_started(struct ab8500_fg *di);
+int ab8500_fg_inst_curr_done(struct ab8500_fg *di);
+int ab8500_bm_of_probe(struct device *dev,
+                      struct device_node *np,
+                      struct abx500_bm_data *bm);
+
+#endif /* _AB8500_CHARGER_H_ */
diff --git a/drivers/power/supply/ab8500-chargalg.h b/drivers/power/supply/ab8500-chargalg.h
new file mode 100644 (file)
index 0000000..94a6f90
--- /dev/null
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ * Author: Johan Gardsmark <johan.gardsmark@stericsson.com> for ST-Ericsson.
+ */
+
+#ifndef _AB8500_CHARGALG_H_
+#define _AB8500_CHARGALG_H_
+
+#include <linux/power_supply.h>
+
+/*
+ * Valid only for supplies of type:
+ * - POWER_SUPPLY_TYPE_MAINS,
+ * - POWER_SUPPLY_TYPE_USB,
+ * because only them store as drv_data pointer to struct ux500_charger.
+ */
+#define psy_to_ux500_charger(x) power_supply_get_drvdata(psy)
+
+/* Forward declaration */
+struct ux500_charger;
+
+struct ux500_charger_ops {
+       int (*enable) (struct ux500_charger *, int, int, int);
+       int (*check_enable) (struct ux500_charger *, int, int);
+       int (*kick_wd) (struct ux500_charger *);
+       int (*update_curr) (struct ux500_charger *, int);
+};
+
+/**
+ * struct ux500_charger - power supply ux500 charger sub class
+ * @psy                        power supply base class
+ * @ops                        ux500 charger operations
+ * @max_out_volt       maximum output charger voltage in mV
+ * @max_out_curr       maximum output charger current in mA
+ * @enabled            indicates if this charger is used or not
+ * @external           external charger unit (pm2xxx)
+ */
+struct ux500_charger {
+       struct power_supply *psy;
+       struct ux500_charger_ops ops;
+       int max_out_volt;
+       int max_out_curr;
+       int wdt_refresh;
+       bool enabled;
+       bool external;
+};
+
+extern struct blocking_notifier_head charger_notifier_list;
+
+#endif /* _AB8500_CHARGALG_H_ */
index f6a6697..c2b8c0b 100644 (file)
@@ -4,7 +4,8 @@
 #include <linux/of.h>
 #include <linux/mfd/abx500.h>
 #include <linux/mfd/abx500/ab8500.h>
-#include <linux/mfd/abx500/ab8500-bm.h>
+
+#include "ab8500-bm.h"
 
 /*
  * These are the defined batteries that uses a NTC and ID resistor placed
index d203453..fdfcd59 100644 (file)
 #include <linux/mfd/core.h>
 #include <linux/mfd/abx500.h>
 #include <linux/mfd/abx500/ab8500.h>
-#include <linux/mfd/abx500/ab8500-bm.h>
 #include <linux/iio/consumer.h>
 
+#include "ab8500-bm.h"
+
 #define VTVOUT_V                       1800
 
 #define BTEMP_THERMAL_LOW_LIMIT                -10
@@ -119,16 +120,6 @@ static enum power_supply_property ab8500_btemp_props[] = {
 
 static LIST_HEAD(ab8500_btemp_list);
 
-/**
- * ab8500_btemp_get() - returns a reference to the primary AB8500 BTEMP
- * (i.e. the first BTEMP in the instance list)
- */
-struct ab8500_btemp *ab8500_btemp_get(void)
-{
-       return list_first_entry(&ab8500_btemp_list, struct ab8500_btemp, node);
-}
-EXPORT_SYMBOL(ab8500_btemp_get);
-
 /**
  * ab8500_btemp_batctrl_volt_to_res() - convert batctrl voltage to resistance
  * @di:                pointer to the ab8500_btemp structure
@@ -754,7 +745,7 @@ static void ab8500_btemp_periodic(struct ab8500_btemp *di,
  *
  * Returns battery temperature
  */
-int ab8500_btemp_get_temp(struct ab8500_btemp *di)
+static int ab8500_btemp_get_temp(struct ab8500_btemp *di)
 {
        int temp = 0;
 
@@ -790,19 +781,6 @@ int ab8500_btemp_get_temp(struct ab8500_btemp *di)
        }
        return temp;
 }
-EXPORT_SYMBOL(ab8500_btemp_get_temp);
-
-/**
- * ab8500_btemp_get_batctrl_temp() - get the temperature
- * @btemp:      pointer to the btemp structure
- *
- * Returns the batctrl temperature in millidegrees
- */
-int ab8500_btemp_get_batctrl_temp(struct ab8500_btemp *btemp)
-{
-       return btemp->bat_temp * 1000;
-}
-EXPORT_SYMBOL(ab8500_btemp_get_batctrl_temp);
 
 /**
  * ab8500_btemp_get_property() - get the btemp properties
@@ -991,7 +969,6 @@ static const struct power_supply_desc ab8500_btemp_desc = {
 static int ab8500_btemp_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
-       struct abx500_bm_data *plat = pdev->dev.platform_data;
        struct power_supply_config psy_cfg = {};
        struct device *dev = &pdev->dev;
        struct ab8500_btemp *di;
@@ -1002,18 +979,12 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
        if (!di)
                return -ENOMEM;
 
-       if (!plat) {
-               dev_err(dev, "no battery management data supplied\n");
-               return -EINVAL;
-       }
-       di->bm = plat;
+       di->bm = &ab8500_bm_data;
 
-       if (np) {
-               ret = ab8500_bm_of_probe(dev, np, di->bm);
-               if (ret) {
-                       dev_err(dev, "failed to get battery information\n");
-                       return ret;
-               }
+       ret = ab8500_bm_of_probe(dev, np, di->bm);
+       if (ret) {
+               dev_err(dev, "failed to get battery information\n");
+               return ret;
        }
 
        /* get parent data */
index ac77c88..a9be10e 100644 (file)
 #include <linux/mfd/core.h>
 #include <linux/mfd/abx500/ab8500.h>
 #include <linux/mfd/abx500.h>
-#include <linux/mfd/abx500/ab8500-bm.h>
-#include <linux/mfd/abx500/ux500_chargalg.h>
 #include <linux/usb/otg.h>
 #include <linux/mutex.h>
 #include <linux/iio/consumer.h>
 
+#include "ab8500-bm.h"
+#include "ab8500-chargalg.h"
+
 /* Charger constants */
 #define NO_PW_CONN                     0
 #define AC_PW_CONN                     1
@@ -3344,7 +3345,6 @@ static const struct power_supply_desc ab8500_usb_chg_desc = {
 static int ab8500_charger_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
-       struct abx500_bm_data *plat = pdev->dev.platform_data;
        struct power_supply_config ac_psy_cfg = {}, usb_psy_cfg = {};
        struct ab8500_charger *di;
        int irq, i, charger_status, ret = 0, ch_stat;
@@ -3354,21 +3354,14 @@ static int ab8500_charger_probe(struct platform_device *pdev)
        if (!di)
                return -ENOMEM;
 
-       if (!plat) {
-               dev_err(dev, "no battery management data supplied\n");
-               return -EINVAL;
-       }
-       di->bm = plat;
+       di->bm = &ab8500_bm_data;
 
-       if (np) {
-               ret = ab8500_bm_of_probe(dev, np, di->bm);
-               if (ret) {
-                       dev_err(dev, "failed to get battery information\n");
-                       return ret;
-               }
-               di->autopower_cfg = of_property_read_bool(np, "autopower_cfg");
-       } else
-               di->autopower_cfg = false;
+       ret = ab8500_bm_of_probe(dev, np, di->bm);
+       if (ret) {
+               dev_err(dev, "failed to get battery information\n");
+               return ret;
+       }
+       di->autopower_cfg = of_property_read_bool(np, "autopower_cfg");
 
        /* get parent data */
        di->dev = dev;
index 06ff42c..0c7c01a 100644 (file)
 #include <linux/mfd/core.h>
 #include <linux/mfd/abx500.h>
 #include <linux/mfd/abx500/ab8500.h>
-#include <linux/mfd/abx500/ab8500-bm.h>
 #include <linux/iio/consumer.h>
 #include <linux/kernel.h>
 
+#include "ab8500-bm.h"
+
 #define MILLI_TO_MICRO                 1000
 #define FG_LSB_IN_MA                   1627
 #define QLSB_NANO_AMP_HOURS_X10                1071
@@ -3026,7 +3027,6 @@ static const struct power_supply_desc ab8500_fg_desc = {
 static int ab8500_fg_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
-       struct abx500_bm_data *plat = pdev->dev.platform_data;
        struct power_supply_config psy_cfg = {};
        struct device *dev = &pdev->dev;
        struct ab8500_fg *di;
@@ -3037,18 +3037,12 @@ static int ab8500_fg_probe(struct platform_device *pdev)
        if (!di)
                return -ENOMEM;
 
-       if (!plat) {
-               dev_err(dev, "no battery management data supplied\n");
-               return -EINVAL;
-       }
-       di->bm = plat;
+       di->bm = &ab8500_bm_data;
 
-       if (np) {
-               ret = ab8500_bm_of_probe(dev, np, di->bm);
-               if (ret) {
-                       dev_err(dev, "failed to get battery information\n");
-                       return ret;
-               }
+       ret = ab8500_bm_of_probe(dev, np, di->bm);
+       if (ret) {
+               dev_err(dev, "failed to get battery information\n");
+               return ret;
        }
 
        mutex_init(&di->cc_lock);
index a9d84d8..f5b7922 100644 (file)
 #include <linux/mfd/core.h>
 #include <linux/mfd/abx500.h>
 #include <linux/mfd/abx500/ab8500.h>
-#include <linux/mfd/abx500/ux500_chargalg.h>
-#include <linux/mfd/abx500/ab8500-bm.h>
 #include <linux/notifier.h>
 
+#include "ab8500-bm.h"
+#include "ab8500-chargalg.h"
+
 /* Watchdog kick interval */
 #define CHG_WD_INTERVAL                        (6 * HZ)
 
@@ -1980,7 +1981,6 @@ static const struct power_supply_desc abx500_chargalg_desc = {
 static int abx500_chargalg_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
-       struct abx500_bm_data *plat = pdev->dev.platform_data;
        struct power_supply_config psy_cfg = {};
        struct abx500_chargalg *di;
        int ret = 0;
@@ -1991,18 +1991,12 @@ static int abx500_chargalg_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
-       if (!plat) {
-               dev_err(&pdev->dev, "no battery management data supplied\n");
-               return -EINVAL;
-       }
-       di->bm = plat;
+       di->bm = &ab8500_bm_data;
 
-       if (np) {
-               ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm);
-               if (ret) {
-                       dev_err(&pdev->dev, "failed to get battery information\n");
-                       return ret;
-               }
+       ret = ab8500_bm_of_probe(&pdev->dev, np, di->bm);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to get battery information\n");
+               return ret;
        }
 
        /* get device struct and parent */
index ac06ecf..d53e0c3 100644 (file)
 #include <linux/i2c.h>
 #include <linux/workqueue.h>
 #include <linux/mfd/abx500/ab8500.h>
-#include <linux/mfd/abx500/ab8500-bm.h>
-#include <linux/mfd/abx500/ux500_chargalg.h>
 #include <linux/pm2301_charger.h>
 #include <linux/gpio.h>
 #include <linux/pm_runtime.h>
 #include <linux/pm.h>
 
+#include "ab8500-bm.h"
+#include "ab8500-chargalg.h"
 #include "pm2301_charger.h"
 
 #define to_pm2xxx_charger_ac_device_info(x) container_of((x), \
index 77c4313..6437348 100644 (file)
@@ -204,6 +204,17 @@ config REGULATOR_BD70528
          This driver can also be built as a module. If so, the module
          will be called bd70528-regulator.
 
+config REGULATOR_BD71815
+       tristate "ROHM BD71815 Power Regulator"
+       depends on MFD_ROHM_BD71828
+       help
+         This driver supports voltage regulators on ROHM BD71815 PMIC.
+         This will enable support for the software controllable buck
+         and LDO regulators and a current regulator for LEDs.
+
+         This driver can also be built as a module. If so, the module
+         will be called bd71815-regulator.
+
 config REGULATOR_BD71828
        tristate "ROHM BD71828 Power Regulator"
        depends on MFD_ROHM_BD71828
index 44d2f8b..c6f84a3 100644 (file)
@@ -30,6 +30,7 @@ obj-$(CONFIG_REGULATOR_ATC260X) += atc260x-regulator.o
 obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o
 obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o
 obj-$(CONFIG_REGULATOR_BD70528) += bd70528-regulator.o
+obj-$(CONFIG_REGULATOR_BD71815)        += bd71815-regulator.o
 obj-$(CONFIG_REGULATOR_BD71828) += bd71828-regulator.o
 obj-$(CONFIG_REGULATOR_BD718XX) += bd718x7-regulator.o
 obj-$(CONFIG_REGULATOR_BD9571MWV) += bd9571mwv-regulator.o
diff --git a/drivers/regulator/bd71815-regulator.c b/drivers/regulator/bd71815-regulator.c
new file mode 100644 (file)
index 0000000..a4e8d5e
--- /dev/null
@@ -0,0 +1,652 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright 2014 Embest Technology Co. Ltd. Inc.
+// bd71815-regulator.c ROHM BD71815 regulator driver
+//
+// Author: Tony Luo <luofc@embedinfo.com>
+//
+// Partially rewritten at 2021 by
+// Matti Vaittinen <matti.vaitinen@fi.rohmeurope.com>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/mfd/rohm-generic.h>
+#include <linux/mfd/rohm-bd71815.h>
+#include <linux/regulator/of_regulator.h>
+
+struct bd71815_regulator {
+       struct regulator_desc desc;
+       const struct rohm_dvs_config *dvs;
+};
+
+struct bd71815_pmic {
+       struct bd71815_regulator descs[BD71815_REGULATOR_CNT];
+       struct regmap *regmap;
+       struct device *dev;
+       struct gpio_descs *gps;
+       struct regulator_dev *rdev[BD71815_REGULATOR_CNT];
+};
+
+static const int bd7181x_wled_currents[] = {
+       10, 20, 30, 50, 70, 100, 200, 300, 500, 700, 1000, 2000, 3000, 4000,
+       5000, 6000, 7000, 8000, 9000, 10000, 11000, 12000, 13000, 14000, 15000,
+       16000, 17000, 18000, 19000, 20000, 21000, 22000, 23000, 24000, 25000,
+};
+
+static const struct rohm_dvs_config buck1_dvs = {
+       .level_map              = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
+                                 ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
+       .run_reg                = BD71815_REG_BUCK1_VOLT_H,
+       .run_mask               = BD71815_VOLT_MASK,
+       .run_on_mask            = BD71815_BUCK_RUN_ON,
+       .snvs_on_mask           = BD71815_BUCK_SNVS_ON,
+       .suspend_reg            = BD71815_REG_BUCK1_VOLT_L,
+       .suspend_mask           = BD71815_VOLT_MASK,
+       .suspend_on_mask        = BD71815_BUCK_SUSP_ON,
+       .lpsr_reg               = BD71815_REG_BUCK1_VOLT_L,
+       .lpsr_mask              = BD71815_VOLT_MASK,
+       .lpsr_on_mask           = BD71815_BUCK_LPSR_ON,
+};
+
+static const struct rohm_dvs_config buck2_dvs = {
+       .level_map              = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
+                                 ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
+       .run_reg                = BD71815_REG_BUCK2_VOLT_H,
+       .run_mask               = BD71815_VOLT_MASK,
+       .run_on_mask            = BD71815_BUCK_RUN_ON,
+       .snvs_on_mask           = BD71815_BUCK_SNVS_ON,
+       .suspend_reg            = BD71815_REG_BUCK2_VOLT_L,
+       .suspend_mask           = BD71815_VOLT_MASK,
+       .suspend_on_mask        = BD71815_BUCK_SUSP_ON,
+       .lpsr_reg               = BD71815_REG_BUCK2_VOLT_L,
+       .lpsr_mask              = BD71815_VOLT_MASK,
+       .lpsr_on_mask           = BD71815_BUCK_LPSR_ON,
+};
+
+static const struct rohm_dvs_config buck3_dvs = {
+       .level_map              = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
+                                 ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
+       .run_reg                = BD71815_REG_BUCK3_VOLT,
+       .run_mask               = BD71815_VOLT_MASK,
+       .run_on_mask            = BD71815_BUCK_RUN_ON,
+       .snvs_on_mask           = BD71815_BUCK_SNVS_ON,
+       .suspend_on_mask        = BD71815_BUCK_SUSP_ON,
+       .lpsr_on_mask           = BD71815_BUCK_LPSR_ON,
+};
+
+static const struct rohm_dvs_config buck4_dvs = {
+       .level_map              = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
+                                 ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
+       .run_reg                = BD71815_REG_BUCK4_VOLT,
+       .run_mask               = BD71815_VOLT_MASK,
+       .run_on_mask            = BD71815_BUCK_RUN_ON,
+       .snvs_on_mask           = BD71815_BUCK_SNVS_ON,
+       .suspend_on_mask        = BD71815_BUCK_SUSP_ON,
+       .lpsr_on_mask           = BD71815_BUCK_LPSR_ON,
+};
+
+static const struct rohm_dvs_config ldo1_dvs = {
+       .level_map              = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
+                                 ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
+       .run_reg                = BD71815_REG_LDO_MODE1,
+       .run_mask               = BD71815_VOLT_MASK,
+       .run_on_mask            = LDO1_RUN_ON,
+       .snvs_on_mask           = LDO1_SNVS_ON,
+       .suspend_on_mask        = LDO1_SUSP_ON,
+       .lpsr_on_mask           = LDO1_LPSR_ON,
+};
+
+static const struct rohm_dvs_config ldo2_dvs = {
+       .level_map              = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
+                                 ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
+       .run_reg                = BD71815_REG_LDO_MODE2,
+       .run_mask               = BD71815_VOLT_MASK,
+       .run_on_mask            = LDO2_RUN_ON,
+       .snvs_on_mask           = LDO2_SNVS_ON,
+       .suspend_on_mask        = LDO2_SUSP_ON,
+       .lpsr_on_mask           = LDO2_LPSR_ON,
+};
+
+static const struct rohm_dvs_config ldo3_dvs = {
+       .level_map              = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
+                                 ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
+       .run_reg                = BD71815_REG_LDO_MODE2,
+       .run_mask               = BD71815_VOLT_MASK,
+       .run_on_mask            = LDO3_RUN_ON,
+       .snvs_on_mask           = LDO3_SNVS_ON,
+       .suspend_on_mask        = LDO3_SUSP_ON,
+       .lpsr_on_mask           = LDO3_LPSR_ON,
+};
+
+static const struct rohm_dvs_config ldo4_dvs = {
+       .level_map              = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
+                                 ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
+       .run_reg                = BD71815_REG_LDO_MODE3,
+       .run_mask               = BD71815_VOLT_MASK,
+       .run_on_mask            = LDO4_RUN_ON,
+       .snvs_on_mask           = LDO4_SNVS_ON,
+       .suspend_on_mask        = LDO4_SUSP_ON,
+       .lpsr_on_mask           = LDO4_LPSR_ON,
+};
+
+static const struct rohm_dvs_config ldo5_dvs = {
+       .level_map              = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
+                                 ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
+       .run_reg                = BD71815_REG_LDO_MODE3,
+       .run_mask               = BD71815_VOLT_MASK,
+       .run_on_mask            = LDO5_RUN_ON,
+       .snvs_on_mask           = LDO5_SNVS_ON,
+       .suspend_on_mask        = LDO5_SUSP_ON,
+       .lpsr_on_mask           = LDO5_LPSR_ON,
+};
+
+static const struct rohm_dvs_config dvref_dvs = {
+       .level_map              = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
+                                 ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
+       .run_on_mask            = DVREF_RUN_ON,
+       .snvs_on_mask           = DVREF_SNVS_ON,
+       .suspend_on_mask        = DVREF_SUSP_ON,
+       .lpsr_on_mask           = DVREF_LPSR_ON,
+};
+
+static const struct rohm_dvs_config ldolpsr_dvs = {
+       .level_map              = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
+                                 ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
+       .run_on_mask            = DVREF_RUN_ON,
+       .snvs_on_mask           = DVREF_SNVS_ON,
+       .suspend_on_mask        = DVREF_SUSP_ON,
+       .lpsr_on_mask           = DVREF_LPSR_ON,
+};
+
+static const struct rohm_dvs_config buck5_dvs = {
+       .level_map              = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
+                                 ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
+       .run_reg                = BD71815_REG_BUCK5_VOLT,
+       .run_mask               = BD71815_VOLT_MASK,
+       .run_on_mask            = BD71815_BUCK_RUN_ON,
+       .snvs_on_mask           = BD71815_BUCK_SNVS_ON,
+       .suspend_on_mask        = BD71815_BUCK_SUSP_ON,
+       .lpsr_on_mask           = BD71815_BUCK_LPSR_ON,
+};
+
+static int set_hw_dvs_levels(struct device_node *np,
+                            const struct regulator_desc *desc,
+                            struct regulator_config *cfg)
+{
+       struct bd71815_regulator *data;
+
+       data = container_of(desc, struct bd71815_regulator, desc);
+       return rohm_regulator_set_dvs_levels(data->dvs, np, desc, cfg->regmap);
+}
+
+/*
+ * Bucks 1 and 2 have two voltage selection registers where selected
+ * voltage can be set. Which of the registers is used can be either controlled
+ * by a control bit in register - or by HW state. If HW state specific voltages
+ * are given - then we assume HW state based control should be used.
+ *
+ * If volatge value is updated to currently selected register - then output
+ * voltage is immediately changed no matter what is set as ramp rate. Thus we
+ * default changing voltage by writing new value to inactive register and
+ * then updating the 'register selection' bit. This naturally only works when
+ * HW state machine is not used to select the voltage.
+ */
+static int buck12_set_hw_dvs_levels(struct device_node *np,
+                                   const struct regulator_desc *desc,
+                                   struct regulator_config *cfg)
+{
+       struct bd71815_regulator *data;
+       int ret = 0, val;
+
+       data = container_of(desc, struct bd71815_regulator, desc);
+
+       if (of_find_property(np, "rohm,dvs-run-voltage", NULL) ||
+           of_find_property(np, "rohm,dvs-suspend-voltage", NULL) ||
+           of_find_property(np, "rohm,dvs-lpsr-voltage", NULL) ||
+           of_find_property(np, "rohm,dvs-snvs-voltage", NULL)) {
+               ret = regmap_read(cfg->regmap, desc->vsel_reg, &val);
+               if (ret)
+                       return ret;
+
+               if (!(BD71815_BUCK_STBY_DVS & val) &&
+                   !(BD71815_BUCK_DVSSEL & val)) {
+                       int val2;
+
+                       /*
+                        * We are currently using voltage from _L.
+                        * We'd better copy it to _H and switch to it to
+                        * avoid shutting us down if LPSR or SUSPEND is set to
+                        * disabled. _L value is at reg _H + 1
+                        */
+                       ret = regmap_read(cfg->regmap, desc->vsel_reg + 1,
+                                         &val2);
+                       if (ret)
+                               return ret;
+
+                       ret = regmap_update_bits(cfg->regmap, desc->vsel_reg,
+                                                BD71815_VOLT_MASK |
+                                                BD71815_BUCK_DVSSEL,
+                                                val2 | BD71815_BUCK_DVSSEL);
+                       if (ret)
+                               return ret;
+               }
+               ret = rohm_regulator_set_dvs_levels(data->dvs, np, desc,
+                                                   cfg->regmap);
+               if (ret)
+                       return ret;
+               /*
+                * DVS levels were given => use HW-state machine for voltage
+                * controls. NOTE: AFAIK, This means that if voltage is changed
+                * by SW the ramp-rate is not respected. Should we disable
+                * SW voltage control when the HW state machine is used?
+                */
+               ret = regmap_update_bits(cfg->regmap, desc->vsel_reg,
+                                        BD71815_BUCK_STBY_DVS,
+                                        BD71815_BUCK_STBY_DVS);
+       }
+
+       return ret;
+}
+
+/*
+ * BUCK1/2
+ * BUCK1RAMPRATE[1:0] BUCK1 DVS ramp rate setting
+ * 00: 10.00mV/usec    10mV 1uS
+ * 01: 5.00mV/usec     10mV 2uS
+ * 10: 2.50mV/usec     10mV 4uS
+ * 11: 1.25mV/usec     10mV 8uS
+ */
+static const unsigned int bd7181x_ramp_table[] = { 1250, 2500, 5000, 10000 };
+
+static int bd7181x_led_set_current_limit(struct regulator_dev *rdev,
+                                       int min_uA, int max_uA)
+{
+       int ret;
+       int onstatus;
+
+       onstatus = regulator_is_enabled_regmap(rdev);
+
+       ret = regulator_set_current_limit_regmap(rdev, min_uA, max_uA);
+       if (!ret) {
+               int newstatus;
+
+               newstatus = regulator_is_enabled_regmap(rdev);
+               if (onstatus != newstatus) {
+                       /*
+                        * HW FIX: spurious led status change detected. Toggle
+                        * state as a workaround
+                        */
+                       if (onstatus)
+                               ret = regulator_enable_regmap(rdev);
+                       else
+                               ret = regulator_disable_regmap(rdev);
+
+                       if (ret)
+                               dev_err(rdev_get_dev(rdev),
+                                       "failed to revert the LED state (%d)\n",
+                                       ret);
+               }
+       }
+
+       return ret;
+}
+
+static int bd7181x_buck12_get_voltage_sel(struct regulator_dev *rdev)
+{
+       struct bd71815_pmic *pmic = rdev_get_drvdata(rdev);
+       int rid = rdev_get_id(rdev);
+       int ret, regh, regl, val;
+
+       regh = BD71815_REG_BUCK1_VOLT_H + rid * 0x2;
+       regl = BD71815_REG_BUCK1_VOLT_L + rid * 0x2;
+
+       ret = regmap_read(pmic->regmap, regh, &val);
+       if (ret)
+               return ret;
+
+       /*
+        * If we use HW state machine based voltage reg selection - then we
+        * return BD71815_REG_BUCK1_VOLT_H which is used at RUN.
+        * Else we do return the BD71815_REG_BUCK1_VOLT_H or
+        * BD71815_REG_BUCK1_VOLT_L depending on which is selected to be used
+        * by BD71815_BUCK_DVSSEL bit
+        */
+       if ((!(val & BD71815_BUCK_STBY_DVS)) && (!(val & BD71815_BUCK_DVSSEL)))
+               ret = regmap_read(pmic->regmap, regl, &val);
+
+       if (ret)
+               return ret;
+
+       return val & BD71815_VOLT_MASK;
+}
+
+/*
+ * For Buck 1/2.
+ */
+static int bd7181x_buck12_set_voltage_sel(struct regulator_dev *rdev,
+                                         unsigned int sel)
+{
+       struct bd71815_pmic *pmic = rdev_get_drvdata(rdev);
+       int rid = rdev_get_id(rdev);
+       int ret, val, reg, regh, regl;
+
+       regh = BD71815_REG_BUCK1_VOLT_H + rid*0x2;
+       regl = BD71815_REG_BUCK1_VOLT_L + rid*0x2;
+
+       ret = regmap_read(pmic->regmap, regh, &val);
+       if (ret)
+               return ret;
+
+       /*
+        * If bucks 1 & 2 are controlled by state machine - then the RUN state
+        * voltage is set to BD71815_REG_BUCK1_VOLT_H. Changing SUSPEND/LPSR
+        * voltages at runtime is not supported by this driver.
+        */
+       if (((val & BD71815_BUCK_STBY_DVS))) {
+               return regmap_update_bits(pmic->regmap, regh, BD71815_VOLT_MASK,
+                                         sel);
+       }
+       /* Update new voltage to the register which is not selected now */
+       if (val & BD71815_BUCK_DVSSEL)
+               reg = regl;
+       else
+               reg = regh;
+
+       ret = regmap_update_bits(pmic->regmap, reg, BD71815_VOLT_MASK, sel);
+       if (ret)
+               return ret;
+
+       /* Select the other DVS register to be used */
+       return regmap_update_bits(pmic->regmap, regh, BD71815_BUCK_DVSSEL, ~val);
+}
+
+static const struct regulator_ops bd7181x_ldo_regulator_ops = {
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .list_voltage = regulator_list_voltage_linear,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+static const struct regulator_ops bd7181x_fixed_regulator_ops = {
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .list_voltage = regulator_list_voltage_linear,
+};
+
+static const struct regulator_ops bd7181x_buck_regulator_ops = {
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .list_voltage = regulator_list_voltage_linear,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .set_voltage_time_sel = regulator_set_voltage_time_sel,
+};
+
+static const struct regulator_ops bd7181x_buck12_regulator_ops = {
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .list_voltage = regulator_list_voltage_linear,
+       .set_voltage_sel = bd7181x_buck12_set_voltage_sel,
+       .get_voltage_sel = bd7181x_buck12_get_voltage_sel,
+       .set_voltage_time_sel = regulator_set_voltage_time_sel,
+       .set_ramp_delay = regulator_set_ramp_delay_regmap,
+};
+
+static const struct regulator_ops bd7181x_led_regulator_ops = {
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .set_current_limit = bd7181x_led_set_current_limit,
+       .get_current_limit = regulator_get_current_limit_regmap,
+};
+
+#define BD71815_FIXED_REG(_name, _id, ereg, emsk, voltage, _dvs)       \
+       [(_id)] = {                                                     \
+               .desc = {                                               \
+                       .name = #_name,                                 \
+                       .of_match = of_match_ptr(#_name),               \
+                       .regulators_node = of_match_ptr("regulators"),  \
+                       .n_voltages = 1,                                \
+                       .ops = &bd7181x_fixed_regulator_ops,            \
+                       .type = REGULATOR_VOLTAGE,                      \
+                       .id = (_id),                                    \
+                       .owner = THIS_MODULE,                           \
+                       .min_uV = (voltage),                            \
+                       .enable_reg = (ereg),                           \
+                       .enable_mask = (emsk),                          \
+                       .of_parse_cb = set_hw_dvs_levels,               \
+               },                                                      \
+               .dvs = (_dvs),                                          \
+       }
+
+#define BD71815_BUCK_REG(_name, _id, vsel, ereg, min, max, step, _dvs) \
+       [(_id)] = {                                                     \
+               .desc = {                                               \
+                       .name = #_name,                                 \
+                       .of_match = of_match_ptr(#_name),               \
+                       .regulators_node = of_match_ptr("regulators"),  \
+                       .n_voltages = ((max) - (min)) / (step) + 1,     \
+                       .ops = &bd7181x_buck_regulator_ops,             \
+                       .type = REGULATOR_VOLTAGE,                      \
+                       .id = (_id),                                    \
+                       .owner = THIS_MODULE,                           \
+                       .min_uV = (min),                                \
+                       .uV_step = (step),                              \
+                       .vsel_reg = (vsel),                             \
+                       .vsel_mask = BD71815_VOLT_MASK,                 \
+                       .enable_reg = (ereg),                           \
+                       .enable_mask = BD71815_BUCK_RUN_ON,             \
+                       .of_parse_cb = set_hw_dvs_levels,               \
+               },                                                      \
+               .dvs = (_dvs),                                          \
+       }
+
+#define BD71815_BUCK12_REG(_name, _id, vsel, ereg, min, max, step,     \
+                          _dvs)                                        \
+       [(_id)] = {                                                     \
+               .desc = {                                               \
+                       .name = #_name,                                 \
+                       .of_match = of_match_ptr(#_name),               \
+                       .regulators_node = of_match_ptr("regulators"),  \
+                       .n_voltages = ((max) - (min)) / (step) + 1,     \
+                       .ops = &bd7181x_buck12_regulator_ops,           \
+                       .type = REGULATOR_VOLTAGE,                      \
+                       .id = (_id),                                    \
+                       .owner = THIS_MODULE,                           \
+                       .min_uV = (min),                                \
+                       .uV_step = (step),                              \
+                       .vsel_reg = (vsel),                             \
+                       .vsel_mask = 0x3f,                              \
+                       .enable_reg = (ereg),                           \
+                       .enable_mask = 0x04,                            \
+                       .ramp_reg = (ereg),                             \
+                       .ramp_mask = BD71815_BUCK_RAMPRATE_MASK,        \
+                       .ramp_delay_table = bd7181x_ramp_table,         \
+                       .n_ramp_values = ARRAY_SIZE(bd7181x_ramp_table),\
+                       .of_parse_cb = buck12_set_hw_dvs_levels,        \
+               },                                                      \
+               .dvs = (_dvs),                                          \
+       }
+
+#define BD71815_LED_REG(_name, _id, csel, mask, ereg, emsk, currents)  \
+       [(_id)] = {                                                     \
+               .desc = {                                               \
+                       .name = #_name,                                 \
+                       .of_match = of_match_ptr(#_name),               \
+                       .regulators_node = of_match_ptr("regulators"),  \
+                       .n_current_limits = ARRAY_SIZE(currents),       \
+                       .ops = &bd7181x_led_regulator_ops,              \
+                       .type = REGULATOR_CURRENT,                      \
+                       .id = (_id),                                    \
+                       .owner = THIS_MODULE,                           \
+                       .curr_table = currents,                         \
+                       .csel_reg = (csel),                             \
+                       .csel_mask = (mask),                            \
+                       .enable_reg = (ereg),                           \
+                       .enable_mask = (emsk),                          \
+               },                                                      \
+       }
+
+#define BD71815_LDO_REG(_name, _id, vsel, ereg, emsk, min, max, step,  \
+                       _dvs)                                           \
+       [(_id)] = {                                                     \
+               .desc = {                                               \
+                       .name = #_name,                                 \
+                       .of_match = of_match_ptr(#_name),               \
+                       .regulators_node = of_match_ptr("regulators"),  \
+                       .n_voltages = ((max) - (min)) / (step) + 1,     \
+                       .ops = &bd7181x_ldo_regulator_ops,              \
+                       .type = REGULATOR_VOLTAGE,                      \
+                       .id = (_id),                                    \
+                       .owner = THIS_MODULE,                           \
+                       .min_uV = (min),                                \
+                       .uV_step = (step),                              \
+                       .vsel_reg = (vsel),                             \
+                       .vsel_mask = BD71815_VOLT_MASK,                 \
+                       .enable_reg = (ereg),                           \
+                       .enable_mask = (emsk),                          \
+                       .of_parse_cb = set_hw_dvs_levels,               \
+               },                                                      \
+               .dvs = (_dvs),                                          \
+       }
+
+static struct bd71815_regulator bd71815_regulators[] = {
+       BD71815_BUCK12_REG(buck1, BD71815_BUCK1, BD71815_REG_BUCK1_VOLT_H,
+                          BD71815_REG_BUCK1_MODE, 800000, 2000000, 25000,
+                          &buck1_dvs),
+       BD71815_BUCK12_REG(buck2, BD71815_BUCK2, BD71815_REG_BUCK2_VOLT_H,
+                          BD71815_REG_BUCK2_MODE, 800000, 2000000, 25000,
+                          &buck2_dvs),
+       BD71815_BUCK_REG(buck3, BD71815_BUCK3, BD71815_REG_BUCK3_VOLT,
+                        BD71815_REG_BUCK3_MODE,  1200000, 2700000, 50000,
+                        &buck3_dvs),
+       BD71815_BUCK_REG(buck4, BD71815_BUCK4, BD71815_REG_BUCK4_VOLT,
+                        BD71815_REG_BUCK4_MODE,  1100000, 1850000, 25000,
+                        &buck4_dvs),
+       BD71815_BUCK_REG(buck5, BD71815_BUCK5, BD71815_REG_BUCK5_VOLT,
+                        BD71815_REG_BUCK5_MODE,  1800000, 3300000, 50000,
+                        &buck5_dvs),
+       BD71815_LDO_REG(ldo1, BD71815_LDO1, BD71815_REG_LDO1_VOLT,
+                       BD71815_REG_LDO_MODE1, LDO1_RUN_ON, 800000, 3300000,
+                       50000, &ldo1_dvs),
+       BD71815_LDO_REG(ldo2, BD71815_LDO2, BD71815_REG_LDO2_VOLT,
+                       BD71815_REG_LDO_MODE2, LDO2_RUN_ON, 800000, 3300000,
+                       50000, &ldo2_dvs),
+       /*
+        * Let's default LDO3 to be enabled by SW. We can override ops if DT
+        * says LDO3 should be enabled by HW when DCIN is connected.
+        */
+       BD71815_LDO_REG(ldo3, BD71815_LDO3, BD71815_REG_LDO3_VOLT,
+                       BD71815_REG_LDO_MODE2, LDO3_RUN_ON, 800000, 3300000,
+                       50000, &ldo3_dvs),
+       BD71815_LDO_REG(ldo4, BD71815_LDO4, BD71815_REG_LDO4_VOLT,
+                       BD71815_REG_LDO_MODE3, LDO4_RUN_ON, 800000, 3300000,
+                       50000, &ldo4_dvs),
+       BD71815_LDO_REG(ldo5, BD71815_LDO5, BD71815_REG_LDO5_VOLT_H,
+                       BD71815_REG_LDO_MODE3, LDO5_RUN_ON, 800000, 3300000,
+                       50000, &ldo5_dvs),
+       BD71815_FIXED_REG(ldodvref, BD71815_LDODVREF, BD71815_REG_LDO_MODE4,
+                         DVREF_RUN_ON, 3000000, &dvref_dvs),
+       BD71815_FIXED_REG(ldolpsr, BD71815_LDOLPSR, BD71815_REG_LDO_MODE4,
+                         LDO_LPSR_RUN_ON, 1800000, &ldolpsr_dvs),
+       BD71815_LED_REG(wled, BD71815_WLED, BD71815_REG_LED_DIMM, LED_DIMM_MASK,
+                       BD71815_REG_LED_CTRL, LED_RUN_ON,
+                       bd7181x_wled_currents),
+};
+
+static int bd7181x_probe(struct platform_device *pdev)
+{
+       struct bd71815_pmic *pmic;
+       struct regulator_config config = {};
+       int i, ret;
+       struct gpio_desc *ldo4_en;
+
+       pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
+       if (!pmic)
+               return -ENOMEM;
+
+       memcpy(pmic->descs, bd71815_regulators, sizeof(pmic->descs));
+
+       pmic->dev = &pdev->dev;
+       pmic->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+       if (!pmic->regmap) {
+               dev_err(pmic->dev, "No parent regmap\n");
+               return -ENODEV;
+       }
+       platform_set_drvdata(pdev, pmic);
+       ldo4_en = devm_gpiod_get_from_of_node(&pdev->dev,
+                                             pdev->dev.parent->of_node,
+                                                "rohm,vsel-gpios", 0,
+                                                GPIOD_ASIS, "ldo4-en");
+
+       if (IS_ERR(ldo4_en)) {
+               ret = PTR_ERR(ldo4_en);
+               if (ret != -ENOENT)
+                       return ret;
+               ldo4_en = NULL;
+       }
+
+       /* Disable to go to ship-mode */
+       ret = regmap_update_bits(pmic->regmap, BD71815_REG_PWRCTRL,
+                                RESTARTEN, 0);
+       if (ret)
+               return ret;
+
+       config.dev = pdev->dev.parent;
+       config.regmap = pmic->regmap;
+
+       for (i = 0; i < BD71815_REGULATOR_CNT; i++) {
+               struct regulator_desc *desc;
+               struct regulator_dev *rdev;
+
+               desc = &pmic->descs[i].desc;
+               if (i == BD71815_LDO4)
+                       config.ena_gpiod = ldo4_en;
+
+               config.driver_data = pmic;
+
+               rdev = devm_regulator_register(&pdev->dev, desc, &config);
+               if (IS_ERR(rdev)) {
+                       dev_err(&pdev->dev,
+                               "failed to register %s regulator\n",
+                               desc->name);
+                       return PTR_ERR(rdev);
+               }
+               config.ena_gpiod = NULL;
+               pmic->rdev[i] = rdev;
+       }
+       return 0;
+}
+
+static const struct platform_device_id bd7181x_pmic_id[] = {
+       { "bd71815-pmic", ROHM_CHIP_TYPE_BD71815 },
+       { },
+};
+MODULE_DEVICE_TABLE(platform, bd7181x_pmic_id);
+
+static struct platform_driver bd7181x_regulator = {
+       .driver = {
+               .name = "bd7181x-pmic",
+               .owner = THIS_MODULE,
+       },
+       .probe = bd7181x_probe,
+       .id_table = bd7181x_pmic_id,
+};
+module_platform_driver(bd7181x_regulator);
+
+MODULE_AUTHOR("Tony Luo <luofc@embedinfo.com>");
+MODULE_DESCRIPTION("BD71815 voltage regulator driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:bd7181x-pmic");
index 6b12e96..a4f09a5 100644 (file)
@@ -90,38 +90,7 @@ static const struct linear_range bd71828_ldo_volts[] = {
        REGULATOR_LINEAR_RANGE(3300000, 0x32, 0x3f, 0),
 };
 
-static int bd71828_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
-{
-       unsigned int val;
-
-       switch (ramp_delay) {
-       case 1 ... 2500:
-               val = 0;
-               break;
-       case 2501 ... 5000:
-               val = 1;
-               break;
-       case 5001 ... 10000:
-               val = 2;
-               break;
-       case 10001 ... 20000:
-               val = 3;
-               break;
-       default:
-               val = 3;
-               dev_err(&rdev->dev,
-                       "ramp_delay: %d not supported, setting 20mV/uS",
-                        ramp_delay);
-       }
-
-       /*
-        * On BD71828 the ramp delay level control reg is at offset +2 to
-        * enable reg
-        */
-       return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg + 2,
-                                 BD71828_MASK_RAMP_DELAY,
-                                 val << (ffs(BD71828_MASK_RAMP_DELAY) - 1));
-}
+static const unsigned int bd71828_ramp_delay[] = { 2500, 5000, 10000, 20000 };
 
 static int buck_set_hw_dvs_levels(struct device_node *np,
                                  const struct regulator_desc *desc,
@@ -185,7 +154,7 @@ static const struct regulator_ops bd71828_dvs_buck_ops = {
        .set_voltage_sel = regulator_set_voltage_sel_regmap,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
        .set_voltage_time_sel = regulator_set_voltage_time_sel,
-       .set_ramp_delay = bd71828_set_ramp_delay,
+       .set_ramp_delay = regulator_set_ramp_delay_regmap,
 };
 
 static const struct regulator_ops bd71828_ldo_ops = {
@@ -219,6 +188,10 @@ static const struct bd71828_regulator_data bd71828_rdata[] = {
                        .enable_mask = BD71828_MASK_RUN_EN,
                        .vsel_reg = BD71828_REG_BUCK1_VOLT,
                        .vsel_mask = BD71828_MASK_BUCK1267_VOLT,
+                       .ramp_delay_table = bd71828_ramp_delay,
+                       .n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
+                       .ramp_reg = BD71828_REG_BUCK1_MODE,
+                       .ramp_mask = BD71828_MASK_RAMP_DELAY,
                        .owner = THIS_MODULE,
                        .of_parse_cb = buck_set_hw_dvs_levels,
                },
@@ -261,6 +234,10 @@ static const struct bd71828_regulator_data bd71828_rdata[] = {
                        .enable_mask = BD71828_MASK_RUN_EN,
                        .vsel_reg = BD71828_REG_BUCK2_VOLT,
                        .vsel_mask = BD71828_MASK_BUCK1267_VOLT,
+                       .ramp_delay_table = bd71828_ramp_delay,
+                       .n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
+                       .ramp_reg = BD71828_REG_BUCK2_MODE,
+                       .ramp_mask = BD71828_MASK_RAMP_DELAY,
                        .owner = THIS_MODULE,
                        .of_parse_cb = buck_set_hw_dvs_levels,
                },
@@ -421,6 +398,10 @@ static const struct bd71828_regulator_data bd71828_rdata[] = {
                        .enable_mask = BD71828_MASK_RUN_EN,
                        .vsel_reg = BD71828_REG_BUCK6_VOLT,
                        .vsel_mask = BD71828_MASK_BUCK1267_VOLT,
+                       .ramp_delay_table = bd71828_ramp_delay,
+                       .n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
+                       .ramp_reg = BD71828_REG_BUCK6_MODE,
+                       .ramp_mask = BD71828_MASK_RAMP_DELAY,
                        .owner = THIS_MODULE,
                        .of_parse_cb = buck_set_hw_dvs_levels,
                },
@@ -458,6 +439,10 @@ static const struct bd71828_regulator_data bd71828_rdata[] = {
                        .enable_mask = BD71828_MASK_RUN_EN,
                        .vsel_reg = BD71828_REG_BUCK7_VOLT,
                        .vsel_mask = BD71828_MASK_BUCK1267_VOLT,
+                       .ramp_delay_table = bd71828_ramp_delay,
+                       .n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
+                       .ramp_reg = BD71828_REG_BUCK7_MODE,
+                       .ramp_mask = BD71828_MASK_RAMP_DELAY,
                        .owner = THIS_MODULE,
                        .of_parse_cb = buck_set_hw_dvs_levels,
                },
index 8ff47ea..e61295b 100644 (file)
@@ -86,37 +86,7 @@ static const struct regulator_ops BD718XX_HWOPNAME(name) = { \
  * 10: 2.50mV/usec     10mV 4uS
  * 11: 1.25mV/usec     10mV 8uS
  */
-static int bd718xx_buck1234_set_ramp_delay(struct regulator_dev *rdev,
-                                          int ramp_delay)
-{
-       int id = rdev_get_id(rdev);
-       unsigned int ramp_value;
-
-       dev_dbg(&rdev->dev, "Buck[%d] Set Ramp = %d\n", id + 1,
-               ramp_delay);
-       switch (ramp_delay) {
-       case 1 ... 1250:
-               ramp_value = BUCK_RAMPRATE_1P25MV;
-               break;
-       case 1251 ... 2500:
-               ramp_value = BUCK_RAMPRATE_2P50MV;
-               break;
-       case 2501 ... 5000:
-               ramp_value = BUCK_RAMPRATE_5P00MV;
-               break;
-       case 5001 ... 10000:
-               ramp_value = BUCK_RAMPRATE_10P00MV;
-               break;
-       default:
-               ramp_value = BUCK_RAMPRATE_10P00MV;
-               dev_err(&rdev->dev,
-                       "%s: ramp_delay: %d not supported, setting 10000mV//us\n",
-                       rdev->desc->name, ramp_delay);
-       }
-
-       return regmap_update_bits(rdev->regmap, BD718XX_REG_BUCK1_CTRL + id,
-                                 BUCK_RAMPRATE_MASK, ramp_value << 6);
-}
+static const unsigned int bd718xx_ramp_delay[] = { 10000, 5000, 2500, 1250 };
 
 /* These functions are used when regulators are under HW state machine control.
  * We assume PMIC is in RUN state because SW running and able to query the
@@ -378,7 +348,7 @@ static const struct regulator_ops bd71837_buck34_ops_hwctrl = {
        .set_voltage_sel = regulator_set_voltage_sel_regmap,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
        .set_voltage_time_sel = regulator_set_voltage_time_sel,
-       .set_ramp_delay = bd718xx_buck1234_set_ramp_delay,
+       .set_ramp_delay = regulator_set_ramp_delay_regmap,
 };
 
 /*
@@ -387,7 +357,7 @@ static const struct regulator_ops bd71837_buck34_ops_hwctrl = {
 BD718XX_OPS(bd718xx_dvs_buck_regulator_ops, regulator_list_voltage_linear_range,
            NULL, regulator_set_voltage_sel_regmap,
            regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel,
-           bd718xx_buck1234_set_ramp_delay);
+           /* bd718xx_buck1234_set_ramp_delay */ regulator_set_ramp_delay_regmap);
 
 /*
  * BD71837 BUCK1/2/3/4
@@ -645,6 +615,10 @@ static struct bd718xx_regulator_data bd71847_regulators[] = {
                        .enable_mask = BD718XX_BUCK_EN,
                        .enable_time = BD71847_BUCK1_STARTUP_TIME,
                        .owner = THIS_MODULE,
+                       .ramp_delay_table = bd718xx_ramp_delay,
+                       .n_ramp_values = ARRAY_SIZE(bd718xx_ramp_delay),
+                       .ramp_reg = BD718XX_REG_BUCK1_CTRL,
+                       .ramp_mask = BUCK_RAMPRATE_MASK,
                        .of_parse_cb = buck_set_hw_dvs_levels,
                },
                .dvs = {
@@ -678,6 +652,10 @@ static struct bd718xx_regulator_data bd71847_regulators[] = {
                        .enable_reg = BD718XX_REG_BUCK2_CTRL,
                        .enable_mask = BD718XX_BUCK_EN,
                        .enable_time = BD71847_BUCK2_STARTUP_TIME,
+                       .ramp_delay_table = bd718xx_ramp_delay,
+                       .n_ramp_values = ARRAY_SIZE(bd718xx_ramp_delay),
+                       .ramp_reg = BD718XX_REG_BUCK2_CTRL,
+                       .ramp_mask = BUCK_RAMPRATE_MASK,
                        .owner = THIS_MODULE,
                        .of_parse_cb = buck_set_hw_dvs_levels,
                },
@@ -985,6 +963,10 @@ static struct bd718xx_regulator_data bd71837_regulators[] = {
                        .enable_reg = BD718XX_REG_BUCK1_CTRL,
                        .enable_mask = BD718XX_BUCK_EN,
                        .enable_time = BD71837_BUCK1_STARTUP_TIME,
+                       .ramp_delay_table = bd718xx_ramp_delay,
+                       .n_ramp_values = ARRAY_SIZE(bd718xx_ramp_delay),
+                       .ramp_reg = BD718XX_REG_BUCK1_CTRL,
+                       .ramp_mask = BUCK_RAMPRATE_MASK,
                        .owner = THIS_MODULE,
                        .of_parse_cb = buck_set_hw_dvs_levels,
                },
@@ -1019,6 +1001,10 @@ static struct bd718xx_regulator_data bd71837_regulators[] = {
                        .enable_reg = BD718XX_REG_BUCK2_CTRL,
                        .enable_mask = BD718XX_BUCK_EN,
                        .enable_time = BD71837_BUCK2_STARTUP_TIME,
+                       .ramp_delay_table = bd718xx_ramp_delay,
+                       .n_ramp_values = ARRAY_SIZE(bd718xx_ramp_delay),
+                       .ramp_reg = BD718XX_REG_BUCK2_CTRL,
+                       .ramp_mask = BUCK_RAMPRATE_MASK,
                        .owner = THIS_MODULE,
                        .of_parse_cb = buck_set_hw_dvs_levels,
                },
@@ -1050,6 +1036,10 @@ static struct bd718xx_regulator_data bd71837_regulators[] = {
                        .enable_reg = BD71837_REG_BUCK3_CTRL,
                        .enable_mask = BD718XX_BUCK_EN,
                        .enable_time = BD71837_BUCK3_STARTUP_TIME,
+                       .ramp_delay_table = bd718xx_ramp_delay,
+                       .n_ramp_values = ARRAY_SIZE(bd718xx_ramp_delay),
+                       .ramp_reg = BD71837_REG_BUCK3_CTRL,
+                       .ramp_mask = BUCK_RAMPRATE_MASK,
                        .owner = THIS_MODULE,
                        .of_parse_cb = buck_set_hw_dvs_levels,
                },
@@ -1079,6 +1069,10 @@ static struct bd718xx_regulator_data bd71837_regulators[] = {
                        .enable_reg = BD71837_REG_BUCK4_CTRL,
                        .enable_mask = BD718XX_BUCK_EN,
                        .enable_time = BD71837_BUCK4_STARTUP_TIME,
+                       .ramp_delay_table = bd718xx_ramp_delay,
+                       .n_ramp_values = ARRAY_SIZE(bd718xx_ramp_delay),
+                       .ramp_reg = BD71837_REG_BUCK4_CTRL,
+                       .ramp_mask = BUCK_RAMPRATE_MASK,
                        .owner = THIS_MODULE,
                        .of_parse_cb = buck_set_hw_dvs_levels,
                },
index f42b394..0e16e31 100644 (file)
@@ -508,6 +508,33 @@ int regulator_map_voltage_pickable_linear_range(struct regulator_dev *rdev,
 }
 EXPORT_SYMBOL_GPL(regulator_map_voltage_pickable_linear_range);
 
+/**
+ * regulator_desc_list_voltage_linear - List voltages with simple calculation
+ *
+ * @desc: Regulator desc for regulator which volatges are to be listed
+ * @selector: Selector to convert into a voltage
+ *
+ * Regulators with a simple linear mapping between voltages and
+ * selectors can set min_uV and uV_step in the regulator descriptor
+ * and then use this function prior regulator registration to list
+ * the voltages. This is useful when voltages need to be listed during
+ * device-tree parsing.
+ */
+int regulator_desc_list_voltage_linear(const struct regulator_desc *desc,
+                                      unsigned int selector)
+{
+       if (selector >= desc->n_voltages)
+               return -EINVAL;
+
+       if (selector < desc->linear_min_sel)
+               return 0;
+
+       selector -= desc->linear_min_sel;
+
+       return desc->min_uV + (desc->uV_step * selector);
+}
+EXPORT_SYMBOL_GPL(regulator_desc_list_voltage_linear);
+
 /**
  * regulator_list_voltage_linear - List voltages with simple calculation
  *
@@ -521,14 +548,7 @@ EXPORT_SYMBOL_GPL(regulator_map_voltage_pickable_linear_range);
 int regulator_list_voltage_linear(struct regulator_dev *rdev,
                                  unsigned int selector)
 {
-       if (selector >= rdev->desc->n_voltages)
-               return -EINVAL;
-       if (selector < rdev->desc->linear_min_sel)
-               return 0;
-
-       selector -= rdev->desc->linear_min_sel;
-
-       return rdev->desc->min_uV + (rdev->desc->uV_step * selector);
+       return regulator_desc_list_voltage_linear(rdev->desc, selector);
 }
 EXPORT_SYMBOL_GPL(regulator_list_voltage_linear);
 
@@ -881,3 +901,68 @@ bool regulator_is_equal(struct regulator *reg1, struct regulator *reg2)
        return reg1->rdev == reg2->rdev;
 }
 EXPORT_SYMBOL_GPL(regulator_is_equal);
+
+static int find_closest_bigger(unsigned int target, const unsigned int *table,
+                              unsigned int num_sel, unsigned int *sel)
+{
+       unsigned int s, tmp, max, maxsel = 0;
+       bool found = false;
+
+       max = table[0];
+
+       for (s = 0; s < num_sel; s++) {
+               if (table[s] > max) {
+                       max = table[s];
+                       maxsel = s;
+               }
+               if (table[s] >= target) {
+                       if (!found || table[s] - target < tmp - target) {
+                               tmp = table[s];
+                               *sel = s;
+                               found = true;
+                               if (tmp == target)
+                                       break;
+                       }
+               }
+       }
+
+       if (!found) {
+               *sel = maxsel;
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * regulator_set_ramp_delay_regmap - set_ramp_delay() helper
+ *
+ * @rdev: regulator to operate on
+ *
+ * Regulators that use regmap for their register I/O can set the ramp_reg
+ * and ramp_mask fields in their descriptor and then use this as their
+ * set_ramp_delay operation, saving some code.
+ */
+int regulator_set_ramp_delay_regmap(struct regulator_dev *rdev, int ramp_delay)
+{
+       int ret;
+       unsigned int sel;
+
+       if (!rdev->desc->n_ramp_values)
+               return -EINVAL;
+
+       ret = find_closest_bigger(ramp_delay, rdev->desc->ramp_delay_table,
+                                 rdev->desc->n_ramp_values, &sel);
+
+       if (ret) {
+               dev_warn(rdev_get_dev(rdev),
+                        "Can't set ramp-delay %u, setting %u\n", ramp_delay,
+                        rdev->desc->ramp_delay_table[sel]);
+       }
+
+       sel <<= ffs(rdev->desc->ramp_mask) - 1;
+
+       return regmap_update_bits(rdev->regmap, rdev->desc->ramp_reg,
+                                 rdev->desc->ramp_mask, sel);
+}
+EXPORT_SYMBOL_GPL(regulator_set_ramp_delay_regmap);
index d49a153..9edc349 100644 (file)
@@ -41,7 +41,7 @@ struct mt6315_chip {
                .type = REGULATOR_VOLTAGE,                      \
                .id = _bid,                                     \
                .owner = THIS_MODULE,                           \
-               .n_voltages = 0xbf,                             \
+               .n_voltages = 0xc0,                             \
                .linear_ranges = mt_volt_range1,                \
                .n_linear_ranges = ARRAY_SIZE(mt_volt_range1),  \
                .vsel_reg = _vsel,                              \
@@ -69,7 +69,7 @@ static unsigned int mt6315_map_mode(u32 mode)
        case MT6315_BUCK_MODE_LP:
                return REGULATOR_MODE_IDLE;
        default:
-               return -EINVAL;
+               return REGULATOR_MODE_INVALID;
        }
 }
 
index 833d398..2f7ee21 100644 (file)
@@ -797,6 +797,14 @@ static int pca9450_i2c_probe(struct i2c_client *i2c,
                return ret;
        }
 
+       /* Clear PRESET_EN bit in BUCK123_DVS to use DVS registers */
+       ret = regmap_clear_bits(pca9450->regmap, PCA9450_REG_BUCK123_DVS,
+                               BUCK123_PRESET_EN);
+       if (ret) {
+               dev_err(&i2c->dev, "Failed to clear PRESET_EN bit: %d\n", ret);
+               return ret;
+       }
+
        /* Set reset behavior on assertion of WDOG_B signal */
        ret = regmap_update_bits(pca9450->regmap, PCA9450_REG_RESET_CTRL,
                                WDOG_B_CFG_MASK, WDOG_B_CFG_COLD_LDO12);
@@ -814,7 +822,7 @@ static int pca9450_i2c_probe(struct i2c_client *i2c,
 
        if (IS_ERR(pca9450->sd_vsel_gpio)) {
                dev_err(&i2c->dev, "Failed to get SD_VSEL GPIO\n");
-               return ret;
+               return PTR_ERR(pca9450->sd_vsel_gpio);
        }
 
        dev_info(&i2c->dev, "%s probed.\n",
index 79a554f..65a108c 100644 (file)
@@ -726,8 +726,8 @@ static const struct rpmh_vreg_hw_data pmic5_ftsmps510 = {
 static const struct rpmh_vreg_hw_data pmic5_hfsmps515 = {
        .regulator_type = VRM,
        .ops = &rpmh_regulator_vrm_ops,
-       .voltage_range = REGULATOR_LINEAR_RANGE(2800000, 0, 4, 16000),
-       .n_voltages = 5,
+       .voltage_range = REGULATOR_LINEAR_RANGE(320000, 0, 235, 16000),
+       .n_voltages = 236,
        .pmic_mode_map = pmic_mode_map_pmic5_smps,
        .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
 };
@@ -901,7 +901,7 @@ static const struct rpmh_vreg_init_data pm8350_vreg_data[] = {
 };
 
 static const struct rpmh_vreg_init_data pm8350c_vreg_data[] = {
-       RPMH_VREG("smps1",  "smp%s1",  &pmic5_hfsmps510, "vdd-s1"),
+       RPMH_VREG("smps1",  "smp%s1",  &pmic5_hfsmps515, "vdd-s1"),
        RPMH_VREG("smps2",  "smp%s2",  &pmic5_ftsmps510, "vdd-s2"),
        RPMH_VREG("smps3",  "smp%s3",  &pmic5_ftsmps510, "vdd-s3"),
        RPMH_VREG("smps4",  "smp%s4",  &pmic5_ftsmps510, "vdd-s4"),
index 5c558b1..6e0d9c0 100644 (file)
@@ -22,13 +22,26 @@ static int set_dvs_level(const struct regulator_desc *desc,
                        return ret;
                return 0;
        }
-
+       /* If voltage is set to 0 => disable */
        if (uv == 0) {
                if (omask)
                        return regmap_update_bits(regmap, oreg, omask, 0);
        }
+       /* Some setups don't allow setting own voltage but do allow enabling */
+       if (!mask) {
+               if (omask)
+                       return regmap_update_bits(regmap, oreg, omask, omask);
+
+               return -EINVAL;
+       }
        for (i = 0; i < desc->n_voltages; i++) {
-               ret = regulator_desc_list_voltage_linear_range(desc, i);
+               /* NOTE to next hacker - Does not support pickable ranges */
+               if (desc->linear_range_selectors)
+                       return -EINVAL;
+               if (desc->n_linear_ranges)
+                       ret = regulator_desc_list_voltage_linear_range(desc, i);
+               else
+                       ret = regulator_desc_list_voltage_linear(desc, i);
                if (ret < 0)
                        continue;
                if (ret == uv) {
@@ -82,6 +95,12 @@ int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs,
                                mask = dvs->lpsr_mask;
                                omask = dvs->lpsr_on_mask;
                                break;
+                       case ROHM_DVS_LEVEL_SNVS:
+                               prop = "rohm,dvs-snvs-voltage";
+                               reg = dvs->snvs_reg;
+                               mask = dvs->snvs_mask;
+                               omask = dvs->snvs_on_mask;
+                               break;
                        default:
                                return -EINVAL;
                        }
index 3d4695d..e3aaac9 100644 (file)
@@ -153,9 +153,9 @@ static int rt4831_regulator_probe(struct platform_device *pdev)
        int i, ret;
 
        regmap = dev_get_regmap(pdev->dev.parent, NULL);
-       if (IS_ERR(regmap)) {
+       if (!regmap) {
                dev_err(&pdev->dev, "Failed to init regmap\n");
-               return PTR_ERR(regmap);
+               return -ENODEV;
        }
 
        /* Configure DSV mode to normal by default */
index e6205f7..773386b 100644 (file)
@@ -501,11 +501,11 @@ config RTC_DRV_M41T80_WDT
          watchdog timer in the ST M41T60 and M41T80 RTC chips series.
 
 config RTC_DRV_BD70528
-       tristate "ROHM BD70528 PMIC RTC"
-       depends on MFD_ROHM_BD70528 && (BD70528_WATCHDOG || !BD70528_WATCHDOG)
+       tristate "ROHM BD70528, BD71815 and BD71828 PMIC RTC"
+       depends on MFD_ROHM_BD71828 || MFD_ROHM_BD70528 && (BD70528_WATCHDOG || !BD70528_WATCHDOG)
        help
          If you say Y here you will get support for the RTC
-         block on ROHM BD70528 and BD71828 Power Management IC.
+         block on ROHM BD70528, BD71815 and BD71828 Power Management IC.
 
          This driver can also be built as a module. If so, the module
          will be called rtc-bd70528.
index 17cb67f..6454afc 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <linux/bcd.h>
 #include <linux/mfd/rohm-bd70528.h>
+#include <linux/mfd/rohm-bd71815.h>
 #include <linux/mfd/rohm-bd71828.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/regmap.h>
 #include <linux/rtc.h>
 
+/*
+ * On BD71828 and BD71815 the ALM0 MASK is 14 bytes after the ALM0
+ * block start
+ */
+#define BD718XX_ALM_EN_OFFSET 14
+
 /*
  * We read regs RTC_SEC => RTC_YEAR
  * this struct is ordered according to chip registers.
@@ -52,8 +59,10 @@ struct bd70528_rtc_alm {
 
 struct bd70528_rtc {
        struct rohm_regmap_dev *parent;
+       struct regmap *regmap;
        struct device *dev;
        u8 reg_time_start;
+       u8 bd718xx_alm_block_start;
        bool has_rtc_timers;
 };
 
@@ -234,10 +243,9 @@ static int bd71828_set_alarm(struct device *dev, struct rtc_wkalrm *a)
        int ret;
        struct bd71828_rtc_alm alm;
        struct bd70528_rtc *r = dev_get_drvdata(dev);
-       struct rohm_regmap_dev *parent = r->parent;
 
-       ret = regmap_bulk_read(parent->regmap, BD71828_REG_RTC_ALM_START,
-                              &alm, sizeof(alm));
+       ret = regmap_bulk_read(r->regmap, r->bd718xx_alm_block_start, &alm,
+                              sizeof(alm));
        if (ret) {
                dev_err(dev, "Failed to read alarm regs\n");
                return ret;
@@ -250,8 +258,8 @@ static int bd71828_set_alarm(struct device *dev, struct rtc_wkalrm *a)
        else
                alm.alm_mask |= BD70528_MASK_ALM_EN;
 
-       ret = regmap_bulk_write(parent->regmap, BD71828_REG_RTC_ALM_START,
-                               &alm, sizeof(alm));
+       ret = regmap_bulk_write(r->regmap, r->bd718xx_alm_block_start, &alm,
+                               sizeof(alm));
        if (ret)
                dev_err(dev, "Failed to set alarm time\n");
 
@@ -265,17 +273,16 @@ static int bd70528_set_alarm(struct device *dev, struct rtc_wkalrm *a)
        struct bd70528_rtc_alm alm;
        int ret;
        struct bd70528_rtc *r = dev_get_drvdata(dev);
-       struct rohm_regmap_dev *parent = r->parent;
 
-       ret = regmap_bulk_read(parent->regmap, BD70528_REG_RTC_WAKE_START,
-                              &wake, sizeof(wake));
+       ret = regmap_bulk_read(r->regmap, BD70528_REG_RTC_WAKE_START, &wake,
+                              sizeof(wake));
        if (ret) {
                dev_err(dev, "Failed to read wake regs\n");
                return ret;
        }
 
-       ret = regmap_bulk_read(parent->regmap, BD70528_REG_RTC_ALM_START,
-                              &alm, sizeof(alm));
+       ret = regmap_bulk_read(r->regmap, BD70528_REG_RTC_ALM_START, &alm,
+                              sizeof(alm));
        if (ret) {
                dev_err(dev, "Failed to read alarm regs\n");
                return ret;
@@ -292,15 +299,14 @@ static int bd70528_set_alarm(struct device *dev, struct rtc_wkalrm *a)
                wake.ctrl &= ~BD70528_MASK_WAKE_EN;
        }
 
-       ret = regmap_bulk_write(parent->regmap,
-                               BD70528_REG_RTC_WAKE_START, &wake,
+       ret = regmap_bulk_write(r->regmap, BD70528_REG_RTC_WAKE_START, &wake,
                                sizeof(wake));
        if (ret) {
                dev_err(dev, "Failed to set wake time\n");
                return ret;
        }
-       ret = regmap_bulk_write(parent->regmap, BD70528_REG_RTC_ALM_START,
-                               &alm, sizeof(alm));
+       ret = regmap_bulk_write(r->regmap, BD70528_REG_RTC_ALM_START, &alm,
+                               sizeof(alm));
        if (ret)
                dev_err(dev, "Failed to set alarm time\n");
 
@@ -312,10 +318,9 @@ static int bd71828_read_alarm(struct device *dev, struct rtc_wkalrm *a)
        int ret;
        struct bd71828_rtc_alm alm;
        struct bd70528_rtc *r = dev_get_drvdata(dev);
-       struct rohm_regmap_dev *parent = r->parent;
 
-       ret = regmap_bulk_read(parent->regmap, BD71828_REG_RTC_ALM_START,
-                              &alm, sizeof(alm));
+       ret = regmap_bulk_read(r->regmap, r->bd718xx_alm_block_start, &alm,
+                              sizeof(alm));
        if (ret) {
                dev_err(dev, "Failed to read alarm regs\n");
                return ret;
@@ -336,10 +341,9 @@ static int bd70528_read_alarm(struct device *dev, struct rtc_wkalrm *a)
        struct bd70528_rtc_alm alm;
        int ret;
        struct bd70528_rtc *r = dev_get_drvdata(dev);
-       struct rohm_regmap_dev *parent = r->parent;
 
-       ret = regmap_bulk_read(parent->regmap, BD70528_REG_RTC_ALM_START,
-                              &alm, sizeof(alm));
+       ret = regmap_bulk_read(r->regmap, BD70528_REG_RTC_ALM_START, &alm,
+                              sizeof(alm));
        if (ret) {
                dev_err(dev, "Failed to read alarm regs\n");
                return ret;
@@ -360,14 +364,12 @@ static int bd70528_set_time_locked(struct device *dev, struct rtc_time *t)
        int ret, tmpret, old_states;
        struct bd70528_rtc_data rtc_data;
        struct bd70528_rtc *r = dev_get_drvdata(dev);
-       struct rohm_regmap_dev *parent = r->parent;
 
        ret = bd70528_disable_rtc_based_timers(r, &old_states);
        if (ret)
                return ret;
 
-       tmpret = regmap_bulk_read(parent->regmap,
-                                 r->reg_time_start, &rtc_data,
+       tmpret = regmap_bulk_read(r->regmap, r->reg_time_start, &rtc_data,
                                  sizeof(rtc_data));
        if (tmpret) {
                dev_err(dev, "Failed to read RTC time registers\n");
@@ -375,8 +377,7 @@ static int bd70528_set_time_locked(struct device *dev, struct rtc_time *t)
        }
        tm2rtc(t, &rtc_data);
 
-       tmpret = regmap_bulk_write(parent->regmap,
-                                  r->reg_time_start, &rtc_data,
+       tmpret = regmap_bulk_write(r->regmap, r->reg_time_start, &rtc_data,
                                   sizeof(rtc_data));
        if (tmpret) {
                dev_err(dev, "Failed to set RTC time\n");
@@ -410,13 +411,11 @@ static int bd70528_set_time(struct device *dev, struct rtc_time *t)
 static int bd70528_get_time(struct device *dev, struct rtc_time *t)
 {
        struct bd70528_rtc *r = dev_get_drvdata(dev);
-       struct rohm_regmap_dev *parent = r->parent;
        struct bd70528_rtc_data rtc_data;
        int ret;
 
        /* read the RTC date and time registers all at once */
-       ret = regmap_bulk_read(parent->regmap,
-                              r->reg_time_start, &rtc_data,
+       ret = regmap_bulk_read(r->regmap, r->reg_time_start, &rtc_data,
                               sizeof(rtc_data));
        if (ret) {
                dev_err(dev, "Failed to read RTC time (err %d)\n", ret);
@@ -443,7 +442,7 @@ static int bd70528_alm_enable(struct device *dev, unsigned int enabled)
                dev_err(dev, "Failed to change wake state\n");
                goto out_unlock;
        }
-       ret = regmap_update_bits(r->parent->regmap, BD70528_REG_RTC_ALM_MASK,
+       ret = regmap_update_bits(r->regmap, BD70528_REG_RTC_ALM_MASK,
                                 BD70528_MASK_ALM_EN, enableval);
        if (ret)
                dev_err(dev, "Failed to change alarm state\n");
@@ -462,8 +461,9 @@ static int bd71828_alm_enable(struct device *dev, unsigned int enabled)
        if (!enabled)
                enableval = 0;
 
-       ret = regmap_update_bits(r->parent->regmap, BD71828_REG_RTC_ALM0_MASK,
-                                BD70528_MASK_ALM_EN, enableval);
+       ret = regmap_update_bits(r->regmap, r->bd718xx_alm_block_start +
+                                BD718XX_ALM_EN_OFFSET, BD70528_MASK_ALM_EN,
+                                enableval);
        if (ret)
                dev_err(dev, "Failed to change alarm state\n");
 
@@ -498,7 +498,6 @@ static int bd70528_probe(struct platform_device *pdev)
 {
        struct bd70528_rtc *bd_rtc;
        const struct rtc_class_ops *rtc_ops;
-       struct rohm_regmap_dev *parent;
        const char *irq_name;
        int ret;
        struct rtc_device *rtc;
@@ -508,20 +507,25 @@ static int bd70528_probe(struct platform_device *pdev)
        u8 hour_reg;
        enum rohm_chip_type chip = platform_get_device_id(pdev)->driver_data;
 
-       parent = dev_get_drvdata(pdev->dev.parent);
-       if (!parent) {
-               dev_err(&pdev->dev, "No MFD driver data\n");
-               return -EINVAL;
-       }
        bd_rtc = devm_kzalloc(&pdev->dev, sizeof(*bd_rtc), GFP_KERNEL);
        if (!bd_rtc)
                return -ENOMEM;
 
-       bd_rtc->parent = parent;
+       bd_rtc->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+       if (!bd_rtc->regmap) {
+               dev_err(&pdev->dev, "No regmap\n");
+               return -EINVAL;
+       }
+
        bd_rtc->dev = &pdev->dev;
 
        switch (chip) {
        case ROHM_CHIP_TYPE_BD70528:
+               bd_rtc->parent = dev_get_drvdata(pdev->dev.parent);
+               if (!bd_rtc->parent) {
+                       dev_err(&pdev->dev, "No MFD data\n");
+                       return -EINVAL;
+               }
                irq_name = "bd70528-rtc-alm";
                bd_rtc->has_rtc_timers = true;
                bd_rtc->reg_time_start = BD70528_REG_RTC_START;
@@ -529,9 +533,28 @@ static int bd70528_probe(struct platform_device *pdev)
                enable_main_irq = true;
                rtc_ops = &bd70528_rtc_ops;
                break;
+       case ROHM_CHIP_TYPE_BD71815:
+               irq_name = "bd71815-rtc-alm-0";
+               bd_rtc->reg_time_start = BD71815_REG_RTC_START;
+
+               /*
+                * See also BD718XX_ALM_EN_OFFSET:
+                * This works for BD71828 and BD71815 as they have same offset
+                * between ALM0 start and ALM0_MASK. If new ICs are to be
+                * added this requires proper check as ALM0_MASK is not located
+                * at the end of ALM0 block - but after all ALM blocks so if
+                * amount of ALMs differ the offset to enable/disable is likely
+                * to be incorrect and enable/disable must be given as own
+                * reg address here.
+                */
+               bd_rtc->bd718xx_alm_block_start = BD71815_REG_RTC_ALM_START;
+               hour_reg = BD71815_REG_HOUR;
+               rtc_ops = &bd71828_rtc_ops;
+               break;
        case ROHM_CHIP_TYPE_BD71828:
                irq_name = "bd71828-rtc-alm-0";
                bd_rtc->reg_time_start = BD71828_REG_RTC_START;
+               bd_rtc->bd718xx_alm_block_start = BD71828_REG_RTC_ALM_START;
                hour_reg = BD71828_REG_RTC_HOUR;
                rtc_ops = &bd71828_rtc_ops;
                break;
@@ -547,7 +570,7 @@ static int bd70528_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, bd_rtc);
 
-       ret = regmap_read(parent->regmap, hour_reg, &hr);
+       ret = regmap_read(bd_rtc->regmap, hour_reg, &hr);
 
        if (ret) {
                dev_err(&pdev->dev, "Failed to reag RTC clock\n");
@@ -595,7 +618,7 @@ static int bd70528_probe(struct platform_device *pdev)
         *  from sub-registers when IRQ is disabled or freed.
         */
        if (enable_main_irq) {
-               ret = regmap_update_bits(parent->regmap,
+               ret = regmap_update_bits(bd_rtc->regmap,
                                 BD70528_REG_INT_MAIN_MASK,
                                 BD70528_INT_RTC_MASK, 0);
                if (ret) {
@@ -610,6 +633,7 @@ static int bd70528_probe(struct platform_device *pdev)
 static const struct platform_device_id bd718x7_rtc_id[] = {
        { "bd70528-rtc", ROHM_CHIP_TYPE_BD70528 },
        { "bd71828-rtc", ROHM_CHIP_TYPE_BD71828 },
+       { "bd71815-rtc", ROHM_CHIP_TYPE_BD71815 },
        { },
 };
 MODULE_DEVICE_TABLE(platform, bd718x7_rtc_id);
index 28c04a4..3a945ab 100644 (file)
@@ -63,7 +63,6 @@ void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *);
 MODULE_AUTHOR("Holger Smolinski <Holger.Smolinski@de.ibm.com>");
 MODULE_DESCRIPTION("Linux on S/390 DASD device driver,"
                   " Copyright IBM Corp. 2000");
-MODULE_SUPPORTED_DEVICE("dasd");
 MODULE_LICENSE("GPL");
 
 /*
@@ -3052,7 +3051,8 @@ static blk_status_t do_dasd_request(struct blk_mq_hw_ctx *hctx,
 
        basedev = block->base;
        spin_lock_irq(&dq->lock);
-       if (basedev->state < DASD_STATE_READY) {
+       if (basedev->state < DASD_STATE_READY ||
+           test_bit(DASD_FLAG_OFFLINE, &basedev->flags)) {
                DBF_DEV_EVENT(DBF_ERR, basedev,
                              "device not ready for request %p", req);
                rc = BLK_STS_IOERR;
@@ -3487,8 +3487,6 @@ void dasd_generic_remove(struct ccw_device *cdev)
        struct dasd_device *device;
        struct dasd_block *block;
 
-       cdev->handler = NULL;
-
        device = dasd_device_from_cdev(cdev);
        if (IS_ERR(device)) {
                dasd_remove_sysfs_files(cdev);
@@ -3507,6 +3505,7 @@ void dasd_generic_remove(struct ccw_device *cdev)
         * no quite down yet.
         */
        dasd_set_target_state(device, DASD_STATE_NEW);
+       cdev->handler = NULL;
        /* dasd_delete_device destroys the device reference. */
        block = device->block;
        dasd_delete_device(device);
index 1569244..307a80f 100644 (file)
@@ -424,8 +424,10 @@ tty3270_update(struct timer_list *t)
                         * last output position matches the start address
                         * of this line.
                         */
-                       if (s->string[1] == sba[0] && s->string[2] == sba[1])
-                               str += 3, len -= 3;
+                       if (s->string[1] == sba[0] && s->string[2] == sba[1]) {
+                               str += 3;
+                               len -= 3;
+                       }
                        if (raw3270_request_add_data(wrq, str, len) != 0)
                                break;
                        list_del_init(&s->update);
index 1515fdc..bd3c724 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/debugfs.h>
+#include <linux/reboot.h>
 
 #include <asm/asm-offsets.h>
 #include <asm/ipl.h>
@@ -238,6 +239,28 @@ static int __init zcore_reipl_init(void)
        return 0;
 }
 
+static int zcore_reboot_and_on_panic_handler(struct notifier_block *self,
+                                            unsigned long         event,
+                                            void                  *data)
+{
+       if (hsa_available)
+               release_hsa();
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block zcore_reboot_notifier = {
+       .notifier_call  = zcore_reboot_and_on_panic_handler,
+       /* we need to be notified before reipl and kdump */
+       .priority       = INT_MAX,
+};
+
+static struct notifier_block zcore_on_panic_notifier = {
+       .notifier_call  = zcore_reboot_and_on_panic_handler,
+       /* we need to be notified before reipl and kdump */
+       .priority       = INT_MAX,
+};
+
 static int __init zcore_init(void)
 {
        unsigned char arch;
@@ -293,28 +316,15 @@ static int __init zcore_init(void)
                goto fail;
 
        zcore_dir = debugfs_create_dir("zcore" , NULL);
-       if (!zcore_dir) {
-               rc = -ENOMEM;
-               goto fail;
-       }
        zcore_reipl_file = debugfs_create_file("reipl", S_IRUSR, zcore_dir,
                                                NULL, &zcore_reipl_fops);
-       if (!zcore_reipl_file) {
-               rc = -ENOMEM;
-               goto fail_dir;
-       }
        zcore_hsa_file = debugfs_create_file("hsa", S_IRUSR|S_IWUSR, zcore_dir,
                                             NULL, &zcore_hsa_fops);
-       if (!zcore_hsa_file) {
-               rc = -ENOMEM;
-               goto fail_reipl_file;
-       }
-       return 0;
 
-fail_reipl_file:
-       debugfs_remove(zcore_reipl_file);
-fail_dir:
-       debugfs_remove(zcore_dir);
+       register_reboot_notifier(&zcore_reboot_notifier);
+       atomic_notifier_chain_register(&panic_notifier_list, &zcore_on_panic_notifier);
+
+       return 0;
 fail:
        diag308(DIAG308_REL_HSA, NULL);
        return rc;
index 6420b19..05e136c 100644 (file)
@@ -47,7 +47,7 @@ static void ccw_timeout_log(struct ccw_device *cdev)
        orb = &private->orb;
        cc = stsch(sch->schid, &schib);
 
-       printk(KERN_WARNING "cio: ccw device timeout occurred at %llx, "
+       printk(KERN_WARNING "cio: ccw device timeout occurred at %lx, "
               "device information:\n", get_tod_clock());
        printk(KERN_WARNING "cio: orb:\n");
        print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
index 68106be..767ac41 100644 (file)
@@ -543,7 +543,7 @@ static ssize_t vfio_ccw_mdev_ioctl(struct mdev_device *mdev,
                if (ret)
                        return ret;
 
-               return copy_to_user((void __user *)arg, &info, minsz);
+               return copy_to_user((void __user *)arg, &info, minsz) ? -EFAULT : 0;
        }
        case VFIO_DEVICE_GET_REGION_INFO:
        {
@@ -561,7 +561,7 @@ static ssize_t vfio_ccw_mdev_ioctl(struct mdev_device *mdev,
                if (ret)
                        return ret;
 
-               return copy_to_user((void __user *)arg, &info, minsz);
+               return copy_to_user((void __user *)arg, &info, minsz) ? -EFAULT : 0;
        }
        case VFIO_DEVICE_GET_IRQ_INFO:
        {
@@ -582,7 +582,7 @@ static ssize_t vfio_ccw_mdev_ioctl(struct mdev_device *mdev,
                if (info.count == -1)
                        return -EINVAL;
 
-               return copy_to_user((void __user *)arg, &info, minsz);
+               return copy_to_user((void __user *)arg, &info, minsz) ? -EFAULT : 0;
        }
        case VFIO_DEVICE_SET_IRQS:
        {
index 41fc2e4..1ffdd41 100644 (file)
@@ -1286,7 +1286,7 @@ static int vfio_ap_mdev_get_device_info(unsigned long arg)
        info.num_regions = 0;
        info.num_irqs = 0;
 
-       return copy_to_user((void __user *)arg, &info, minsz);
+       return copy_to_user((void __user *)arg, &info, minsz) ? -EFAULT : 0;
 }
 
 static ssize_t vfio_ap_mdev_ioctl(struct mdev_device *mdev,
index a1da83b..91acff4 100644 (file)
@@ -436,7 +436,7 @@ struct qeth_qdio_out_buffer {
        int is_header[QDIO_MAX_ELEMENTS_PER_BUFFER];
 
        struct qeth_qdio_out_q *q;
-       struct qeth_qdio_out_buffer *next_pending;
+       struct list_head list_entry;
 };
 
 struct qeth_card;
@@ -500,6 +500,7 @@ struct qeth_qdio_out_q {
        struct qdio_buffer *qdio_bufs[QDIO_MAX_BUFFERS_PER_Q];
        struct qeth_qdio_out_buffer *bufs[QDIO_MAX_BUFFERS_PER_Q];
        struct qdio_outbuf_state *bufstates; /* convenience pointer */
+       struct list_head pending_bufs;
        struct qeth_out_q_stats stats;
        spinlock_t lock;
        unsigned int priority;
index b71b890..a814698 100644 (file)
@@ -73,8 +73,6 @@ static void qeth_free_qdio_queues(struct qeth_card *card);
 static void qeth_notify_skbs(struct qeth_qdio_out_q *queue,
                struct qeth_qdio_out_buffer *buf,
                enum iucv_tx_notify notification);
-static void qeth_tx_complete_buf(struct qeth_qdio_out_buffer *buf, bool error,
-                                int budget);
 
 static void qeth_close_dev_handler(struct work_struct *work)
 {
@@ -465,41 +463,6 @@ static enum iucv_tx_notify qeth_compute_cq_notification(int sbalf15,
        return n;
 }
 
-static void qeth_cleanup_handled_pending(struct qeth_qdio_out_q *q, int bidx,
-                                        int forced_cleanup)
-{
-       if (q->card->options.cq != QETH_CQ_ENABLED)
-               return;
-
-       if (q->bufs[bidx]->next_pending != NULL) {
-               struct qeth_qdio_out_buffer *head = q->bufs[bidx];
-               struct qeth_qdio_out_buffer *c = q->bufs[bidx]->next_pending;
-
-               while (c) {
-                       if (forced_cleanup ||
-                           atomic_read(&c->state) == QETH_QDIO_BUF_EMPTY) {
-                               struct qeth_qdio_out_buffer *f = c;
-
-                               QETH_CARD_TEXT(f->q->card, 5, "fp");
-                               QETH_CARD_TEXT_(f->q->card, 5, "%lx", (long) f);
-                               /* release here to avoid interleaving between
-                                  outbound tasklet and inbound tasklet
-                                  regarding notifications and lifecycle */
-                               qeth_tx_complete_buf(c, forced_cleanup, 0);
-
-                               c = f->next_pending;
-                               WARN_ON_ONCE(head->next_pending != f);
-                               head->next_pending = c;
-                               kmem_cache_free(qeth_qdio_outbuf_cache, f);
-                       } else {
-                               head = c;
-                               c = c->next_pending;
-                       }
-
-               }
-       }
-}
-
 static void qeth_qdio_handle_aob(struct qeth_card *card,
                                 unsigned long phys_aob_addr)
 {
@@ -507,6 +470,7 @@ static void qeth_qdio_handle_aob(struct qeth_card *card,
        struct qaob *aob;
        struct qeth_qdio_out_buffer *buffer;
        enum iucv_tx_notify notification;
+       struct qeth_qdio_out_q *queue;
        unsigned int i;
 
        aob = (struct qaob *) phys_to_virt(phys_aob_addr);
@@ -537,7 +501,7 @@ static void qeth_qdio_handle_aob(struct qeth_card *card,
                qeth_notify_skbs(buffer->q, buffer, notification);
 
                /* Free dangling allocations. The attached skbs are handled by
-                * qeth_cleanup_handled_pending().
+                * qeth_tx_complete_pending_bufs().
                 */
                for (i = 0;
                     i < aob->sb_count && i < QETH_MAX_BUFFER_ELEMENTS(card);
@@ -549,7 +513,9 @@ static void qeth_qdio_handle_aob(struct qeth_card *card,
                        buffer->is_header[i] = 0;
                }
 
+               queue = buffer->q;
                atomic_set(&buffer->state, QETH_QDIO_BUF_EMPTY);
+               napi_schedule(&queue->napi);
                break;
        default:
                WARN_ON_ONCE(1);
@@ -1424,9 +1390,6 @@ static void qeth_tx_complete_buf(struct qeth_qdio_out_buffer *buf, bool error,
        struct qeth_qdio_out_q *queue = buf->q;
        struct sk_buff *skb;
 
-       if (atomic_read(&buf->state) == QETH_QDIO_BUF_PENDING)
-               qeth_notify_skbs(queue, buf, TX_NOTIFY_GENERALERROR);
-
        /* Empty buffer? */
        if (buf->next_element_to_fill == 0)
                return;
@@ -1488,14 +1451,38 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
        atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY);
 }
 
+static void qeth_tx_complete_pending_bufs(struct qeth_card *card,
+                                         struct qeth_qdio_out_q *queue,
+                                         bool drain)
+{
+       struct qeth_qdio_out_buffer *buf, *tmp;
+
+       list_for_each_entry_safe(buf, tmp, &queue->pending_bufs, list_entry) {
+               if (drain || atomic_read(&buf->state) == QETH_QDIO_BUF_EMPTY) {
+                       QETH_CARD_TEXT(card, 5, "fp");
+                       QETH_CARD_TEXT_(card, 5, "%lx", (long) buf);
+
+                       if (drain)
+                               qeth_notify_skbs(queue, buf,
+                                                TX_NOTIFY_GENERALERROR);
+                       qeth_tx_complete_buf(buf, drain, 0);
+
+                       list_del(&buf->list_entry);
+                       kmem_cache_free(qeth_qdio_outbuf_cache, buf);
+               }
+       }
+}
+
 static void qeth_drain_output_queue(struct qeth_qdio_out_q *q, bool free)
 {
        int j;
 
+       qeth_tx_complete_pending_bufs(q->card, q, true);
+
        for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) {
                if (!q->bufs[j])
                        continue;
-               qeth_cleanup_handled_pending(q, j, 1);
+
                qeth_clear_output_buffer(q, q->bufs[j], true, 0);
                if (free) {
                        kmem_cache_free(qeth_qdio_outbuf_cache, q->bufs[j]);
@@ -2615,7 +2602,6 @@ static int qeth_init_qdio_out_buf(struct qeth_qdio_out_q *q, int bidx)
        skb_queue_head_init(&newbuf->skb_list);
        lockdep_set_class(&newbuf->skb_list.lock, &qdio_out_skb_queue_key);
        newbuf->q = q;
-       newbuf->next_pending = q->bufs[bidx];
        atomic_set(&newbuf->state, QETH_QDIO_BUF_EMPTY);
        q->bufs[bidx] = newbuf;
        return 0;
@@ -2634,15 +2620,28 @@ static void qeth_free_output_queue(struct qeth_qdio_out_q *q)
 static struct qeth_qdio_out_q *qeth_alloc_output_queue(void)
 {
        struct qeth_qdio_out_q *q = kzalloc(sizeof(*q), GFP_KERNEL);
+       unsigned int i;
 
        if (!q)
                return NULL;
 
-       if (qdio_alloc_buffers(q->qdio_bufs, QDIO_MAX_BUFFERS_PER_Q)) {
-               kfree(q);
-               return NULL;
+       if (qdio_alloc_buffers(q->qdio_bufs, QDIO_MAX_BUFFERS_PER_Q))
+               goto err_qdio_bufs;
+
+       for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
+               if (qeth_init_qdio_out_buf(q, i))
+                       goto err_out_bufs;
        }
+
        return q;
+
+err_out_bufs:
+       while (i > 0)
+               kmem_cache_free(qeth_qdio_outbuf_cache, q->bufs[--i]);
+       qdio_free_buffers(q->qdio_bufs, QDIO_MAX_BUFFERS_PER_Q);
+err_qdio_bufs:
+       kfree(q);
+       return NULL;
 }
 
 static void qeth_tx_completion_timer(struct timer_list *timer)
@@ -2655,7 +2654,7 @@ static void qeth_tx_completion_timer(struct timer_list *timer)
 
 static int qeth_alloc_qdio_queues(struct qeth_card *card)
 {
-       int i, j;
+       unsigned int i;
 
        QETH_CARD_TEXT(card, 2, "allcqdbf");
 
@@ -2684,18 +2683,12 @@ static int qeth_alloc_qdio_queues(struct qeth_card *card)
                card->qdio.out_qs[i] = queue;
                queue->card = card;
                queue->queue_no = i;
+               INIT_LIST_HEAD(&queue->pending_bufs);
                spin_lock_init(&queue->lock);
                timer_setup(&queue->timer, qeth_tx_completion_timer, 0);
                queue->coalesce_usecs = QETH_TX_COALESCE_USECS;
                queue->max_coalesced_frames = QETH_TX_MAX_COALESCED_FRAMES;
                queue->priority = QETH_QIB_PQUE_PRIO_DEFAULT;
-
-               /* give outbound qeth_qdio_buffers their qdio_buffers */
-               for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) {
-                       WARN_ON(queue->bufs[j]);
-                       if (qeth_init_qdio_out_buf(queue, j))
-                               goto out_freeoutqbufs;
-               }
        }
 
        /* completion */
@@ -2704,13 +2697,6 @@ static int qeth_alloc_qdio_queues(struct qeth_card *card)
 
        return 0;
 
-out_freeoutqbufs:
-       while (j > 0) {
-               --j;
-               kmem_cache_free(qeth_qdio_outbuf_cache,
-                               card->qdio.out_qs[i]->bufs[j]);
-               card->qdio.out_qs[i]->bufs[j] = NULL;
-       }
 out_freeoutq:
        while (i > 0) {
                qeth_free_output_queue(card->qdio.out_qs[--i]);
@@ -6107,6 +6093,8 @@ static void qeth_iqd_tx_complete(struct qeth_qdio_out_q *queue,
                                        qeth_schedule_recovery(card);
                                }
 
+                               list_add(&buffer->list_entry,
+                                        &queue->pending_bufs);
                                /* Skip clearing the buffer: */
                                return;
                        case QETH_QDIO_BUF_QAOB_OK:
@@ -6162,6 +6150,8 @@ static int qeth_tx_poll(struct napi_struct *napi, int budget)
                unsigned int bytes = 0;
                int completed;
 
+               qeth_tx_complete_pending_bufs(card, queue, false);
+
                if (qeth_out_queue_is_empty(queue)) {
                        napi_complete(napi);
                        return 0;
@@ -6194,7 +6184,6 @@ static int qeth_tx_poll(struct napi_struct *napi, int budget)
 
                        qeth_handle_send_error(card, buffer, error);
                        qeth_iqd_tx_complete(queue, bidx, error, budget);
-                       qeth_cleanup_handled_pending(queue, bidx, false);
                }
 
                netdev_tx_completed_queue(txq, packets, bytes);
@@ -7249,9 +7238,7 @@ int qeth_open(struct net_device *dev)
        card->data.state = CH_STATE_UP;
        netif_tx_start_all_queues(dev);
 
-       napi_enable(&card->napi);
        local_bh_disable();
-       napi_schedule(&card->napi);
        if (IS_IQD(card)) {
                struct qeth_qdio_out_q *queue;
                unsigned int i;
@@ -7263,8 +7250,12 @@ int qeth_open(struct net_device *dev)
                        napi_schedule(&queue->napi);
                }
        }
+
+       napi_enable(&card->napi);
+       napi_schedule(&card->napi);
        /* kick-start the NAPI softirq: */
        local_bh_enable();
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(qeth_open);
@@ -7274,6 +7265,11 @@ int qeth_stop(struct net_device *dev)
        struct qeth_card *card = dev->ml_priv;
 
        QETH_CARD_TEXT(card, 4, "qethstop");
+
+       napi_disable(&card->napi);
+       cancel_delayed_work_sync(&card->buffer_reclaim_work);
+       qdio_stop_irq(CARD_DDEV(card));
+
        if (IS_IQD(card)) {
                struct qeth_qdio_out_q *queue;
                unsigned int i;
@@ -7294,10 +7290,6 @@ int qeth_stop(struct net_device *dev)
                netif_tx_disable(dev);
        }
 
-       napi_disable(&card->napi);
-       cancel_delayed_work_sync(&card->buffer_reclaim_work);
-       qdio_stop_irq(CARD_DDEV(card));
-
        return 0;
 }
 EXPORT_SYMBOL_GPL(qeth_stop);
index 00e72b9..d93595b 100644 (file)
@@ -50,7 +50,6 @@ MODULE_PARM_DESC(sol_compat,
 MODULE_AUTHOR("Eric Brower <ebrower@usa.net>");
 MODULE_DESCRIPTION("7-Segment Display driver for Sun Microsystems CP1400/1500");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("d7s");
 
 struct d7s {
        void __iomem    *regs;
index 3836976..f135a10 100644 (file)
@@ -80,7 +80,6 @@
 MODULE_AUTHOR("Hewlett-Packard Company");
 MODULE_DESCRIPTION("Driver for HP Smart Array Controller version " \
        HPSA_DRIVER_VERSION);
-MODULE_SUPPORTED_DEVICE("HP Smart Array Controllers");
 MODULE_VERSION(HPSA_DRIVER_VERSION);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("cciss");
index 755313b..f140eaf 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/bsg-lib.h>
 #include <asm/firmware.h>
 #include <asm/irq.h>
+#include <asm/rtas.h>
 #include <asm/vio.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -158,6 +159,9 @@ static void ibmvfc_npiv_logout(struct ibmvfc_host *);
 static void ibmvfc_tgt_implicit_logout_and_del(struct ibmvfc_target *);
 static void ibmvfc_tgt_move_login(struct ibmvfc_target *);
 
+static void ibmvfc_release_sub_crqs(struct ibmvfc_host *);
+static void ibmvfc_init_sub_crqs(struct ibmvfc_host *);
+
 static const char *unknown_error = "unknown error";
 
 static long h_reg_sub_crq(unsigned long unit_address, unsigned long ioba,
@@ -899,6 +903,9 @@ static int ibmvfc_reenable_crq_queue(struct ibmvfc_host *vhost)
 {
        int rc = 0;
        struct vio_dev *vdev = to_vio_dev(vhost->dev);
+       unsigned long flags;
+
+       ibmvfc_release_sub_crqs(vhost);
 
        /* Re-enable the CRQ */
        do {
@@ -910,6 +917,15 @@ static int ibmvfc_reenable_crq_queue(struct ibmvfc_host *vhost)
        if (rc)
                dev_err(vhost->dev, "Error enabling adapter (rc=%d)\n", rc);
 
+       spin_lock_irqsave(vhost->host->host_lock, flags);
+       spin_lock(vhost->crq.q_lock);
+       vhost->do_enquiry = 1;
+       vhost->using_channels = 0;
+       spin_unlock(vhost->crq.q_lock);
+       spin_unlock_irqrestore(vhost->host->host_lock, flags);
+
+       ibmvfc_init_sub_crqs(vhost);
+
        return rc;
 }
 
@@ -926,8 +942,8 @@ static int ibmvfc_reset_crq(struct ibmvfc_host *vhost)
        unsigned long flags;
        struct vio_dev *vdev = to_vio_dev(vhost->dev);
        struct ibmvfc_queue *crq = &vhost->crq;
-       struct ibmvfc_queue *scrq;
-       int i;
+
+       ibmvfc_release_sub_crqs(vhost);
 
        /* Close the CRQ */
        do {
@@ -947,16 +963,6 @@ static int ibmvfc_reset_crq(struct ibmvfc_host *vhost)
        memset(crq->msgs.crq, 0, PAGE_SIZE);
        crq->cur = 0;
 
-       if (vhost->scsi_scrqs.scrqs) {
-               for (i = 0; i < nr_scsi_hw_queues; i++) {
-                       scrq = &vhost->scsi_scrqs.scrqs[i];
-                       spin_lock(scrq->q_lock);
-                       memset(scrq->msgs.scrq, 0, PAGE_SIZE);
-                       scrq->cur = 0;
-                       spin_unlock(scrq->q_lock);
-               }
-       }
-
        /* And re-open it again */
        rc = plpar_hcall_norets(H_REG_CRQ, vdev->unit_address,
                                crq->msg_token, PAGE_SIZE);
@@ -966,9 +972,12 @@ static int ibmvfc_reset_crq(struct ibmvfc_host *vhost)
                dev_warn(vhost->dev, "Partner adapter not ready\n");
        else if (rc != 0)
                dev_warn(vhost->dev, "Couldn't register crq (rc=%d)\n", rc);
+
        spin_unlock(vhost->crq.q_lock);
        spin_unlock_irqrestore(vhost->host->host_lock, flags);
 
+       ibmvfc_init_sub_crqs(vhost);
+
        return rc;
 }
 
@@ -5642,7 +5651,8 @@ static int ibmvfc_register_scsi_channel(struct ibmvfc_host *vhost,
        rc = h_reg_sub_crq(vdev->unit_address, scrq->msg_token, PAGE_SIZE,
                           &scrq->cookie, &scrq->hw_irq);
 
-       if (rc) {
+       /* H_CLOSED indicates successful register, but no CRQ partner */
+       if (rc && rc != H_CLOSED) {
                dev_warn(dev, "Error registering sub-crq: %d\n", rc);
                if (rc == H_PARAMETER)
                        dev_warn_once(dev, "Firmware may not support MQ\n");
@@ -5675,8 +5685,8 @@ static int ibmvfc_register_scsi_channel(struct ibmvfc_host *vhost,
 
 irq_failed:
        do {
-               plpar_hcall_norets(H_FREE_SUB_CRQ, vdev->unit_address, scrq->cookie);
-       } while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
+               rc = plpar_hcall_norets(H_FREE_SUB_CRQ, vdev->unit_address, scrq->cookie);
+       } while (rtas_busy_delay(rc));
 reg_failed:
        ibmvfc_free_queue(vhost, scrq);
        LEAVE;
@@ -5694,6 +5704,7 @@ static void ibmvfc_deregister_scsi_channel(struct ibmvfc_host *vhost, int index)
 
        free_irq(scrq->irq, scrq);
        irq_dispose_mapping(scrq->irq);
+       scrq->irq = 0;
 
        do {
                rc = plpar_hcall_norets(H_FREE_SUB_CRQ, vdev->unit_address,
@@ -5707,17 +5718,21 @@ static void ibmvfc_deregister_scsi_channel(struct ibmvfc_host *vhost, int index)
        LEAVE;
 }
 
-static int ibmvfc_init_sub_crqs(struct ibmvfc_host *vhost)
+static void ibmvfc_init_sub_crqs(struct ibmvfc_host *vhost)
 {
        int i, j;
 
        ENTER;
+       if (!vhost->mq_enabled)
+               return;
 
        vhost->scsi_scrqs.scrqs = kcalloc(nr_scsi_hw_queues,
                                          sizeof(*vhost->scsi_scrqs.scrqs),
                                          GFP_KERNEL);
-       if (!vhost->scsi_scrqs.scrqs)
-               return -1;
+       if (!vhost->scsi_scrqs.scrqs) {
+               vhost->do_enquiry = 0;
+               return;
+       }
 
        for (i = 0; i < nr_scsi_hw_queues; i++) {
                if (ibmvfc_register_scsi_channel(vhost, i)) {
@@ -5726,13 +5741,12 @@ static int ibmvfc_init_sub_crqs(struct ibmvfc_host *vhost)
                        kfree(vhost->scsi_scrqs.scrqs);
                        vhost->scsi_scrqs.scrqs = NULL;
                        vhost->scsi_scrqs.active_queues = 0;
-                       LEAVE;
-                       return -1;
+                       vhost->do_enquiry = 0;
+                       break;
                }
        }
 
        LEAVE;
-       return 0;
 }
 
 static void ibmvfc_release_sub_crqs(struct ibmvfc_host *vhost)
@@ -5770,6 +5784,8 @@ static void ibmvfc_free_mem(struct ibmvfc_host *vhost)
                          vhost->disc_buf_dma);
        dma_free_coherent(vhost->dev, sizeof(*vhost->login_buf),
                          vhost->login_buf, vhost->login_buf_dma);
+       dma_free_coherent(vhost->dev, sizeof(*vhost->channel_setup_buf),
+                         vhost->channel_setup_buf, vhost->channel_setup_dma);
        dma_pool_destroy(vhost->sg_pool);
        ibmvfc_free_queue(vhost, async_q);
        LEAVE;
@@ -5999,11 +6015,7 @@ static int ibmvfc_probe(struct vio_dev *vdev, const struct vio_device_id *id)
                goto remove_shost;
        }
 
-       if (vhost->mq_enabled) {
-               rc = ibmvfc_init_sub_crqs(vhost);
-               if (rc)
-                       dev_warn(dev, "Failed to allocate Sub-CRQs. rc=%d\n", rc);
-       }
+       ibmvfc_init_sub_crqs(vhost);
 
        if (shost_to_fc_host(shost)->rqst_q)
                blk_queue_max_segments(shost_to_fc_host(shost)->rqst_q, 1);
@@ -6038,7 +6050,7 @@ out:
  * Return value:
  *     0
  **/
-static int ibmvfc_remove(struct vio_dev *vdev)
+static void ibmvfc_remove(struct vio_dev *vdev)
 {
        struct ibmvfc_host *vhost = dev_get_drvdata(&vdev->dev);
        LIST_HEAD(purge);
@@ -6070,7 +6082,6 @@ static int ibmvfc_remove(struct vio_dev *vdev)
        spin_unlock(&ibmvfc_driver_lock);
        scsi_host_put(vhost->host);
        LEAVE;
-       return 0;
 }
 
 /**
index 29fcc44..77fafb1 100644 (file)
@@ -2335,7 +2335,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        return -1;
 }
 
-static int ibmvscsi_remove(struct vio_dev *vdev)
+static void ibmvscsi_remove(struct vio_dev *vdev)
 {
        struct ibmvscsi_host_data *hostdata = dev_get_drvdata(&vdev->dev);
 
@@ -2356,8 +2356,6 @@ static int ibmvscsi_remove(struct vio_dev *vdev)
        spin_unlock(&ibmvscsi_driver_lock);
 
        scsi_host_put(hostdata->host);
-
-       return 0;
 }
 
 /**
index cc3908c..9abd9e2 100644 (file)
@@ -3595,7 +3595,7 @@ free_adapter:
        return rc;
 }
 
-static int ibmvscsis_remove(struct vio_dev *vdev)
+static void ibmvscsis_remove(struct vio_dev *vdev)
 {
        struct scsi_info *vscsi = dev_get_drvdata(&vdev->dev);
 
@@ -3622,8 +3622,6 @@ static int ibmvscsis_remove(struct vio_dev *vdev)
        list_del(&vscsi->list);
        spin_unlock_bh(&ibmvscsis_dev_lock);
        kfree(vscsi);
-
-       return 0;
 }
 
 static ssize_t system_id_show(struct device *dev,
index bc79a01..46a8f2d 100644 (file)
@@ -2421,7 +2421,7 @@ lpfc_debugfs_dif_err_write(struct file *file, const char __user *buf,
        memset(dstbuf, 0, 33);
        size = (nbytes < 32) ? nbytes : 32;
        if (copy_from_user(dstbuf, buf, size))
-               return 0;
+               return -EFAULT;
 
        if (dent == phba->debug_InjErrLBA) {
                if ((dstbuf[0] == 'o') && (dstbuf[1] == 'f') &&
@@ -2430,7 +2430,7 @@ lpfc_debugfs_dif_err_write(struct file *file, const char __user *buf,
        }
 
        if ((tmp == 0) && (kstrtoull(dstbuf, 0, &tmp)))
-               return 0;
+               return -EINVAL;
 
        if (dent == phba->debug_writeGuard)
                phba->lpfc_injerr_wgrd_cnt = (uint32_t)tmp;
index ffca030..6aa6de7 100644 (file)
@@ -413,7 +413,7 @@ mpt3sas_get_port_by_id(struct MPT3SAS_ADAPTER *ioc,
         * And add this object to port_table_list.
         */
        if (!ioc->multipath_on_hba) {
-               port = kzalloc(sizeof(struct hba_port), GFP_KERNEL);
+               port = kzalloc(sizeof(struct hba_port), GFP_ATOMIC);
                if (!port)
                        return NULL;
 
index 4adf9de..329fd02 100644 (file)
@@ -2273,12 +2273,12 @@ static void myrs_cleanup(struct myrs_hba *cs)
        if (cs->mmio_base) {
                cs->disable_intr(cs);
                iounmap(cs->mmio_base);
+               cs->mmio_base = NULL;
        }
        if (cs->irq)
                free_irq(cs->irq, cs);
        if (cs->io_addr)
                release_region(cs->io_addr, 0x80);
-       iounmap(cs->mmio_base);
        pci_set_drvdata(pdev, NULL);
        pci_disable_device(pdev);
        scsi_host_put(cs->host);
index 5d5f50d..ac89002 100644 (file)
@@ -55,7 +55,6 @@
 
 MODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>");
 MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module");
-MODULE_SUPPORTED_DEVICE("sd,sr,sg,st");
 MODULE_LICENSE("GPL");
 
 #include "nsp_io.h"
index 10e5e6c..01620f3 100644 (file)
        (min(1270, ((ql) > 0) ? (QLA_TGT_DATASEGS_PER_CMD_24XX + \
                QLA_TGT_DATASEGS_PER_CONT_24XX*((ql) - 1)) : 0))
 #endif
-#endif
 
 #define GET_TARGET_ID(ha, iocb) ((HAS_EXTENDED_IDS(ha))                        \
                         ? le16_to_cpu((iocb)->u.isp2x.target.extended) \
@@ -244,6 +243,7 @@ struct ctio_to_2xxx {
 #ifndef CTIO_RET_TYPE
 #define CTIO_RET_TYPE  0x17            /* CTIO return entry */
 #define ATIO_TYPE7 0x06 /* Accept target I/O entry for 24xx */
+#endif
 
 struct fcp_hdr {
        uint8_t  r_ctl;
index ee55867..994f1b8 100644 (file)
@@ -280,27 +280,28 @@ static int sd_zbc_update_wp_offset_cb(struct blk_zone *zone, unsigned int idx,
 static void sd_zbc_update_wp_offset_workfn(struct work_struct *work)
 {
        struct scsi_disk *sdkp;
+       unsigned long flags;
        unsigned int zno;
        int ret;
 
        sdkp = container_of(work, struct scsi_disk, zone_wp_offset_work);
 
-       spin_lock_bh(&sdkp->zones_wp_offset_lock);
+       spin_lock_irqsave(&sdkp->zones_wp_offset_lock, flags);
        for (zno = 0; zno < sdkp->nr_zones; zno++) {
                if (sdkp->zones_wp_offset[zno] != SD_ZBC_UPDATING_WP_OFST)
                        continue;
 
-               spin_unlock_bh(&sdkp->zones_wp_offset_lock);
+               spin_unlock_irqrestore(&sdkp->zones_wp_offset_lock, flags);
                ret = sd_zbc_do_report_zones(sdkp, sdkp->zone_wp_update_buf,
                                             SD_BUF_SIZE,
                                             zno * sdkp->zone_blocks, true);
-               spin_lock_bh(&sdkp->zones_wp_offset_lock);
+               spin_lock_irqsave(&sdkp->zones_wp_offset_lock, flags);
                if (!ret)
                        sd_zbc_parse_report(sdkp, sdkp->zone_wp_update_buf + 64,
                                            zno, sd_zbc_update_wp_offset_cb,
                                            sdkp);
        }
-       spin_unlock_bh(&sdkp->zones_wp_offset_lock);
+       spin_unlock_irqrestore(&sdkp->zones_wp_offset_lock, flags);
 
        scsi_device_put(sdkp->device);
 }
@@ -324,6 +325,7 @@ blk_status_t sd_zbc_prepare_zone_append(struct scsi_cmnd *cmd, sector_t *lba,
        struct request *rq = cmd->request;
        struct scsi_disk *sdkp = scsi_disk(rq->rq_disk);
        unsigned int wp_offset, zno = blk_rq_zone_no(rq);
+       unsigned long flags;
        blk_status_t ret;
 
        ret = sd_zbc_cmnd_checks(cmd);
@@ -337,7 +339,7 @@ blk_status_t sd_zbc_prepare_zone_append(struct scsi_cmnd *cmd, sector_t *lba,
        if (!blk_req_zone_write_trylock(rq))
                return BLK_STS_ZONE_RESOURCE;
 
-       spin_lock_bh(&sdkp->zones_wp_offset_lock);
+       spin_lock_irqsave(&sdkp->zones_wp_offset_lock, flags);
        wp_offset = sdkp->zones_wp_offset[zno];
        switch (wp_offset) {
        case SD_ZBC_INVALID_WP_OFST:
@@ -366,7 +368,7 @@ blk_status_t sd_zbc_prepare_zone_append(struct scsi_cmnd *cmd, sector_t *lba,
 
                *lba += wp_offset;
        }
-       spin_unlock_bh(&sdkp->zones_wp_offset_lock);
+       spin_unlock_irqrestore(&sdkp->zones_wp_offset_lock, flags);
        if (ret)
                blk_req_zone_write_unlock(rq);
        return ret;
@@ -445,6 +447,7 @@ static unsigned int sd_zbc_zone_wp_update(struct scsi_cmnd *cmd,
        struct scsi_disk *sdkp = scsi_disk(rq->rq_disk);
        unsigned int zno = blk_rq_zone_no(rq);
        enum req_opf op = req_op(rq);
+       unsigned long flags;
 
        /*
         * If we got an error for a command that needs updating the write
@@ -452,7 +455,7 @@ static unsigned int sd_zbc_zone_wp_update(struct scsi_cmnd *cmd,
         * invalid to force an update from disk the next time a zone append
         * command is issued.
         */
-       spin_lock_bh(&sdkp->zones_wp_offset_lock);
+       spin_lock_irqsave(&sdkp->zones_wp_offset_lock, flags);
 
        if (result && op != REQ_OP_ZONE_RESET_ALL) {
                if (op == REQ_OP_ZONE_APPEND) {
@@ -496,7 +499,7 @@ static unsigned int sd_zbc_zone_wp_update(struct scsi_cmnd *cmd,
        }
 
 unlock_wp_offset:
-       spin_unlock_bh(&sdkp->zones_wp_offset_lock);
+       spin_unlock_irqrestore(&sdkp->zones_wp_offset_lock, flags);
 
        return good_bytes;
 }
index c53f456..a1dacb6 100644 (file)
@@ -48,7 +48,6 @@
 MODULE_AUTHOR("Microsemi");
 MODULE_DESCRIPTION("Driver for Microsemi Smart Family Controller version "
        DRIVER_VERSION);
-MODULE_SUPPORTED_DEVICE("Microsemi Smart Family Controllers");
 MODULE_VERSION(DRIVER_VERSION);
 MODULE_LICENSE("GPL");
 
index 841ad2f..9ca536a 100644 (file)
@@ -1269,8 +1269,8 @@ static int st_open(struct inode *inode, struct file *filp)
        spin_lock(&st_use_lock);
        if (STp->in_use) {
                spin_unlock(&st_use_lock);
-               scsi_tape_put(STp);
                DEBC_printk(STp, "Device already in use.\n");
+               scsi_tape_put(STp);
                return (-EBUSY);
        }
 
index c55202b..a981f26 100644 (file)
@@ -911,7 +911,7 @@ static void ufs_mtk_vreg_set_lpm(struct ufs_hba *hba, bool lpm)
        if (!hba->vreg_info.vccq2 || !hba->vreg_info.vcc)
                return;
 
-       if (lpm & !hba->vreg_info.vcc->enabled)
+       if (lpm && !hba->vreg_info.vcc->enabled)
                regulator_set_mode(hba->vreg_info.vccq2->reg,
                                   REGULATOR_MODE_IDLE);
        else if (!lpm)
index f97d7b0..a9dc8d7 100644 (file)
@@ -253,12 +253,17 @@ static int ufs_qcom_host_reset(struct ufs_hba *hba)
 {
        int ret = 0;
        struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+       bool reenable_intr = false;
 
        if (!host->core_reset) {
                dev_warn(hba->dev, "%s: reset control not set\n", __func__);
                goto out;
        }
 
+       reenable_intr = hba->is_irq_enabled;
+       disable_irq(hba->irq);
+       hba->is_irq_enabled = false;
+
        ret = reset_control_assert(host->core_reset);
        if (ret) {
                dev_err(hba->dev, "%s: core_reset assert failed, err = %d\n",
@@ -280,6 +285,11 @@ static int ufs_qcom_host_reset(struct ufs_hba *hba)
 
        usleep_range(1000, 1100);
 
+       if (reenable_intr) {
+               enable_irq(hba->irq);
+               hba->is_irq_enabled = true;
+       }
+
 out:
        return ret;
 }
index 7716175..c867607 100644 (file)
@@ -95,8 +95,6 @@
                       16, 4, buf, __len, false);                        \
 } while (0)
 
-static bool early_suspend;
-
 int ufshcd_dump_regs(struct ufs_hba *hba, size_t offset, size_t len,
                     const char *prefix)
 {
@@ -1535,7 +1533,7 @@ static ssize_t ufshcd_clkscale_enable_show(struct device *dev,
 {
        struct ufs_hba *hba = dev_get_drvdata(dev);
 
-       return snprintf(buf, PAGE_SIZE, "%d\n", hba->clk_scaling.is_enabled);
+       return sysfs_emit(buf, "%d\n", hba->clk_scaling.is_enabled);
 }
 
 static ssize_t ufshcd_clkscale_enable_store(struct device *dev,
@@ -4987,6 +4985,7 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
                         * UFS device needs urgent BKOPs.
                         */
                        if (!hba->pm_op_in_progress &&
+                           !ufshcd_eh_in_progress(hba) &&
                            ufshcd_is_exception_event(lrbp->ucd_rsp_ptr) &&
                            schedule_work(&hba->eeh_work)) {
                                /*
@@ -5784,13 +5783,20 @@ static void ufshcd_err_handling_prepare(struct ufs_hba *hba)
                        ufshcd_suspend_clkscaling(hba);
                ufshcd_clk_scaling_allow(hba, false);
        }
+       ufshcd_scsi_block_requests(hba);
+       /* Drain ufshcd_queuecommand() */
+       down_write(&hba->clk_scaling_lock);
+       up_write(&hba->clk_scaling_lock);
+       cancel_work_sync(&hba->eeh_work);
 }
 
 static void ufshcd_err_handling_unprepare(struct ufs_hba *hba)
 {
+       ufshcd_scsi_unblock_requests(hba);
        ufshcd_release(hba);
        if (ufshcd_is_clkscaling_supported(hba))
                ufshcd_clk_scaling_suspend(hba, false);
+       ufshcd_clear_ua_wluns(hba);
        pm_runtime_put(hba->dev);
 }
 
@@ -5882,8 +5888,8 @@ static void ufshcd_err_handler(struct work_struct *work)
        spin_unlock_irqrestore(hba->host->host_lock, flags);
        ufshcd_err_handling_prepare(hba);
        spin_lock_irqsave(hba->host->host_lock, flags);
-       ufshcd_scsi_block_requests(hba);
-       hba->ufshcd_state = UFSHCD_STATE_RESET;
+       if (hba->ufshcd_state != UFSHCD_STATE_ERROR)
+               hba->ufshcd_state = UFSHCD_STATE_RESET;
 
        /* Complete requests that have door-bell cleared by h/w */
        ufshcd_complete_requests(hba);
@@ -6042,12 +6048,8 @@ skip_err_handling:
        }
        ufshcd_clear_eh_in_progress(hba);
        spin_unlock_irqrestore(hba->host->host_lock, flags);
-       ufshcd_scsi_unblock_requests(hba);
        ufshcd_err_handling_unprepare(hba);
        up(&hba->host_sem);
-
-       if (!err && needs_reset)
-               ufshcd_clear_ua_wluns(hba);
 }
 
 /**
@@ -7858,6 +7860,8 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool async)
        unsigned long flags;
        ktime_t start = ktime_get();
 
+       hba->ufshcd_state = UFSHCD_STATE_RESET;
+
        ret = ufshcd_link_startup(hba);
        if (ret)
                goto out;
@@ -8972,11 +8976,6 @@ int ufshcd_system_suspend(struct ufs_hba *hba)
        int ret = 0;
        ktime_t start = ktime_get();
 
-       if (!hba) {
-               early_suspend = true;
-               return 0;
-       }
-
        down(&hba->host_sem);
 
        if (!hba->is_powered)
@@ -9028,14 +9027,6 @@ int ufshcd_system_resume(struct ufs_hba *hba)
        int ret = 0;
        ktime_t start = ktime_get();
 
-       if (!hba)
-               return -EINVAL;
-
-       if (unlikely(early_suspend)) {
-               early_suspend = false;
-               down(&hba->host_sem);
-       }
-
        if (!hba->is_powered || pm_runtime_suspended(hba->dev))
                /*
                 * Let the runtime resume take care of resuming
@@ -9068,9 +9059,6 @@ int ufshcd_runtime_suspend(struct ufs_hba *hba)
        int ret = 0;
        ktime_t start = ktime_get();
 
-       if (!hba)
-               return -EINVAL;
-
        if (!hba->is_powered)
                goto out;
        else
@@ -9109,9 +9097,6 @@ int ufshcd_runtime_resume(struct ufs_hba *hba)
        int ret = 0;
        ktime_t start = ktime_get();
 
-       if (!hba)
-               return -EINVAL;
-
        if (!hba->is_powered)
                goto out;
        else
index 081f54a..8a79605 100644 (file)
@@ -17,8 +17,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Maintained by: Jim Gill <jgill@vmware.com>
- *
  */
 
 #include <linux/kernel.h>
index 75966d3..51a82f7 100644 (file)
@@ -17,8 +17,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Maintained by: Jim Gill <jgill@vmware.com>
- *
  */
 
 #ifndef _VMW_PVSCSI_H_
index e5d7fb8..bd0fbcd 100644 (file)
@@ -30,7 +30,6 @@
 MODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk>");
 MODULE_DESCRIPTION("Maple bus driver for Dreamcast");
 MODULE_LICENSE("GPL v2");
-MODULE_SUPPORTED_DEVICE("{{SEGA, Dreamcast/Maple}}");
 
 static void maple_dma_handler(struct work_struct *work);
 static void maple_vblank_handler(struct work_struct *work);
index 442cc7c..52ddb32 100644 (file)
@@ -1433,6 +1433,7 @@ static int cqspi_probe(struct platform_device *pdev)
        cqspi = spi_master_get_devdata(master);
 
        cqspi->pdev = pdev;
+       platform_set_drvdata(pdev, cqspi);
 
        /* Obtain configuration from OF. */
        ret = cqspi_of_get_pdata(cqspi);
index 35b75f0..81a246f 100644 (file)
@@ -260,6 +260,7 @@ static irqreturn_t apci1032_interrupt(int irq, void *d)
        struct apci1032_private *devpriv = dev->private;
        struct comedi_subdevice *s = dev->read_subdev;
        unsigned int ctrl;
+       unsigned short val;
 
        /* check interrupt is from this device */
        if ((inl(devpriv->amcc_iobase + AMCC_OP_REG_INTCSR) &
@@ -275,7 +276,8 @@ static irqreturn_t apci1032_interrupt(int irq, void *d)
        outl(ctrl & ~APCI1032_CTRL_INT_ENA, dev->iobase + APCI1032_CTRL_REG);
 
        s->state = inl(dev->iobase + APCI1032_STATUS_REG) & 0xffff;
-       comedi_buf_write_samples(s, &s->state, 1);
+       val = s->state;
+       comedi_buf_write_samples(s, &val, 1);
        comedi_handle_events(dev, s);
 
        /* enable the interrupt */
index 11efb21..b04c15d 100644 (file)
@@ -208,7 +208,7 @@ static irqreturn_t apci1500_interrupt(int irq, void *d)
        struct comedi_device *dev = d;
        struct apci1500_private *devpriv = dev->private;
        struct comedi_subdevice *s = dev->read_subdev;
-       unsigned int status = 0;
+       unsigned short status = 0;
        unsigned int val;
 
        val = inl(devpriv->amcc + AMCC_OP_REG_INTCSR);
@@ -238,14 +238,14 @@ static irqreturn_t apci1500_interrupt(int irq, void *d)
         *
         *    Mask     Meaning
         * ----------  ------------------------------------------
-        * 0x00000001  Event 1 has occurred
-        * 0x00000010  Event 2 has occurred
-        * 0x00000100  Counter/timer 1 has run down (not implemented)
-        * 0x00001000  Counter/timer 2 has run down (not implemented)
-        * 0x00010000  Counter 3 has run down (not implemented)
-        * 0x00100000  Watchdog has run down (not implemented)
-        * 0x01000000  Voltage error
-        * 0x10000000  Short-circuit error
+        * 0b00000001  Event 1 has occurred
+        * 0b00000010  Event 2 has occurred
+        * 0b00000100  Counter/timer 1 has run down (not implemented)
+        * 0b00001000  Counter/timer 2 has run down (not implemented)
+        * 0b00010000  Counter 3 has run down (not implemented)
+        * 0b00100000  Watchdog has run down (not implemented)
+        * 0b01000000  Voltage error
+        * 0b10000000  Short-circuit error
         */
        comedi_buf_write_samples(s, &status, 1);
        comedi_handle_events(dev, s);
index 692893c..0906077 100644 (file)
@@ -300,11 +300,11 @@ static int pci1710_ai_eoc(struct comedi_device *dev,
 static int pci1710_ai_read_sample(struct comedi_device *dev,
                                  struct comedi_subdevice *s,
                                  unsigned int cur_chan,
-                                 unsigned int *val)
+                                 unsigned short *val)
 {
        const struct boardtype *board = dev->board_ptr;
        struct pci1710_private *devpriv = dev->private;
-       unsigned int sample;
+       unsigned short sample;
        unsigned int chan;
 
        sample = inw(dev->iobase + PCI171X_AD_DATA_REG);
@@ -345,7 +345,7 @@ static int pci1710_ai_insn_read(struct comedi_device *dev,
        pci1710_ai_setup_chanlist(dev, s, &insn->chanspec, 1, 1);
 
        for (i = 0; i < insn->n; i++) {
-               unsigned int val;
+               unsigned short val;
 
                /* start conversion */
                outw(0, dev->iobase + PCI171X_SOFTTRG_REG);
@@ -395,7 +395,7 @@ static void pci1710_handle_every_sample(struct comedi_device *dev,
 {
        struct comedi_cmd *cmd = &s->async->cmd;
        unsigned int status;
-       unsigned int val;
+       unsigned short val;
        int ret;
 
        status = inw(dev->iobase + PCI171X_STATUS_REG);
@@ -455,7 +455,7 @@ static void pci1710_handle_fifo(struct comedi_device *dev,
        }
 
        for (i = 0; i < devpriv->max_samples; i++) {
-               unsigned int val;
+               unsigned short val;
                int ret;
 
                ret = pci1710_ai_read_sample(dev, s, s->async->cur_chan, &val);
index 0437526..981d281 100644 (file)
@@ -126,7 +126,9 @@ static irqreturn_t pc236_interrupt(int irq, void *d)
 
        handled = pc236_intr_check(dev);
        if (dev->attached && handled) {
-               comedi_buf_write_samples(s, &s->state, 1);
+               unsigned short val = 0;
+
+               comedi_buf_write_samples(s, &val, 1);
                comedi_handle_events(dev, s);
        }
        return IRQ_RETVAL(handled);
index d740c47..2f20bd5 100644 (file)
@@ -1281,7 +1281,7 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev,
             devpriv->amcc + AMCC_OP_REG_INTCSR);
 
        ret = request_irq(pcidev->irq, cb_pcidas_interrupt, IRQF_SHARED,
-                         dev->board_name, dev);
+                         "cb_pcidas", dev);
        if (ret) {
                dev_dbg(dev->class_dev, "unable to allocate irq %d\n",
                        pcidev->irq);
index fa987bb..6d3ba39 100644 (file)
@@ -4035,7 +4035,7 @@ static int auto_attach(struct comedi_device *dev,
        init_stc_registers(dev);
 
        retval = request_irq(pcidev->irq, handle_interrupt, IRQF_SHARED,
-                            dev->board_name, dev);
+                            "cb_pcidas64", dev);
        if (retval) {
                dev_dbg(dev->class_dev, "unable to allocate irq %u\n",
                        pcidev->irq);
index 9361b2d..5338b5e 100644 (file)
@@ -210,12 +210,13 @@ static irqreturn_t parport_interrupt(int irq, void *d)
        struct comedi_device *dev = d;
        struct comedi_subdevice *s = dev->read_subdev;
        unsigned int ctrl;
+       unsigned short val = 0;
 
        ctrl = inb(dev->iobase + PARPORT_CTRL_REG);
        if (!(ctrl & PARPORT_CTRL_IRQ_ENA))
                return IRQ_NONE;
 
-       comedi_buf_write_samples(s, &s->state, 1);
+       comedi_buf_write_samples(s, &val, 1);
        comedi_handle_events(dev, s);
 
        return IRQ_HANDLED;
index 04e224f..96f4107 100644 (file)
@@ -186,7 +186,7 @@ static irqreturn_t das6402_interrupt(int irq, void *d)
        if (status & DAS6402_STATUS_FFULL) {
                async->events |= COMEDI_CB_OVERFLOW;
        } else if (status & DAS6402_STATUS_FFNE) {
-               unsigned int val;
+               unsigned short val;
 
                val = das6402_ai_read_sample(dev, s);
                comedi_buf_write_samples(s, &val, 1);
index 4ea100f..2881808 100644 (file)
@@ -427,7 +427,7 @@ static irqreturn_t das800_interrupt(int irq, void *d)
        struct comedi_cmd *cmd;
        unsigned long irq_flags;
        unsigned int status;
-       unsigned int val;
+       unsigned short val;
        bool fifo_empty;
        bool fifo_overflow;
        int i;
index 17e6018..56682f0 100644 (file)
@@ -404,7 +404,7 @@ static irqreturn_t dmm32at_isr(int irq, void *d)
 {
        struct comedi_device *dev = d;
        unsigned char intstat;
-       unsigned int val;
+       unsigned short val;
        int i;
 
        if (!dev->attached) {
index 726e40d..0d3d4ca 100644 (file)
@@ -924,7 +924,7 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
        struct comedi_subdevice *s = dev->read_subdev;
        int i;
        int c = 0;
-       unsigned int lval;
+       unsigned short lval;
 
        if (!dev->attached)
                return IRQ_NONE;
index 99e7441..f1a45cf 100644 (file)
@@ -195,7 +195,9 @@ static irqreturn_t ni6527_interrupt(int irq, void *d)
                return IRQ_NONE;
 
        if (status & NI6527_STATUS_EDGE) {
-               comedi_buf_write_samples(s, &s->state, 1);
+               unsigned short val = 0;
+
+               comedi_buf_write_samples(s, &val, 1);
                comedi_handle_events(dev, s);
        }
 
index eb3f9f7..7cd8497 100644 (file)
@@ -472,6 +472,7 @@ static irqreturn_t ni_65xx_interrupt(int irq, void *d)
        struct comedi_device *dev = d;
        struct comedi_subdevice *s = dev->read_subdev;
        unsigned int status;
+       unsigned short val = 0;
 
        status = readb(dev->mmio + NI_65XX_STATUS_REG);
        if ((status & NI_65XX_STATUS_INT) == 0)
@@ -482,7 +483,7 @@ static irqreturn_t ni_65xx_interrupt(int irq, void *d)
        writeb(NI_65XX_CLR_EDGE_INT | NI_65XX_CLR_OVERFLOW_INT,
               dev->mmio + NI_65XX_CLR_REG);
 
-       comedi_buf_write_samples(s, &s->state, 1);
+       comedi_buf_write_samples(s, &val, 1);
        comedi_handle_events(dev, s);
 
        return IRQ_HANDLED;
index 2dbf69e..bd6f42f 100644 (file)
@@ -184,7 +184,7 @@ static irqreturn_t pcl711_interrupt(int irq, void *d)
        struct comedi_device *dev = d;
        struct comedi_subdevice *s = dev->read_subdev;
        struct comedi_cmd *cmd = &s->async->cmd;
-       unsigned int data;
+       unsigned short data;
 
        if (!dev->attached) {
                dev_err(dev->class_dev, "spurious interrupt\n");
index 64eb649..88f25d7 100644 (file)
@@ -220,9 +220,11 @@ static irqreturn_t pcl726_interrupt(int irq, void *d)
        struct pcl726_private *devpriv = dev->private;
 
        if (devpriv->cmd_running) {
+               unsigned short val = 0;
+
                pcl726_intr_cancel(dev, s);
 
-               comedi_buf_write_samples(s, &s->state, 1);
+               comedi_buf_write_samples(s, &val, 1);
                comedi_handle_events(dev, s);
        }
 
index 63e3011..f4b4a68 100644 (file)
@@ -423,7 +423,7 @@ static int pcl818_ai_eoc(struct comedi_device *dev,
 
 static bool pcl818_ai_write_sample(struct comedi_device *dev,
                                   struct comedi_subdevice *s,
-                                  unsigned int chan, unsigned int val)
+                                  unsigned int chan, unsigned short val)
 {
        struct pcl818_private *devpriv = dev->private;
        struct comedi_cmd *cmd = &s->async->cmd;
index 7956abc..9f92081 100644 (file)
@@ -877,5 +877,4 @@ module_comedi_usb_driver(vmk80xx_driver, vmk80xx_usb_driver);
 
 MODULE_AUTHOR("Manuel Gebele <forensixs@gmx.de>");
 MODULE_DESCRIPTION("Velleman USB Board Low-Level Driver");
-MODULE_SUPPORTED_DEVICE("K8055/K8061 aka VM110/VM140");
 MODULE_LICENSE("GPL");
index dc09cc6..09e7b4c 100644 (file)
@@ -1120,6 +1120,7 @@ static int ks_wlan_set_scan(struct net_device *dev,
 {
        struct ks_wlan_private *priv = netdev_priv(dev);
        struct iw_scan_req *req = NULL;
+       int len;
 
        if (priv->sleep_mode == SLP_SLEEP)
                return -EPERM;
@@ -1129,8 +1130,9 @@ static int ks_wlan_set_scan(struct net_device *dev,
        if (wrqu->data.length == sizeof(struct iw_scan_req) &&
            wrqu->data.flags & IW_SCAN_THIS_ESSID) {
                req = (struct iw_scan_req *)extra;
-               priv->scan_ssid_len = req->essid_len;
-               memcpy(priv->scan_ssid, req->essid, priv->scan_ssid_len);
+               len = min_t(int, req->essid_len, IW_ESSID_MAX_SIZE);
+               priv->scan_ssid_len = len;
+               memcpy(priv->scan_ssid, req->essid, len);
        } else {
                priv->scan_ssid_len = 0;
        }
index fa1e34a..182bb94 100644 (file)
@@ -791,6 +791,7 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf,  int len)
        p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, WLAN_EID_SSID, &ie_len,
                       pbss_network->ie_length - _BEACON_IE_OFFSET_);
        if (p && ie_len > 0) {
+               ie_len = min_t(int, ie_len, sizeof(pbss_network->ssid.ssid));
                memset(&pbss_network->ssid, 0, sizeof(struct ndis_802_11_ssid));
                memcpy(pbss_network->ssid.ssid, p + 2, ie_len);
                pbss_network->ssid.ssid_length = ie_len;
@@ -811,6 +812,7 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf,  int len)
        p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, WLAN_EID_SUPP_RATES, &ie_len,
                       pbss_network->ie_length - _BEACON_IE_OFFSET_);
        if (p) {
+               ie_len = min_t(int, ie_len, NDIS_802_11_LENGTH_RATES_EX);
                memcpy(supportRate, p + 2, ie_len);
                supportRateNum = ie_len;
        }
@@ -819,6 +821,8 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf,  int len)
        p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, WLAN_EID_EXT_SUPP_RATES,
                       &ie_len, pbss_network->ie_length - _BEACON_IE_OFFSET_);
        if (p) {
+               ie_len = min_t(int, ie_len,
+                              NDIS_802_11_LENGTH_RATES_EX - supportRateNum);
                memcpy(supportRate + supportRateNum, p + 2, ie_len);
                supportRateNum += ie_len;
        }
@@ -934,6 +938,7 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf,  int len)
 
                pht_cap->mcs.rx_mask[0] = 0xff;
                pht_cap->mcs.rx_mask[1] = 0x0;
+               ie_len = min_t(int, ie_len, sizeof(pmlmepriv->htpriv.ht_cap));
                memcpy(&pmlmepriv->htpriv.ht_cap, p + 2, ie_len);
        }
 
index bf22f13..58954b8 100644 (file)
@@ -1133,9 +1133,11 @@ static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a,
                                                break;
                                        }
                                        sec_len = *(pos++); len -= 1;
-                                       if (sec_len > 0 && sec_len <= len) {
+                                       if (sec_len > 0 &&
+                                           sec_len <= len &&
+                                           sec_len <= 32) {
                                                ssid[ssid_index].ssid_length = sec_len;
-                                               memcpy(ssid[ssid_index].ssid, pos, ssid[ssid_index].ssid_length);
+                                               memcpy(ssid[ssid_index].ssid, pos, sec_len);
                                                ssid_index++;
                                        }
                                        pos += sec_len;
index 963a2ff..39f5a6a 100644 (file)
@@ -27,6 +27,7 @@ config RTLLIB_CRYPTO_CCMP
 config RTLLIB_CRYPTO_TKIP
        tristate "Support for rtllib TKIP crypto"
        depends on RTLLIB
+       select CRYPTO
        select CRYPTO_LIB_ARC4
        select CRYPTO_MICHAEL_MIC
        default y
index 16bcee1..407effd 100644 (file)
@@ -406,9 +406,10 @@ static int _rtl92e_wx_set_scan(struct net_device *dev,
                struct iw_scan_req *req = (struct iw_scan_req *)b;
 
                if (req->essid_len) {
-                       ieee->current_network.ssid_len = req->essid_len;
-                       memcpy(ieee->current_network.ssid, req->essid,
-                              req->essid_len);
+                       int len = min_t(int, req->essid_len, IW_ESSID_MAX_SIZE);
+
+                       ieee->current_network.ssid_len = len;
+                       memcpy(ieee->current_network.ssid, req->essid, len);
                }
        }
 
index d853586..77bf886 100644 (file)
@@ -331,8 +331,10 @@ static int r8192_wx_set_scan(struct net_device *dev, struct iw_request_info *a,
                struct iw_scan_req *req = (struct iw_scan_req *)b;
 
                if (req->essid_len) {
-                       ieee->current_network.ssid_len = req->essid_len;
-                       memcpy(ieee->current_network.ssid, req->essid, req->essid_len);
+                       int len = min_t(int, req->essid_len, IW_ESSID_MAX_SIZE);
+
+                       ieee->current_network.ssid_len = len;
+                       memcpy(ieee->current_network.ssid, req->essid, len);
                }
        }
 
index 1811646..75716f5 100644 (file)
@@ -192,8 +192,10 @@ u8 r8712_sitesurvey_cmd(struct _adapter *padapter,
        psurveyPara->ss_ssidlen = 0;
        memset(psurveyPara->ss_ssid, 0, IW_ESSID_MAX_SIZE + 1);
        if (pssid && pssid->SsidLength) {
-               memcpy(psurveyPara->ss_ssid, pssid->Ssid, pssid->SsidLength);
-               psurveyPara->ss_ssidlen = cpu_to_le32(pssid->SsidLength);
+               int len = min_t(int, pssid->SsidLength, IW_ESSID_MAX_SIZE);
+
+               memcpy(psurveyPara->ss_ssid, pssid->Ssid, len);
+               psurveyPara->ss_ssidlen = cpu_to_le32(len);
        }
        set_fwstate(pmlmepriv, _FW_UNDER_SURVEY);
        r8712_enqueue_cmd(pcmdpriv, ph2c);
index 81de5a9..60dd798 100644 (file)
@@ -924,7 +924,7 @@ static int r871x_wx_set_priv(struct net_device *dev,
        struct iw_point *dwrq = (struct iw_point *)awrq;
 
        len = dwrq->length;
-       ext = memdup_user(dwrq->pointer, len);
+       ext = strndup_user(dwrq->pointer, len);
        if (IS_ERR(ext))
                return PTR_ERR(ext);
 
index e7061d3..c3c2c15 100644 (file)
@@ -150,7 +150,7 @@ struct vnt_cts {
        u16 reserved;
        struct ieee80211_cts data;
        u16 reserved2;
-} __packed;
+} __packed __aligned(2);
 
 struct vnt_cts_fb {
        struct vnt_phy_field b;
@@ -160,7 +160,7 @@ struct vnt_cts_fb {
        __le16 cts_duration_ba_f1;
        struct ieee80211_cts data;
        u16 reserved2;
-} __packed;
+} __packed __aligned(2);
 
 struct vnt_tx_fifo_head {
        u8 tx_key[WLAN_KEY_LEN_CCMP];
index cd6bcfd..ed53d0b 100644 (file)
@@ -5,6 +5,7 @@
  * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
  * Copyright (c) 2010, ST-Ericsson
  */
+#include <linux/gpio/consumer.h>
 #include <net/mac80211.h>
 
 #include "bh.h"
index 92ef329..78c4932 100644 (file)
@@ -8,6 +8,10 @@
 #ifndef WFX_BH_H
 #define WFX_BH_H
 
+#include <linux/atomic.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+
 struct wfx_dev;
 
 struct wfx_hif {
index ea39114..ca04b3d 100644 (file)
@@ -8,6 +8,9 @@
 #ifndef WFX_BUS_H
 #define WFX_BUS_H
 
+#include <linux/mmc/sdio_func.h>
+#include <linux/spi/spi.h>
+
 #define WFX_REG_CONFIG        0x0
 #define WFX_REG_CONTROL       0x1
 #define WFX_REG_IN_OUT_QUEUE  0x2
index 588edce..e06d7e1 100644 (file)
@@ -5,13 +5,19 @@
  * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
  * Copyright (c) 2010, ST-Ericsson
  */
+#include <linux/module.h>
 #include <linux/mmc/sdio.h>
 #include <linux/mmc/sdio_func.h>
 #include <linux/mmc/card.h>
+#include <linux/interrupt.h>
 #include <linux/of_irq.h>
+#include <linux/irq.h>
 
 #include "bus.h"
 #include "wfx.h"
+#include "hwio.h"
+#include "main.h"
+#include "bh.h"
 
 static const struct wfx_platform_data wfx_sdio_pdata = {
        .file_fw = "wfm_wf200",
index f89855a..a99125d 100644 (file)
@@ -6,12 +6,19 @@
  * Copyright (c) 2011, Sagrad Inc.
  * Copyright (c) 2010, ST-Ericsson
  */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
 #include <linux/spi/spi.h>
+#include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/of.h>
 
 #include "bus.h"
 #include "wfx.h"
+#include "hwio.h"
+#include "main.h"
+#include "bh.h"
 
 #define SET_WRITE 0x7FFF        /* usage: and operation */
 #define SET_READ 0x8000         /* usage: or operation */
index 2cfa162..385f2d4 100644 (file)
@@ -5,8 +5,13 @@
  * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
  * Copyright (c) 2010, ST-Ericsson
  */
+#include <linux/etherdevice.h>
+#include <net/mac80211.h>
+
 #include "data_rx.h"
 #include "wfx.h"
+#include "bh.h"
+#include "sta.h"
 
 static void wfx_rx_handle_ba(struct wfx_vif *wvif, struct ieee80211_mgmt *mgmt)
 {
index 76f26e3..77fb104 100644 (file)
@@ -6,9 +6,14 @@
  * Copyright (c) 2010, ST-Ericsson
  */
 #include <net/mac80211.h>
+#include <linux/etherdevice.h>
 
+#include "data_tx.h"
 #include "wfx.h"
+#include "bh.h"
 #include "sta.h"
+#include "queue.h"
+#include "debug.h"
 #include "traces.h"
 #include "hif_tx_mib.h"
 
index 6b30200..401363d 100644 (file)
@@ -8,6 +8,9 @@
 #ifndef WFX_DATA_TX_H
 #define WFX_DATA_TX_H
 
+#include <linux/list.h>
+#include <net/mac80211.h>
+
 #include "hif_api_cmd.h"
 #include "hif_api_mib.h"
 
index 3e87d13..eedada7 100644 (file)
@@ -5,9 +5,15 @@
  * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
  * Copyright (c) 2010, ST-Ericsson
  */
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/crc32.h>
+
 #include "debug.h"
 #include "wfx.h"
 #include "sta.h"
+#include "main.h"
+#include "hif_tx.h"
 #include "hif_tx_mib.h"
 
 #define CREATE_TRACE_POINTS
index 1bb9054..1b8aec0 100644 (file)
@@ -6,6 +6,8 @@
  * Copyright (c) 2010, ST-Ericsson
  */
 #include <linux/firmware.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
 #include <linux/bitfield.h>
 
 #include "fwio.h"
index 8b671c9..58c9bb0 100644 (file)
@@ -8,6 +8,10 @@
 #ifndef WFX_HIF_API_CMD_H
 #define WFX_HIF_API_CMD_H
 
+#include <linux/ieee80211.h>
+
+#include "hif_api_general.h"
+
 enum hif_requests_ids {
        HIF_REQ_ID_RESET                = 0x0a,
        HIF_REQ_ID_READ_MIB             = 0x05,
index 70b253d..2418894 100644 (file)
@@ -8,6 +8,15 @@
 #ifndef WFX_HIF_API_GENERAL_H
 #define WFX_HIF_API_GENERAL_H
 
+#ifdef __KERNEL__
+#include <linux/types.h>
+#include <linux/if_ether.h>
+#else
+#include <net/ethernet.h>
+#include <stdint.h>
+#define __packed __attribute__((__packed__))
+#endif
+
 #define HIF_ID_IS_INDICATION      0x80
 #define HIF_COUNTER_MAX           7
 
index 17dc133..63b4372 100644 (file)
@@ -6,7 +6,11 @@
  * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
  * Copyright (c) 2010, ST-Ericsson
  */
+#include <linux/etherdevice.h>
+
+#include "hif_tx.h"
 #include "wfx.h"
+#include "bh.h"
 #include "hwio.h"
 #include "debug.h"
 #include "sta.h"
index 6432ed8..1926cf1 100644 (file)
@@ -6,8 +6,13 @@
  * Copyright (c) 2010, ST-Ericsson
  * Copyright (C) 2010, ST-Ericsson SA
  */
+
+#include <linux/etherdevice.h>
+
 #include "wfx.h"
+#include "hif_tx.h"
 #include "hif_tx_mib.h"
+#include "hif_api_mib.h"
 
 int hif_set_output_power(struct wfx_vif *wvif, int val)
 {
index 089bb41..36fbc5b 100644 (file)
@@ -5,10 +5,13 @@
  * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
  * Copyright (c) 2010, ST-Ericsson
  */
+#include <linux/kernel.h>
+#include <linux/delay.h>
 #include <linux/slab.h>
 
 #include "hwio.h"
 #include "wfx.h"
+#include "bus.h"
 #include "traces.h"
 
 /*
index 8bb9bcf..0b8e4f7 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef WFX_HWIO_H
 #define WFX_HWIO_H
 
+#include <linux/types.h>
+
 struct wfx_dev;
 
 int wfx_data_read(struct wfx_dev *wdev, void *buf, size_t buf_len);
index c93d07d..2ab82be 100644 (file)
@@ -5,10 +5,12 @@
  * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
  * Copyright (c) 2010, ST-Ericsson
  */
+#include <linux/etherdevice.h>
 #include <net/mac80211.h>
 
 #include "key.h"
 #include "wfx.h"
+#include "hif_tx_mib.h"
 
 static int wfx_alloc_key(struct wfx_dev *wdev)
 {
index 4dc9fea..70a44d0 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef WFX_KEY_H
 #define WFX_KEY_H
 
+#include <net/mac80211.h>
+
 struct wfx_dev;
 struct wfx_vif;
 
index b9ea9a9..e7bc198 100644 (file)
  * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
  * Copyright (c) 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
  */
+#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_net.h>
+#include <linux/gpio/consumer.h>
 #include <linux/mmc/sdio_func.h>
 #include <linux/spi/spi.h>
+#include <linux/etherdevice.h>
 #include <linux/firmware.h>
 
+#include "main.h"
 #include "wfx.h"
 #include "fwio.h"
 #include "hwio.h"
 #include "bus.h"
+#include "bh.h"
 #include "sta.h"
 #include "key.h"
 #include "scan.h"
 #include "debug.h"
+#include "data_tx.h"
 #include "hif_tx_mib.h"
+#include "hif_api_cmd.h"
 
 #define WFX_PDS_MAX_SIZE 1500
 
index 086bcc0..a0db322 100644 (file)
 #ifndef WFX_MAIN_H
 #define WFX_MAIN_H
 
+#include <linux/device.h>
 #include <linux/gpio/consumer.h>
 
+#include "hif_api_general.h"
+
 struct wfx_dev;
 struct hwbus_ops;
 
index 3bddf28..31c37f6 100644 (file)
@@ -5,9 +5,13 @@
  * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
  * Copyright (c) 2010, ST-Ericsson
  */
+#include <linux/sched.h>
 #include <net/mac80211.h>
 
+#include "queue.h"
 #include "wfx.h"
+#include "sta.h"
+#include "data_tx.h"
 #include "traces.h"
 
 void wfx_tx_lock(struct wfx_dev *wdev)
index e43aa9d..80ba194 100644 (file)
@@ -8,6 +8,9 @@
 #ifndef WFX_QUEUE_H
 #define WFX_QUEUE_H
 
+#include <linux/skbuff.h>
+#include <linux/atomic.h>
+
 struct wfx_dev;
 struct wfx_vif;
 
index e5b7eef..c7496a7 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef WFX_SCAN_H
 #define WFX_SCAN_H
 
+#include <net/mac80211.h>
+
 struct wfx_dev;
 struct wfx_vif;
 
index 5585f9e..196779a 100644 (file)
@@ -5,11 +5,17 @@
  * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
  * Copyright (c) 2010, ST-Ericsson
  */
+#include <linux/etherdevice.h>
 #include <net/mac80211.h>
 
 #include "sta.h"
 #include "wfx.h"
+#include "fwio.h"
+#include "bh.h"
+#include "key.h"
 #include "scan.h"
+#include "debug.h"
+#include "hif_tx.h"
 #include "hif_tx_mib.h"
 
 #define HIF_MAX_ARP_IP_ADDRTABLE_ENTRIES 2
index a3fb9fc..d7b5df5 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef WFX_STA_H
 #define WFX_STA_H
 
+#include <net/mac80211.h>
+
 struct wfx_dev;
 struct wfx_vif;
 
index afe1074..e34c7a5 100644 (file)
 #define _WFX_TRACE_H
 
 #include <linux/tracepoint.h>
+#include <net/mac80211.h>
 
 #include "bus.h"
+#include "hif_api_cmd.h"
+#include "hif_api_mib.h"
 
 /* The hell below need some explanations. For each symbolic number, we need to
  * define it with TRACE_DEFINE_ENUM() and in a list for __print_symbolic.
index a185b82..9489868 100644 (file)
@@ -10,6 +10,9 @@
 #ifndef WFX_H
 #define WFX_H
 
+#include <linux/completion.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
 #include <linux/nospec.h>
 #include <net/mac80211.h>
 
index cf4718c..319a1e7 100644 (file)
@@ -747,7 +747,6 @@ module_platform_driver(optee_driver);
 
 MODULE_AUTHOR("Linaro");
 MODULE_DESCRIPTION("OP-TEE driver");
-MODULE_SUPPORTED_DEVICE("");
 MODULE_VERSION("1.0");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:optee");
index 345917a..1c4aac8 100644 (file)
@@ -674,6 +674,9 @@ void thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev,
 {
        struct cooling_dev_stats *stats = cdev->stats;
 
+       if (!stats)
+               return;
+
        spin_lock(&stats->lock);
 
        if (stats->state == new_state)
index b63fecc..2a95b4c 100644 (file)
@@ -768,12 +768,6 @@ static int tb_init_port(struct tb_port *port)
 
        tb_dump_port(port->sw->tb, &port->config);
 
-       /* Control port does not need HopID allocation */
-       if (port->port) {
-               ida_init(&port->in_hopids);
-               ida_init(&port->out_hopids);
-       }
-
        INIT_LIST_HEAD(&port->list);
        return 0;
 
@@ -1842,10 +1836,8 @@ static void tb_switch_release(struct device *dev)
        dma_port_free(sw->dma_port);
 
        tb_switch_for_each_port(sw, port) {
-               if (!port->disabled) {
-                       ida_destroy(&port->in_hopids);
-                       ida_destroy(&port->out_hopids);
-               }
+               ida_destroy(&port->in_hopids);
+               ida_destroy(&port->out_hopids);
        }
 
        kfree(sw->uuid);
@@ -2025,6 +2017,12 @@ struct tb_switch *tb_switch_alloc(struct tb *tb, struct device *parent,
                /* minimum setup for tb_find_cap and tb_drom_read to work */
                sw->ports[i].sw = sw;
                sw->ports[i].port = i;
+
+               /* Control port does not need HopID allocation */
+               if (i) {
+                       ida_init(&sw->ports[i].in_hopids);
+                       ida_init(&sw->ports[i].out_hopids);
+               }
        }
 
        ret = tb_switch_find_vse_cap(sw, TB_VSE_CAP_PLUG_EVENTS);
index 1f000ac..c348b1f 100644 (file)
@@ -138,6 +138,10 @@ static void tb_discover_tunnels(struct tb_switch *sw)
                                parent->boot = true;
                                parent = tb_switch_parent(parent);
                        }
+               } else if (tb_tunnel_is_dp(tunnel)) {
+                       /* Keep the domain from powering down */
+                       pm_runtime_get_sync(&tunnel->src_port->sw->dev);
+                       pm_runtime_get_sync(&tunnel->dst_port->sw->dev);
                }
 
                list_add_tail(&tunnel->list, &tcm->tunnel_list);
index c908489..9afa1dc 100644 (file)
@@ -317,7 +317,6 @@ static void hvcs_hangup(struct tty_struct * tty);
 
 static int hvcs_probe(struct vio_dev *dev,
                const struct vio_device_id *id);
-static int hvcs_remove(struct vio_dev *dev);
 static int __init hvcs_module_init(void);
 static void __exit hvcs_module_exit(void);
 static int hvcs_initialize(void);
@@ -819,7 +818,7 @@ static int hvcs_probe(
        return 0;
 }
 
-static int hvcs_remove(struct vio_dev *dev)
+static void hvcs_remove(struct vio_dev *dev)
 {
        struct hvcs_struct *hvcsd = dev_get_drvdata(&dev->dev);
        unsigned long flags;
@@ -849,7 +848,6 @@ static int hvcs_remove(struct vio_dev *dev)
 
        printk(KERN_INFO "HVCS: vty-server@%X removed from the"
                        " vio bus.\n", dev->unit_address);
-       return 0;
 };
 
 static struct vio_driver hvcs_vio_driver = {
index 8b2797b..5e23745 100644 (file)
@@ -66,8 +66,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
        wake_up_interruptible(&tty->link->read_wait);
        wake_up_interruptible(&tty->link->write_wait);
        if (tty->driver->subtype == PTY_TYPE_MASTER) {
-               struct file *f;
-
+               set_bit(TTY_OTHER_CLOSED, &tty->flags);
 #ifdef CONFIG_UNIX98_PTYS
                if (tty->driver == ptm_driver) {
                        mutex_lock(&devpts_mutex);
@@ -76,17 +75,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
                        mutex_unlock(&devpts_mutex);
                }
 #endif
-
-               /*
-                * This hack is required because a program can open a
-                * pty and redirect a console to it, but if the pty is
-                * closed and the console is not released, then the
-                * slave side will never close.  So release the
-                * redirect when the master closes.
-                */
-               f = tty_release_redirect(tty->link);
-               if (f)
-                       fput(f);
+               tty_vhangup(tty->link);
        }
 }
 
index 9a87275..94af7a5 100644 (file)
@@ -1639,8 +1639,6 @@ module_exit(icom_exit);
 
 MODULE_AUTHOR("Michael Anderson <mjanders@us.ibm.com>");
 MODULE_DESCRIPTION("IBM iSeries Serial IOA driver");
-MODULE_SUPPORTED_DEVICE
-    ("IBM iSeries 2745, 2771, 2772, 2742, 2793 and 2805 Communications adapters");
 MODULE_LICENSE("GPL");
 MODULE_FIRMWARE("icom_call_setup.bin");
 MODULE_FIRMWARE("icom_res_dce.bin");
index cd30da0..0ea799b 100644 (file)
@@ -19,7 +19,6 @@
 MODULE_AUTHOR("Digi International, https://www.digi.com");
 MODULE_DESCRIPTION("Driver for the Digi International Neo and Classic PCI based product line");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("jsm");
 
 #define JSM_DRIVER_NAME "jsm"
 #define NR_PORTS       32
index 9795b2e..1b61d26 100644 (file)
@@ -1056,9 +1056,9 @@ static int max310x_startup(struct uart_port *port)
        max310x_port_update(port, MAX310X_MODE1_REG,
                            MAX310X_MODE1_TRNSCVCTRL_BIT, 0);
 
-       /* Reset FIFOs */
-       max310x_port_write(port, MAX310X_MODE2_REG,
-                          MAX310X_MODE2_FIFORST_BIT);
+       /* Configure MODE2 register & Reset FIFOs*/
+       val = MAX310X_MODE2_RXEMPTINV_BIT | MAX310X_MODE2_FIFORST_BIT;
+       max310x_port_write(port, MAX310X_MODE2_REG, val);
        max310x_port_update(port, MAX310X_MODE2_REG,
                            MAX310X_MODE2_FIFORST_BIT, 0);
 
@@ -1086,27 +1086,8 @@ static int max310x_startup(struct uart_port *port)
        /* Clear IRQ status register */
        max310x_port_read(port, MAX310X_IRQSTS_REG);
 
-       /*
-        * Let's ask for an interrupt after a timeout equivalent to
-        * the receiving time of 4 characters after the last character
-        * has been received.
-        */
-       max310x_port_write(port, MAX310X_RXTO_REG, 4);
-
-       /*
-        * Make sure we also get RX interrupts when the RX FIFO is
-        * filling up quickly, so get an interrupt when half of the RX
-        * FIFO has been filled in.
-        */
-       max310x_port_write(port, MAX310X_FIFOTRIGLVL_REG,
-                          MAX310X_FIFOTRIGLVL_RX(MAX310X_FIFO_SIZE / 2));
-
-       /* Enable RX timeout interrupt in LSR */
-       max310x_port_write(port, MAX310X_LSR_IRQEN_REG,
-                          MAX310X_LSR_RXTO_BIT);
-
-       /* Enable LSR, RX FIFO trigger, CTS change interrupts */
-       val = MAX310X_IRQ_LSR_BIT  | MAX310X_IRQ_RXFIFO_BIT | MAX310X_IRQ_TXEMPTY_BIT;
+       /* Enable RX, TX, CTS change interrupts */
+       val = MAX310X_IRQ_RXEMPTY_BIT | MAX310X_IRQ_TXEMPTY_BIT;
        max310x_port_write(port, MAX310X_IRQEN_REG, val | MAX310X_IRQ_CTS_BIT);
 
        return 0;
index 74733ec..391bada 100644 (file)
@@ -544,9 +544,7 @@ EXPORT_SYMBOL_GPL(tty_wakeup);
  *     @tty: tty device
  *
  *     This is available to the pty code so if the master closes, if the
- *     slave is a redirect it can release the redirect.  It returns the
- *     filp for the redirect, which must be fput when the operations on
- *     the tty are completed.
+ *     slave is a redirect it can release the redirect.
  */
 struct file *tty_release_redirect(struct tty_struct *tty)
 {
@@ -561,6 +559,7 @@ struct file *tty_release_redirect(struct tty_struct *tty)
 
        return f;
 }
+EXPORT_SYMBOL_GPL(tty_release_redirect);
 
 /**
  *     __tty_hangup            -       actual handler for hangup events
index f9170d1..5f0513c 100644 (file)
@@ -2197,7 +2197,10 @@ static int cdnsp_queue_isoc_tx(struct cdnsp_device *pdev,
         * inverted in the first TDs isoc TRB.
         */
        field = TRB_TYPE(TRB_ISOC) | TRB_TLBPC(last_burst_pkt) |
-               start_cycle ? 0 : 1 | TRB_SIA | TRB_TBC(burst_count);
+               TRB_SIA | TRB_TBC(burst_count);
+
+       if (!start_cycle)
+               field |= TRB_CYCLE;
 
        /* Fill the rest of the TRB fields, and remaining normal TRBs. */
        for (i = 0; i < trbs_per_td; i++) {
index 37f824b..39ddb55 100644 (file)
@@ -1935,6 +1935,11 @@ static const struct usb_device_id acm_ids[] = {
        .driver_info = SEND_ZERO_PACKET,
        },
 
+       /* Exclude Goodix Fingerprint Reader */
+       { USB_DEVICE(0x27c6, 0x5395),
+       .driver_info = IGNORE_DEVICE,
+       },
+
        /* control interfaces without any protocol set */
        { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
                USB_CDC_PROTO_NONE) },
index c9f6e97..f27b4ae 100644 (file)
@@ -494,16 +494,24 @@ static int usblp_release(struct inode *inode, struct file *file)
 /* No kernel lock - fine */
 static __poll_t usblp_poll(struct file *file, struct poll_table_struct *wait)
 {
-       __poll_t ret;
+       struct usblp *usblp = file->private_data;
+       __poll_t ret = 0;
        unsigned long flags;
 
-       struct usblp *usblp = file->private_data;
        /* Should we check file->f_mode & FMODE_WRITE before poll_wait()? */
        poll_wait(file, &usblp->rwait, wait);
        poll_wait(file, &usblp->wwait, wait);
+
+       mutex_lock(&usblp->mut);
+       if (!usblp->present)
+               ret |= EPOLLHUP;
+       mutex_unlock(&usblp->mut);
+
        spin_lock_irqsave(&usblp->lock, flags);
-       ret = ((usblp->bidir && usblp->rcomplete) ? EPOLLIN  | EPOLLRDNORM : 0) |
-          ((usblp->no_paper || usblp->wcomplete) ? EPOLLOUT | EPOLLWRNORM : 0);
+       if (usblp->bidir && usblp->rcomplete)
+               ret |= EPOLLIN  | EPOLLRDNORM;
+       if (usblp->no_paper || usblp->wcomplete)
+               ret |= EPOLLOUT | EPOLLWRNORM;
        spin_unlock_irqrestore(&usblp->lock, flags);
        return ret;
 }
index 8f07b05..a566bb4 100644 (file)
@@ -748,6 +748,38 @@ void usb_put_intf(struct usb_interface *intf)
 }
 EXPORT_SYMBOL_GPL(usb_put_intf);
 
+/**
+ * usb_intf_get_dma_device - acquire a reference on the usb interface's DMA endpoint
+ * @intf: the usb interface
+ *
+ * While a USB device cannot perform DMA operations by itself, many USB
+ * controllers can. A call to usb_intf_get_dma_device() returns the DMA endpoint
+ * for the given USB interface, if any. The returned device structure must be
+ * released with put_device().
+ *
+ * See also usb_get_dma_device().
+ *
+ * Returns: A reference to the usb interface's DMA endpoint; or NULL if none
+ *          exists.
+ */
+struct device *usb_intf_get_dma_device(struct usb_interface *intf)
+{
+       struct usb_device *udev = interface_to_usbdev(intf);
+       struct device *dmadev;
+
+       if (!udev->bus)
+               return NULL;
+
+       dmadev = get_device(udev->bus->sysdev);
+       if (!dmadev || !dmadev->dma_mask) {
+               put_device(dmadev);
+               return NULL;
+       }
+
+       return dmadev;
+}
+EXPORT_SYMBOL_GPL(usb_intf_get_dma_device);
+
 /*                     USB device locking
  *
  * USB devices and interfaces are locked using the semaphore in their
index 846a47b..fcaf044 100644 (file)
@@ -358,8 +358,10 @@ static int dwc3_qcom_suspend(struct dwc3_qcom *qcom)
        if (ret)
                dev_warn(qcom->dev, "failed to disable interconnect: %d\n", ret);
 
+       if (device_may_wakeup(qcom->dev))
+               dwc3_qcom_enable_interrupts(qcom);
+
        qcom->is_suspended = true;
-       dwc3_qcom_enable_interrupts(qcom);
 
        return 0;
 }
@@ -372,7 +374,8 @@ static int dwc3_qcom_resume(struct dwc3_qcom *qcom)
        if (!qcom->is_suspended)
                return 0;
 
-       dwc3_qcom_disable_interrupts(qcom);
+       if (device_may_wakeup(qcom->dev))
+               dwc3_qcom_disable_interrupts(qcom);
 
        for (i = 0; i < qcom->num_clocks; i++) {
                ret = clk_prepare_enable(qcom->clks[i]);
@@ -650,16 +653,19 @@ static int dwc3_qcom_of_register_core(struct platform_device *pdev)
        ret = of_platform_populate(np, NULL, NULL, dev);
        if (ret) {
                dev_err(dev, "failed to register dwc3 core - %d\n", ret);
-               return ret;
+               goto node_put;
        }
 
        qcom->dwc3 = of_find_device_by_node(dwc3_np);
        if (!qcom->dwc3) {
+               ret = -ENODEV;
                dev_err(dev, "failed to get dwc3 platform device\n");
-               return -ENODEV;
        }
 
-       return 0;
+node_put:
+       of_node_put(dwc3_np);
+
+       return ret;
 }
 
 static struct platform_device *
@@ -938,6 +944,8 @@ static const struct dwc3_acpi_pdata sdm845_acpi_urs_pdata = {
 static const struct acpi_device_id dwc3_qcom_acpi_match[] = {
        { "QCOM2430", (unsigned long)&sdm845_acpi_pdata },
        { "QCOM0304", (unsigned long)&sdm845_acpi_urs_pdata },
+       { "QCOM0497", (unsigned long)&sdm845_acpi_urs_pdata },
+       { "QCOM04A6", (unsigned long)&sdm845_acpi_pdata },
        { },
 };
 MODULE_DEVICE_TABLE(acpi, dwc3_qcom_acpi_match);
index aebcf8e..4a337f3 100644 (file)
@@ -783,8 +783,6 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
 
        trace_dwc3_gadget_ep_disable(dep);
 
-       dwc3_remove_requests(dwc, dep);
-
        /* make sure HW endpoint isn't stalled */
        if (dep->flags & DWC3_EP_STALL)
                __dwc3_gadget_ep_set_halt(dep, 0, false);
@@ -803,6 +801,8 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
                dep->endpoint.desc = NULL;
        }
 
+       dwc3_remove_requests(dwc, dep);
+
        return 0;
 }
 
@@ -1617,7 +1617,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
 {
        struct dwc3             *dwc = dep->dwc;
 
-       if (!dep->endpoint.desc || !dwc->pullups_connected) {
+       if (!dep->endpoint.desc || !dwc->pullups_connected || !dwc->connected) {
                dev_err(dwc->dev, "%s: can't queue to disabled endpoint\n",
                                dep->name);
                return -ESHUTDOWN;
@@ -2247,6 +2247,7 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
        if (!is_on) {
                u32 count;
 
+               dwc->connected = false;
                /*
                 * In the Synopsis DesignWare Cores USB3 Databook Rev. 3.30a
                 * Section 4.1.8 Table 4-7, it states that for a device-initiated
@@ -2271,7 +2272,6 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
                        dwc->ev_buf->lpos = (dwc->ev_buf->lpos + count) %
                                                dwc->ev_buf->length;
                }
-               dwc->connected = false;
        } else {
                __dwc3_gadget_start(dwc);
        }
@@ -3321,8 +3321,6 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
 {
        u32                     reg;
 
-       dwc->connected = true;
-
        /*
         * WORKAROUND: DWC3 revisions <1.88a have an issue which
         * would cause a missing Disconnect Event if there's a
@@ -3362,6 +3360,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
         * transfers."
         */
        dwc3_stop_active_transfers(dwc);
+       dwc->connected = true;
 
        reg = dwc3_readl(dwc->regs, DWC3_DCTL);
        reg &= ~DWC3_DCTL_TSTCTRL_MASK;
index 0d56f33..15a607c 100644 (file)
@@ -97,6 +97,8 @@ struct gadget_config_name {
        struct list_head list;
 };
 
+#define USB_MAX_STRING_WITH_NULL_LEN   (USB_MAX_STRING_LEN+1)
+
 static int usb_string_copy(const char *s, char **s_copy)
 {
        int ret;
@@ -106,12 +108,16 @@ static int usb_string_copy(const char *s, char **s_copy)
        if (ret > USB_MAX_STRING_LEN)
                return -EOVERFLOW;
 
-       str = kstrdup(s, GFP_KERNEL);
-       if (!str)
-               return -ENOMEM;
+       if (copy) {
+               str = copy;
+       } else {
+               str = kmalloc(USB_MAX_STRING_WITH_NULL_LEN, GFP_KERNEL);
+               if (!str)
+                       return -ENOMEM;
+       }
+       strcpy(str, s);
        if (str[ret - 1] == '\n')
                str[ret - 1] = '\0';
-       kfree(copy);
        *s_copy = str;
        return 0;
 }
index 00d3469..560382e 100644 (file)
@@ -499,6 +499,7 @@ static void f_audio_disable(struct usb_function *f)
        uac1->as_out_alt = 0;
        uac1->as_in_alt = 0;
 
+       u_audio_stop_playback(&uac1->g_audio);
        u_audio_stop_capture(&uac1->g_audio);
 }
 
index 5d960b6..6f03e94 100644 (file)
@@ -478,7 +478,7 @@ static int set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts,
        }
 
        max_size_bw = num_channels(chmask) * ssize *
-               DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1)));
+               ((srate / (factor / (1 << (ep_desc->bInterval - 1)))) + 1);
        ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw,
                                                    max_size_ep));
 
index 3dfb460..f558c31 100644 (file)
@@ -182,12 +182,11 @@ out:                                                                      \
                                                size_t len)             \
        {                                                               \
                struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item);  \
-               int ret;                                                \
+               int ret = -EINVAL;                                      \
                u8 val;                                                 \
                                                                        \
                mutex_lock(&opts->lock);                                \
-               ret = sscanf(page, "%02hhx", &val);                     \
-               if (ret > 0) {                                          \
+               if (sscanf(page, "%02hhx", &val) > 0) {                 \
                        opts->_n_ = val;                                \
                        ret = len;                                      \
                }                                                       \
index f1ea514..1d3ebb0 100644 (file)
@@ -1773,8 +1773,8 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
        udc_info = dev_get_platdata(&pdev->dev);
 
        base_addr = devm_platform_ioremap_resource(pdev, 0);
-       if (!base_addr) {
-               retval = -ENOMEM;
+       if (IS_ERR(base_addr)) {
+               retval = PTR_ERR(base_addr);
                goto err_mem;
        }
 
index 84da840..5bbccc9 100644 (file)
@@ -66,6 +66,7 @@
 #define PCI_DEVICE_ID_ASMEDIA_1042A_XHCI               0x1142
 #define PCI_DEVICE_ID_ASMEDIA_1142_XHCI                        0x1242
 #define PCI_DEVICE_ID_ASMEDIA_2142_XHCI                        0x2142
+#define PCI_DEVICE_ID_ASMEDIA_3242_XHCI                        0x3242
 
 static const char hcd_name[] = "xhci_hcd";
 
@@ -276,11 +277,14 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
                pdev->device == PCI_DEVICE_ID_ASMEDIA_1042_XHCI)
                xhci->quirks |= XHCI_BROKEN_STREAMS;
        if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
-               pdev->device == PCI_DEVICE_ID_ASMEDIA_1042A_XHCI)
+               pdev->device == PCI_DEVICE_ID_ASMEDIA_1042A_XHCI) {
                xhci->quirks |= XHCI_TRUST_TX_LENGTH;
+               xhci->quirks |= XHCI_NO_64BIT_SUPPORT;
+       }
        if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
            (pdev->device == PCI_DEVICE_ID_ASMEDIA_1142_XHCI ||
-            pdev->device == PCI_DEVICE_ID_ASMEDIA_2142_XHCI))
+            pdev->device == PCI_DEVICE_ID_ASMEDIA_2142_XHCI ||
+            pdev->device == PCI_DEVICE_ID_ASMEDIA_3242_XHCI))
                xhci->quirks |= XHCI_NO_64BIT_SUPPORT;
 
        if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
@@ -295,6 +299,11 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
             pdev->device == 0x9026)
                xhci->quirks |= XHCI_RESET_PLL_ON_DISCONNECT;
 
+       if (pdev->vendor == PCI_VENDOR_ID_AMD &&
+           (pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_2 ||
+            pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_4))
+               xhci->quirks |= XHCI_NO_SOFT_RETRY;
+
        if (xhci->quirks & XHCI_RESET_ON_RESUME)
                xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
                                "QUIRK: Resetting on resume");
index 5e548a1..ce38076 100644 (file)
@@ -2484,7 +2484,8 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
                remaining       = 0;
                break;
        case COMP_USB_TRANSACTION_ERROR:
-               if ((ep_ring->err_count++ > MAX_SOFT_RETRY) ||
+               if (xhci->quirks & XHCI_NO_SOFT_RETRY ||
+                   (ep_ring->err_count++ > MAX_SOFT_RETRY) ||
                    le32_to_cpu(slot_ctx->tt_info) & TT_SLOT)
                        break;
 
index bd27bd6..1975016 100644 (file)
@@ -883,44 +883,42 @@ static void xhci_clear_command_ring(struct xhci_hcd *xhci)
        xhci_set_cmd_ring_deq(xhci);
 }
 
-static void xhci_disable_port_wake_on_bits(struct xhci_hcd *xhci)
+/*
+ * Disable port wake bits if do_wakeup is not set.
+ *
+ * Also clear a possible internal port wake state left hanging for ports that
+ * detected termination but never successfully enumerated (trained to 0U).
+ * Internal wake causes immediate xHCI wake after suspend. PORT_CSC write done
+ * at enumeration clears this wake, force one here as well for unconnected ports
+ */
+
+static void xhci_disable_hub_port_wake(struct xhci_hcd *xhci,
+                                      struct xhci_hub *rhub,
+                                      bool do_wakeup)
 {
-       struct xhci_port **ports;
-       int port_index;
        unsigned long flags;
        u32 t1, t2, portsc;
+       int i;
 
        spin_lock_irqsave(&xhci->lock, flags);
 
-       /* disable usb3 ports Wake bits */
-       port_index = xhci->usb3_rhub.num_ports;
-       ports = xhci->usb3_rhub.ports;
-       while (port_index--) {
-               t1 = readl(ports[port_index]->addr);
-               portsc = t1;
-               t1 = xhci_port_state_to_neutral(t1);
-               t2 = t1 & ~PORT_WAKE_BITS;
-               if (t1 != t2) {
-                       writel(t2, ports[port_index]->addr);
-                       xhci_dbg(xhci, "disable wake bits port %d-%d, portsc: 0x%x, write: 0x%x\n",
-                                xhci->usb3_rhub.hcd->self.busnum,
-                                port_index + 1, portsc, t2);
-               }
-       }
+       for (i = 0; i < rhub->num_ports; i++) {
+               portsc = readl(rhub->ports[i]->addr);
+               t1 = xhci_port_state_to_neutral(portsc);
+               t2 = t1;
+
+               /* clear wake bits if do_wake is not set */
+               if (!do_wakeup)
+                       t2 &= ~PORT_WAKE_BITS;
+
+               /* Don't touch csc bit if connected or connect change is set */
+               if (!(portsc & (PORT_CSC | PORT_CONNECT)))
+                       t2 |= PORT_CSC;
 
-       /* disable usb2 ports Wake bits */
-       port_index = xhci->usb2_rhub.num_ports;
-       ports = xhci->usb2_rhub.ports;
-       while (port_index--) {
-               t1 = readl(ports[port_index]->addr);
-               portsc = t1;
-               t1 = xhci_port_state_to_neutral(t1);
-               t2 = t1 & ~PORT_WAKE_BITS;
                if (t1 != t2) {
-                       writel(t2, ports[port_index]->addr);
-                       xhci_dbg(xhci, "disable wake bits port %d-%d, portsc: 0x%x, write: 0x%x\n",
-                                xhci->usb2_rhub.hcd->self.busnum,
-                                port_index + 1, portsc, t2);
+                       writel(t2, rhub->ports[i]->addr);
+                       xhci_dbg(xhci, "config port %d-%d wake bits, portsc: 0x%x, write: 0x%x\n",
+                                rhub->hcd->self.busnum, i + 1, portsc, t2);
                }
        }
        spin_unlock_irqrestore(&xhci->lock, flags);
@@ -983,8 +981,8 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
                return -EINVAL;
 
        /* Clear root port wake on bits if wakeup not allowed. */
-       if (!do_wakeup)
-               xhci_disable_port_wake_on_bits(xhci);
+       xhci_disable_hub_port_wake(xhci, &xhci->usb3_rhub, do_wakeup);
+       xhci_disable_hub_port_wake(xhci, &xhci->usb2_rhub, do_wakeup);
 
        if (!HCD_HW_ACCESSIBLE(hcd))
                return 0;
@@ -1088,6 +1086,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
        struct usb_hcd          *secondary_hcd;
        int                     retval = 0;
        bool                    comp_timer_running = false;
+       bool                    pending_portevent = false;
 
        if (!hcd->state)
                return 0;
@@ -1226,13 +1225,22 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
 
  done:
        if (retval == 0) {
-               /* Resume root hubs only when have pending events. */
-               if (xhci_pending_portevent(xhci)) {
+               /*
+                * Resume roothubs only if there are pending events.
+                * USB 3 devices resend U3 LFPS wake after a 100ms delay if
+                * the first wake signalling failed, give it that chance.
+                */
+               pending_portevent = xhci_pending_portevent(xhci);
+               if (!pending_portevent) {
+                       msleep(120);
+                       pending_portevent = xhci_pending_portevent(xhci);
+               }
+
+               if (pending_portevent) {
                        usb_hcd_resume_root_hub(xhci->shared_hcd);
                        usb_hcd_resume_root_hub(hcd);
                }
        }
-
        /*
         * If system is subject to the Quirk, Compliance Mode Timer needs to
         * be re-initialized Always after a system resume. Ports are subject
index d41de5d..ca822ad 100644 (file)
@@ -1891,6 +1891,7 @@ struct xhci_hcd {
 #define XHCI_SKIP_PHY_INIT     BIT_ULL(37)
 #define XHCI_DISABLE_SPARSE    BIT_ULL(38)
 #define XHCI_SG_TRB_CACHE_SIZE_QUIRK   BIT_ULL(39)
+#define XHCI_NO_SOFT_RETRY     BIT_ULL(40)
 
        unsigned int            num_active_eps;
        unsigned int            limit_active_eps;
index 670e4d9..dcc88df 100644 (file)
@@ -117,7 +117,6 @@ MODULE_DEVICE_TABLE(usb, ld_usb_table);
 MODULE_AUTHOR("Michael Hund <mhund@ld-didactic.de>");
 MODULE_DESCRIPTION("LD USB Driver");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("LD USB Devices");
 
 /* All interrupt in transfers are collected in a ring buffer to
  * avoid racing conditions and get better performance of the driver.
index e7334b7..75fff2e 100644 (file)
@@ -746,6 +746,8 @@ struct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv,
 
 void usbhs_pipe_free(struct usbhs_pipe *pipe)
 {
+       usbhsp_pipe_select(pipe);
+       usbhsp_pipe_cfg_set(pipe, 0xFFFF, 0);
        usbhsp_put_pipe(pipe);
 }
 
index 8d997b7..2db917e 100644 (file)
@@ -86,6 +86,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x1a86, 0x7522) },
        { USB_DEVICE(0x1a86, 0x7523) },
        { USB_DEVICE(0x4348, 0x5523) },
+       { USB_DEVICE(0x9986, 0x7523) },
        { },
 };
 MODULE_DEVICE_TABLE(usb, id_table);
index 9e1c609..a373cd6 100644 (file)
@@ -145,6 +145,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x10C4, 0x8857) }, /* CEL EM357 ZigBee USB Stick */
        { USB_DEVICE(0x10C4, 0x88A4) }, /* MMB Networks ZigBee USB Device */
        { USB_DEVICE(0x10C4, 0x88A5) }, /* Planet Innovation Ingeni ZigBee USB Device */
+       { USB_DEVICE(0x10C4, 0x88D8) }, /* Acuity Brands nLight Air Adapter */
        { USB_DEVICE(0x10C4, 0x88FB) }, /* CESINEL MEDCAL STII Network Analyzer */
        { USB_DEVICE(0x10C4, 0x8938) }, /* CESINEL MEDCAL S II Network Analyzer */
        { USB_DEVICE(0x10C4, 0x8946) }, /* Ketra N1 Wireless Interface */
@@ -201,6 +202,8 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x1901, 0x0194) }, /* GE Healthcare Remote Alarm Box */
        { USB_DEVICE(0x1901, 0x0195) }, /* GE B850/B650/B450 CP2104 DP UART interface */
        { USB_DEVICE(0x1901, 0x0196) }, /* GE B850 CP2105 DP UART interface */
+       { USB_DEVICE(0x1901, 0x0197) }, /* GE CS1000 Display serial interface */
+       { USB_DEVICE(0x1901, 0x0198) }, /* GE CS1000 M.2 Key E serial interface */
        { USB_DEVICE(0x199B, 0xBA30) }, /* LORD WSDA-200-USB */
        { USB_DEVICE(0x19CF, 0x3000) }, /* Parrot NMEA GPS Flight Recorder */
        { USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */
index a493670..68401ad 100644 (file)
@@ -3003,26 +3003,32 @@ static int edge_startup(struct usb_serial *serial)
                                response = -ENODEV;
                        }
 
-                       usb_free_urb(edge_serial->interrupt_read_urb);
-                       kfree(edge_serial->interrupt_in_buffer);
-
-                       usb_free_urb(edge_serial->read_urb);
-                       kfree(edge_serial->bulk_in_buffer);
-
-                       kfree(edge_serial);
-
-                       return response;
+                       goto error;
                }
 
                /* start interrupt read for this edgeport this interrupt will
                 * continue as long as the edgeport is connected */
                response = usb_submit_urb(edge_serial->interrupt_read_urb,
                                                                GFP_KERNEL);
-               if (response)
+               if (response) {
                        dev_err(ddev, "%s - Error %d submitting control urb\n",
                                __func__, response);
+
+                       goto error;
+               }
        }
        return response;
+
+error:
+       usb_free_urb(edge_serial->interrupt_read_urb);
+       kfree(edge_serial->interrupt_in_buffer);
+
+       usb_free_urb(edge_serial->read_urb);
+       kfree(edge_serial->bulk_in_buffer);
+
+       kfree(edge_serial);
+
+       return response;
 }
 
 
index 483d07d..0ca0490 100644 (file)
@@ -545,37 +545,13 @@ static void xr_close(struct usb_serial_port *port)
 
 static int xr_probe(struct usb_serial *serial, const struct usb_device_id *id)
 {
-       struct usb_driver *driver = serial->type->usb_driver;
-       struct usb_interface *control_interface;
-       int ret;
-
        /* Don't bind to control interface */
        if (serial->interface->cur_altsetting->desc.bInterfaceNumber == 0)
                return -ENODEV;
 
-       /* But claim the control interface during data interface probe */
-       control_interface = usb_ifnum_to_if(serial->dev, 0);
-       if (!control_interface)
-               return -ENODEV;
-
-       ret = usb_driver_claim_interface(driver, control_interface, NULL);
-       if (ret) {
-               dev_err(&serial->interface->dev, "Failed to claim control interface\n");
-               return ret;
-       }
-
        return 0;
 }
 
-static void xr_disconnect(struct usb_serial *serial)
-{
-       struct usb_driver *driver = serial->type->usb_driver;
-       struct usb_interface *control_interface;
-
-       control_interface = usb_ifnum_to_if(serial->dev, 0);
-       usb_driver_release_interface(driver, control_interface);
-}
-
 static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x04e2, 0x1410) }, /* XR21V141X */
        { }
@@ -590,7 +566,6 @@ static struct usb_serial_driver xr_device = {
        .id_table               = id_table,
        .num_ports              = 1,
        .probe                  = xr_probe,
-       .disconnect             = xr_disconnect,
        .open                   = xr_open,
        .close                  = xr_close,
        .break_ctl              = xr_break_ctl,
index 5eb895b..f4304ce 100644 (file)
@@ -656,6 +656,13 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
                need_auto_sense = 1;
        }
 
+       /* Some devices (Kindle) require another command after SYNC CACHE */
+       if ((us->fflags & US_FL_SENSE_AFTER_SYNC) &&
+                       srb->cmnd[0] == SYNCHRONIZE_CACHE) {
+               usb_stor_dbg(us, "-- sense after SYNC CACHE\n");
+               need_auto_sense = 1;
+       }
+
        /*
         * If we have a failure, we're going to do a REQUEST_SENSE 
         * automatically.  Note that we differentiate between a command
index 5732e96..efa972b 100644 (file)
@@ -2211,6 +2211,18 @@ UNUSUAL_DEV( 0x1908, 0x3335, 0x0200, 0x0200,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_NO_READ_DISC_INFO ),
 
+/*
+ * Reported by Matthias Schwarzott <zzam@gentoo.org>
+ * The Amazon Kindle treats SYNCHRONIZE CACHE as an indication that
+ * the host may be finished with it, and automatically ejects its
+ * emulated media unless it receives another command within one second.
+ */
+UNUSUAL_DEV( 0x1949, 0x0004, 0x0000, 0x9999,
+               "Amazon",
+               "Kindle",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_SENSE_AFTER_SYNC ),
+
 /*
  * Reported by Oliver Neukum <oneukum@suse.com>
  * This device morphes spontaneously into another device if the access
index be0b646..ce7af39 100644 (file)
@@ -942,6 +942,7 @@ static int tcpm_set_current_limit(struct tcpm_port *port, u32 max_ma, u32 mv)
 
        port->supply_voltage = mv;
        port->current_limit = max_ma;
+       power_supply_changed(port->psy);
 
        if (port->tcpc->set_current_limit)
                ret = port->tcpc->set_current_limit(port->tcpc, max_ma, mv);
@@ -2928,6 +2929,7 @@ static int tcpm_pd_select_pdo(struct tcpm_port *port, int *sink_pdo,
 
        port->pps_data.supported = false;
        port->usb_type = POWER_SUPPLY_USB_TYPE_PD;
+       power_supply_changed(port->psy);
 
        /*
         * Select the source PDO providing the most power which has a
@@ -2952,6 +2954,7 @@ static int tcpm_pd_select_pdo(struct tcpm_port *port, int *sink_pdo,
                                port->pps_data.supported = true;
                                port->usb_type =
                                        POWER_SUPPLY_USB_TYPE_PD_PPS;
+                               power_supply_changed(port->psy);
                        }
                        continue;
                default:
@@ -3109,6 +3112,7 @@ static unsigned int tcpm_pd_select_pps_apdo(struct tcpm_port *port)
                                                  port->pps_data.out_volt));
                port->pps_data.op_curr = min(port->pps_data.max_curr,
                                             port->pps_data.op_curr);
+               power_supply_changed(port->psy);
        }
 
        return src_pdo;
@@ -3344,6 +3348,7 @@ static int tcpm_set_charge(struct tcpm_port *port, bool charge)
                        return ret;
        }
        port->vbus_charge = charge;
+       power_supply_changed(port->psy);
        return 0;
 }
 
@@ -3523,6 +3528,7 @@ static void tcpm_reset_port(struct tcpm_port *port)
        port->try_src_count = 0;
        port->try_snk_count = 0;
        port->usb_type = POWER_SUPPLY_USB_TYPE_C;
+       power_supply_changed(port->psy);
        port->nr_sink_caps = 0;
        port->sink_cap_done = false;
        if (port->tcpc->enable_frs)
@@ -5167,7 +5173,7 @@ static void tcpm_enable_frs_work(struct kthread_work *work)
                goto unlock;
 
        /* Send when the state machine is idle */
-       if (port->state != SNK_READY || port->vdm_state != VDM_STATE_DONE || port->send_discover)
+       if (port->state != SNK_READY || port->vdm_sm_running || port->send_discover)
                goto resched;
 
        port->upcoming_state = GET_SINK_CAP;
@@ -5905,7 +5911,7 @@ static int tcpm_psy_set_prop(struct power_supply *psy,
                ret = -EINVAL;
                break;
        }
-
+       power_supply_changed(port->psy);
        return ret;
 }
 
@@ -6058,6 +6064,7 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
        err = devm_tcpm_psy_register(port);
        if (err)
                goto out_role_sw_put;
+       power_supply_changed(port->psy);
 
        port->typec_port = typec_register_port(port->dev, &port->typec_caps);
        if (IS_ERR(port->typec_port)) {
index 6e6ef63..29bd1c5 100644 (file)
@@ -64,7 +64,6 @@ enum {
 struct tps6598x_rx_identity_reg {
        u8 status;
        struct usb_pd_identity identity;
-       u32 vdo[3];
 } __packed;
 
 /* Standard Task return codes */
index 2305d42..8f1de1f 100644 (file)
@@ -46,6 +46,8 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a
        int sockfd = 0;
        struct socket *socket;
        int rv;
+       struct task_struct *tcp_rx = NULL;
+       struct task_struct *tcp_tx = NULL;
 
        if (!sdev) {
                dev_err(dev, "sdev is null\n");
@@ -69,23 +71,47 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a
                }
 
                socket = sockfd_lookup(sockfd, &err);
-               if (!socket)
+               if (!socket) {
+                       dev_err(dev, "failed to lookup sock");
                        goto err;
+               }
 
-               sdev->ud.tcp_socket = socket;
-               sdev->ud.sockfd = sockfd;
+               if (socket->type != SOCK_STREAM) {
+                       dev_err(dev, "Expecting SOCK_STREAM - found %d",
+                               socket->type);
+                       goto sock_err;
+               }
 
+               /* unlock and create threads and get tasks */
                spin_unlock_irq(&sdev->ud.lock);
+               tcp_rx = kthread_create(stub_rx_loop, &sdev->ud, "stub_rx");
+               if (IS_ERR(tcp_rx)) {
+                       sockfd_put(socket);
+                       return -EINVAL;
+               }
+               tcp_tx = kthread_create(stub_tx_loop, &sdev->ud, "stub_tx");
+               if (IS_ERR(tcp_tx)) {
+                       kthread_stop(tcp_rx);
+                       sockfd_put(socket);
+                       return -EINVAL;
+               }
 
-               sdev->ud.tcp_rx = kthread_get_run(stub_rx_loop, &sdev->ud,
-                                                 "stub_rx");
-               sdev->ud.tcp_tx = kthread_get_run(stub_tx_loop, &sdev->ud,
-                                                 "stub_tx");
+               /* get task structs now */
+               get_task_struct(tcp_rx);
+               get_task_struct(tcp_tx);
 
+               /* lock and update sdev->ud state */
                spin_lock_irq(&sdev->ud.lock);
+               sdev->ud.tcp_socket = socket;
+               sdev->ud.sockfd = sockfd;
+               sdev->ud.tcp_rx = tcp_rx;
+               sdev->ud.tcp_tx = tcp_tx;
                sdev->ud.status = SDEV_ST_USED;
                spin_unlock_irq(&sdev->ud.lock);
 
+               wake_up_process(sdev->ud.tcp_rx);
+               wake_up_process(sdev->ud.tcp_tx);
+
        } else {
                dev_info(dev, "stub down\n");
 
@@ -100,6 +126,8 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a
 
        return count;
 
+sock_err:
+       sockfd_put(socket);
 err:
        spin_unlock_irq(&sdev->ud.lock);
        return -EINVAL;
index 96e5371..c4b4256 100644 (file)
@@ -312,6 +312,8 @@ static ssize_t attach_store(struct device *dev, struct device_attribute *attr,
        struct vhci *vhci;
        int err;
        unsigned long flags;
+       struct task_struct *tcp_rx = NULL;
+       struct task_struct *tcp_tx = NULL;
 
        /*
         * @rhport: port number of vhci_hcd
@@ -349,12 +351,35 @@ static ssize_t attach_store(struct device *dev, struct device_attribute *attr,
 
        /* Extract socket from fd. */
        socket = sockfd_lookup(sockfd, &err);
-       if (!socket)
+       if (!socket) {
+               dev_err(dev, "failed to lookup sock");
                return -EINVAL;
+       }
+       if (socket->type != SOCK_STREAM) {
+               dev_err(dev, "Expecting SOCK_STREAM - found %d",
+                       socket->type);
+               sockfd_put(socket);
+               return -EINVAL;
+       }
+
+       /* create threads before locking */
+       tcp_rx = kthread_create(vhci_rx_loop, &vdev->ud, "vhci_rx");
+       if (IS_ERR(tcp_rx)) {
+               sockfd_put(socket);
+               return -EINVAL;
+       }
+       tcp_tx = kthread_create(vhci_tx_loop, &vdev->ud, "vhci_tx");
+       if (IS_ERR(tcp_tx)) {
+               kthread_stop(tcp_rx);
+               sockfd_put(socket);
+               return -EINVAL;
+       }
 
-       /* now need lock until setting vdev status as used */
+       /* get task structs now */
+       get_task_struct(tcp_rx);
+       get_task_struct(tcp_tx);
 
-       /* begin a lock */
+       /* now begin lock until setting vdev status set */
        spin_lock_irqsave(&vhci->lock, flags);
        spin_lock(&vdev->ud.lock);
 
@@ -364,6 +389,8 @@ static ssize_t attach_store(struct device *dev, struct device_attribute *attr,
                spin_unlock_irqrestore(&vhci->lock, flags);
 
                sockfd_put(socket);
+               kthread_stop_put(tcp_rx);
+               kthread_stop_put(tcp_tx);
 
                dev_err(dev, "port %d already used\n", rhport);
                /*
@@ -382,6 +409,8 @@ static ssize_t attach_store(struct device *dev, struct device_attribute *attr,
        vdev->speed         = speed;
        vdev->ud.sockfd     = sockfd;
        vdev->ud.tcp_socket = socket;
+       vdev->ud.tcp_rx     = tcp_rx;
+       vdev->ud.tcp_tx     = tcp_tx;
        vdev->ud.status     = VDEV_ST_NOTASSIGNED;
        usbip_kcov_handle_init(&vdev->ud);
 
@@ -389,8 +418,8 @@ static ssize_t attach_store(struct device *dev, struct device_attribute *attr,
        spin_unlock_irqrestore(&vhci->lock, flags);
        /* end the lock */
 
-       vdev->ud.tcp_rx = kthread_get_run(vhci_rx_loop, &vdev->ud, "vhci_rx");
-       vdev->ud.tcp_tx = kthread_get_run(vhci_tx_loop, &vdev->ud, "vhci_tx");
+       wake_up_process(vdev->ud.tcp_rx);
+       wake_up_process(vdev->ud.tcp_tx);
 
        rh_port_connect(vdev, speed);
 
index 100f680..7383a54 100644 (file)
@@ -90,8 +90,9 @@ unlock:
 }
 static BIN_ATTR_RO(dev_desc, sizeof(struct usb_device_descriptor));
 
-static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *attr,
-                    const char *in, size_t count)
+static ssize_t usbip_sockfd_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *in, size_t count)
 {
        struct vudc *udc = (struct vudc *) dev_get_drvdata(dev);
        int rv;
@@ -100,6 +101,8 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a
        struct socket *socket;
        unsigned long flags;
        int ret;
+       struct task_struct *tcp_rx = NULL;
+       struct task_struct *tcp_tx = NULL;
 
        rv = kstrtoint(in, 0, &sockfd);
        if (rv != 0)
@@ -138,24 +141,54 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a
                        goto unlock_ud;
                }
 
-               udc->ud.tcp_socket = socket;
+               if (socket->type != SOCK_STREAM) {
+                       dev_err(dev, "Expecting SOCK_STREAM - found %d",
+                               socket->type);
+                       ret = -EINVAL;
+                       goto sock_err;
+               }
 
+               /* unlock and create threads and get tasks */
                spin_unlock_irq(&udc->ud.lock);
                spin_unlock_irqrestore(&udc->lock, flags);
 
-               udc->ud.tcp_rx = kthread_get_run(&v_rx_loop,
-                                                   &udc->ud, "vudc_rx");
-               udc->ud.tcp_tx = kthread_get_run(&v_tx_loop,
-                                                   &udc->ud, "vudc_tx");
+               tcp_rx = kthread_create(&v_rx_loop, &udc->ud, "vudc_rx");
+               if (IS_ERR(tcp_rx)) {
+                       sockfd_put(socket);
+                       return -EINVAL;
+               }
+               tcp_tx = kthread_create(&v_tx_loop, &udc->ud, "vudc_tx");
+               if (IS_ERR(tcp_tx)) {
+                       kthread_stop(tcp_rx);
+                       sockfd_put(socket);
+                       return -EINVAL;
+               }
+
+               /* get task structs now */
+               get_task_struct(tcp_rx);
+               get_task_struct(tcp_tx);
 
+               /* lock and update udc->ud state */
                spin_lock_irqsave(&udc->lock, flags);
                spin_lock_irq(&udc->ud.lock);
+
+               udc->ud.tcp_socket = socket;
+               udc->ud.tcp_rx = tcp_rx;
+               udc->ud.tcp_tx = tcp_tx;
                udc->ud.status = SDEV_ST_USED;
+
                spin_unlock_irq(&udc->ud.lock);
 
                ktime_get_ts64(&udc->start_time);
                v_start_timer(udc);
                udc->connected = 1;
+
+               spin_unlock_irqrestore(&udc->lock, flags);
+
+               wake_up_process(udc->ud.tcp_rx);
+               wake_up_process(udc->ud.tcp_tx);
+               return count;
+
        } else {
                if (!udc->connected) {
                        dev_err(dev, "Device not connected");
@@ -177,6 +210,8 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a
 
        return count;
 
+sock_err:
+       sockfd_put(socket);
 unlock_ud:
        spin_unlock_irq(&udc->ud.lock);
 unlock:
index 7c8bbfc..d555a6a 100644 (file)
@@ -431,8 +431,7 @@ static int ifcvf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        }
 
        adapter = vdpa_alloc_device(struct ifcvf_adapter, vdpa,
-                                   dev, &ifc_vdpa_ops,
-                                   IFCVF_MAX_QUEUE_PAIRS * 2, NULL);
+                                   dev, &ifc_vdpa_ops, NULL);
        if (adapter == NULL) {
                IFCVF_ERR(pdev, "Failed to allocate vDPA structure");
                return -ENOMEM;
@@ -456,7 +455,7 @@ static int ifcvf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        for (i = 0; i < IFCVF_MAX_QUEUE_PAIRS * 2; i++)
                vf->vring[i].irq = -EINVAL;
 
-       ret = vdpa_register_device(&adapter->vdpa);
+       ret = vdpa_register_device(&adapter->vdpa, IFCVF_MAX_QUEUE_PAIRS * 2);
        if (ret) {
                IFCVF_ERR(pdev, "Failed to register ifcvf to vdpa bus");
                goto err;
index 10e9b09..71397fd 100644 (file)
@@ -1982,7 +1982,7 @@ static int mlx5v_probe(struct auxiliary_device *adev,
        max_vqs = min_t(u32, max_vqs, MLX5_MAX_SUPPORTED_VQS);
 
        ndev = vdpa_alloc_device(struct mlx5_vdpa_net, mvdev.vdev, mdev->device, &mlx5_vdpa_ops,
-                                2 * mlx5_vdpa_max_qps(max_vqs), NULL);
+                                NULL);
        if (IS_ERR(ndev))
                return PTR_ERR(ndev);
 
@@ -2009,7 +2009,7 @@ static int mlx5v_probe(struct auxiliary_device *adev,
        if (err)
                goto err_res;
 
-       err = vdpa_register_device(&mvdev->vdev);
+       err = vdpa_register_device(&mvdev->vdev, 2 * mlx5_vdpa_max_qps(max_vqs));
        if (err)
                goto err_reg;
 
index da67f07..5cffce6 100644 (file)
@@ -69,7 +69,6 @@ static void vdpa_release_dev(struct device *d)
  * initialized but before registered.
  * @parent: the parent device
  * @config: the bus operations that is supported by this device
- * @nvqs: number of virtqueues supported by this device
  * @size: size of the parent structure that contains private data
  * @name: name of the vdpa device; optional.
  *
@@ -81,7 +80,7 @@ static void vdpa_release_dev(struct device *d)
  */
 struct vdpa_device *__vdpa_alloc_device(struct device *parent,
                                        const struct vdpa_config_ops *config,
-                                       int nvqs, size_t size, const char *name)
+                                       size_t size, const char *name)
 {
        struct vdpa_device *vdev;
        int err = -EINVAL;
@@ -107,7 +106,6 @@ struct vdpa_device *__vdpa_alloc_device(struct device *parent,
        vdev->index = err;
        vdev->config = config;
        vdev->features_valid = false;
-       vdev->nvqs = nvqs;
 
        if (name)
                err = dev_set_name(&vdev->dev, "%s", name);
@@ -136,10 +134,12 @@ static int vdpa_name_match(struct device *dev, const void *data)
        return (strcmp(dev_name(&vdev->dev), data) == 0);
 }
 
-static int __vdpa_register_device(struct vdpa_device *vdev)
+static int __vdpa_register_device(struct vdpa_device *vdev, int nvqs)
 {
        struct device *dev;
 
+       vdev->nvqs = nvqs;
+
        lockdep_assert_held(&vdpa_dev_mutex);
        dev = bus_find_device(&vdpa_bus, NULL, dev_name(&vdev->dev), vdpa_name_match);
        if (dev) {
@@ -155,15 +155,16 @@ static int __vdpa_register_device(struct vdpa_device *vdev)
  * Caller must invoke this routine in the management device dev_add()
  * callback after setting up valid mgmtdev for this vdpa device.
  * @vdev: the vdpa device to be registered to vDPA bus
+ * @nvqs: number of virtqueues supported by this device
  *
  * Returns an error when fail to add device to vDPA bus
  */
-int _vdpa_register_device(struct vdpa_device *vdev)
+int _vdpa_register_device(struct vdpa_device *vdev, int nvqs)
 {
        if (!vdev->mdev)
                return -EINVAL;
 
-       return __vdpa_register_device(vdev);
+       return __vdpa_register_device(vdev, nvqs);
 }
 EXPORT_SYMBOL_GPL(_vdpa_register_device);
 
@@ -171,15 +172,16 @@ EXPORT_SYMBOL_GPL(_vdpa_register_device);
  * vdpa_register_device - register a vDPA device
  * Callers must have a succeed call of vdpa_alloc_device() before.
  * @vdev: the vdpa device to be registered to vDPA bus
+ * @nvqs: number of virtqueues supported by this device
  *
  * Returns an error when fail to add to vDPA bus
  */
-int vdpa_register_device(struct vdpa_device *vdev)
+int vdpa_register_device(struct vdpa_device *vdev, int nvqs)
 {
        int err;
 
        mutex_lock(&vdpa_dev_mutex);
-       err = __vdpa_register_device(vdev);
+       err = __vdpa_register_device(vdev, nvqs);
        mutex_unlock(&vdpa_dev_mutex);
        return err;
 }
index d594284..5b6b2f8 100644 (file)
@@ -235,7 +235,7 @@ struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr)
                ops = &vdpasim_config_ops;
 
        vdpasim = vdpa_alloc_device(struct vdpasim, vdpa, NULL, ops,
-                                   dev_attr->nvqs, dev_attr->name);
+                                   dev_attr->name);
        if (!vdpasim)
                goto err_alloc;
 
index d344c5b..a1ab616 100644 (file)
@@ -110,8 +110,7 @@ out:
 
 static void vdpasim_net_get_config(struct vdpasim *vdpasim, void *config)
 {
-       struct virtio_net_config *net_config =
-               (struct virtio_net_config *)config;
+       struct virtio_net_config *net_config = config;
 
        net_config->mtu = cpu_to_vdpasim16(vdpasim, 1500);
        net_config->status = cpu_to_vdpasim16(vdpasim, VIRTIO_NET_S_LINK_UP);
@@ -147,7 +146,7 @@ static int vdpasim_net_dev_add(struct vdpa_mgmt_dev *mdev, const char *name)
        if (IS_ERR(simdev))
                return PTR_ERR(simdev);
 
-       ret = _vdpa_register_device(&simdev->vdpa);
+       ret = _vdpa_register_device(&simdev->vdpa, VDPASIM_NET_VQ_NUM);
        if (ret)
                goto reg_err;
 
index 5533df9..67d0bf4 100644 (file)
@@ -21,8 +21,8 @@ config VFIO_VIRQFD
 
 menuconfig VFIO
        tristate "VFIO Non-Privileged userspace driver framework"
-       depends on IOMMU_API
-       select VFIO_IOMMU_TYPE1 if (X86 || S390 || ARM || ARM64)
+       select IOMMU_API
+       select VFIO_IOMMU_TYPE1 if MMU && (X86 || S390 || ARM || ARM64)
        help
          VFIO provides a framework for secure userspace device drivers.
          See Documentation/driver-api/vfio.rst for more details.
index dc1a3c4..ab34110 100644 (file)
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 config VFIO_PLATFORM
        tristate "VFIO support for platform devices"
-       depends on VFIO && EVENTFD && (ARM || ARM64)
+       depends on VFIO && EVENTFD && (ARM || ARM64 || COMPILE_TEST)
        select VFIO_VIRQFD
        help
          Support for platform devices with VFIO. This is required to make
@@ -12,7 +12,7 @@ config VFIO_PLATFORM
 
 config VFIO_AMBA
        tristate "VFIO support for AMBA devices"
-       depends on VFIO_PLATFORM && ARM_AMBA
+       depends on VFIO_PLATFORM && (ARM_AMBA || COMPILE_TEST)
        help
          Support for ARM AMBA devices with VFIO. This is required to make
          use of ARM AMBA devices present on the system using the VFIO
index 4bb162c..be44440 100644 (file)
@@ -189,7 +189,7 @@ static struct vfio_dma *vfio_find_dma(struct vfio_iommu *iommu,
 }
 
 static struct rb_node *vfio_find_dma_first_node(struct vfio_iommu *iommu,
-                                               dma_addr_t start, size_t size)
+                                               dma_addr_t start, u64 size)
 {
        struct rb_node *res = NULL;
        struct rb_node *node = iommu->dma_list.rb_node;
@@ -785,7 +785,12 @@ static int vfio_pin_page_external(struct vfio_dma *dma, unsigned long vaddr,
                return -ENODEV;
 
        ret = vaddr_get_pfns(mm, vaddr, 1, dma->prot, pfn_base, pages);
-       if (ret == 1 && do_accounting && !is_invalid_reserved_pfn(*pfn_base)) {
+       if (ret != 1)
+               goto out;
+
+       ret = 0;
+
+       if (do_accounting && !is_invalid_reserved_pfn(*pfn_base)) {
                ret = vfio_lock_acct(dma, 1, true);
                if (ret) {
                        put_pfn(*pfn_base, dma->prot);
@@ -797,6 +802,7 @@ static int vfio_pin_page_external(struct vfio_dma *dma, unsigned long vaddr,
                }
        }
 
+out:
        mmput(mm);
        return ret;
 }
@@ -1288,7 +1294,7 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iommu,
        int ret = -EINVAL, retries = 0;
        unsigned long pgshift;
        dma_addr_t iova = unmap->iova;
-       unsigned long size = unmap->size;
+       u64 size = unmap->size;
        bool unmap_all = unmap->flags & VFIO_DMA_UNMAP_FLAG_ALL;
        bool invalidate_vaddr = unmap->flags & VFIO_DMA_UNMAP_FLAG_VADDR;
        struct rb_node *n, *first_n;
@@ -1304,14 +1310,12 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iommu,
        if (unmap_all) {
                if (iova || size)
                        goto unlock;
-               size = SIZE_MAX;
-       } else if (!size || size & (pgsize - 1)) {
+               size = U64_MAX;
+       } else if (!size || size & (pgsize - 1) ||
+                  iova + size - 1 < iova || size > SIZE_MAX) {
                goto unlock;
        }
 
-       if (iova + size - 1 < iova || size > SIZE_MAX)
-               goto unlock;
-
        /* When dirty tracking is enabled, allow only min supported pgsize */
        if ((unmap->flags & VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP) &&
            (!iommu->dirty_page_tracking || (bitmap->pgsize != pgsize))) {
index ef688c8..e0a27e3 100644 (file)
@@ -308,8 +308,10 @@ static long vhost_vdpa_get_vring_num(struct vhost_vdpa *v, u16 __user *argp)
 
 static void vhost_vdpa_config_put(struct vhost_vdpa *v)
 {
-       if (v->config_ctx)
+       if (v->config_ctx) {
                eventfd_ctx_put(v->config_ctx);
+               v->config_ctx = NULL;
+       }
 }
 
 static long vhost_vdpa_set_config_call(struct vhost_vdpa *v, u32 __user *argp)
@@ -329,8 +331,12 @@ static long vhost_vdpa_set_config_call(struct vhost_vdpa *v, u32 __user *argp)
        if (!IS_ERR_OR_NULL(ctx))
                eventfd_ctx_put(ctx);
 
-       if (IS_ERR(v->config_ctx))
-               return PTR_ERR(v->config_ctx);
+       if (IS_ERR(v->config_ctx)) {
+               long ret = PTR_ERR(v->config_ctx);
+
+               v->config_ctx = NULL;
+               return ret;
+       }
 
        v->vdpa->config->set_config_cb(v->vdpa, &cb);
 
@@ -900,14 +906,10 @@ err:
 
 static void vhost_vdpa_clean_irq(struct vhost_vdpa *v)
 {
-       struct vhost_virtqueue *vq;
        int i;
 
-       for (i = 0; i < v->nvqs; i++) {
-               vq = &v->vqs[i];
-               if (vq->call_ctx.producer.irq)
-                       irq_bypass_unregister_producer(&vq->call_ctx.producer);
-       }
+       for (i = 0; i < v->nvqs; i++)
+               vhost_vdpa_unsetup_vq_irq(v, i);
 }
 
 static int vhost_vdpa_release(struct inode *inode, struct file *filep)
index a262e12..5ccb070 100644 (file)
@@ -332,8 +332,8 @@ static void vhost_vq_reset(struct vhost_dev *dev,
        vq->error_ctx = NULL;
        vq->kick = NULL;
        vq->log_ctx = NULL;
-       vhost_reset_is_le(vq);
        vhost_disable_cross_endian(vq);
+       vhost_reset_is_le(vq);
        vq->busyloop_timeout = 0;
        vq->umem = NULL;
        vq->iotlb = NULL;
index 551372f..465f55b 100644 (file)
@@ -287,11 +287,8 @@ static inline void aty_st_8(int regindex, u8 val, const struct atyfb_par *par)
 #endif
 }
 
-#if defined(CONFIG_PMAC_BACKLIGHT) || defined (CONFIG_FB_ATY_GENERIC_LCD) || \
-defined (CONFIG_FB_ATY_BACKLIGHT)
 extern void aty_st_lcd(int index, u32 val, const struct atyfb_par *par);
 extern u32 aty_ld_lcd(int index, const struct atyfb_par *par);
-#endif
 
     /*
      *  DAC operations
index e946903..1aef3d6 100644 (file)
 #define PRINTKE(fmt, args...)  printk(KERN_ERR "atyfb: " fmt, ## args)
 
 #if defined(CONFIG_PMAC_BACKLIGHT) || defined(CONFIG_FB_ATY_GENERIC_LCD) || \
-defined(CONFIG_FB_ATY_BACKLIGHT)
+defined(CONFIG_FB_ATY_BACKLIGHT) || defined (CONFIG_PPC_PMAC)
 static const u32 lt_lcd_regs[] = {
        CNFG_PANEL_LG,
        LCD_GEN_CNTL_LG,
@@ -175,8 +175,8 @@ u32 aty_ld_lcd(int index, const struct atyfb_par *par)
                return aty_ld_le32(LCD_DATA, par);
        }
 }
-#else /* defined(CONFIG_PMAC_BACKLIGHT) || defined(CONFIG_FB_ATY_BACKLIGHT) \
-        defined(CONFIG_FB_ATY_GENERIC_LCD) */
+#else /* defined(CONFIG_PMAC_BACKLIGHT) || defined(CONFIG_FB_ATY_BACKLIGHT) ||
+        defined(CONFIG_FB_ATY_GENERIC_LCD) || defined(CONFIG_PPC_PMAC) */
 void aty_st_lcd(int index, u32 val, const struct atyfb_par *par)
 { }
 
@@ -184,7 +184,8 @@ u32 aty_ld_lcd(int index, const struct atyfb_par *par)
 {
        return 0;
 }
-#endif /* defined(CONFIG_PMAC_BACKLIGHT) || defined (CONFIG_FB_ATY_GENERIC_LCD) */
+#endif /* defined(CONFIG_PMAC_BACKLIGHT) || defined(CONFIG_FB_ATY_BACKLIGHT) ||
+         defined (CONFIG_FB_ATY_GENERIC_LCD) || defined(CONFIG_PPC_PMAC) */
 
 #ifdef CONFIG_FB_ATY_GENERIC_LCD
 /*
index 1f6b7c5..130e12b 100644 (file)
@@ -333,7 +333,7 @@ static long acrn_dev_ioctl(struct file *filp, unsigned int cmd,
                acrn_ioreq_request_clear(vm);
                break;
        case ACRN_IOCTL_PM_GET_CPU_STATE:
-               if (copy_from_user(&cstate_cmd, (void *)ioctl_param,
+               if (copy_from_user(&cstate_cmd, (void __user *)ioctl_param,
                                   sizeof(cstate_cmd)))
                        return -EFAULT;
 
@@ -404,6 +404,14 @@ fail_remove:
 }
 static DEVICE_ATTR_WO(remove_cpu);
 
+static umode_t acrn_attr_visible(struct kobject *kobj, struct attribute *a, int n)
+{
+       if (a == &dev_attr_remove_cpu.attr)
+               return IS_ENABLED(CONFIG_HOTPLUG_CPU) ? a->mode : 0;
+
+       return a->mode;
+}
+
 static struct attribute *acrn_attrs[] = {
        &dev_attr_remove_cpu.attr,
        NULL
@@ -411,6 +419,7 @@ static struct attribute *acrn_attrs[] = {
 
 static struct attribute_group acrn_attr_group = {
        .attrs = acrn_attrs,
+       .is_visible = acrn_attr_visible,
 };
 
 static const struct attribute_group *acrn_attr_groups[] = {
index a8766d5..df51849 100644 (file)
@@ -112,7 +112,7 @@ static int acrn_irqfd_assign(struct acrn_vm *vm, struct acrn_irqfd *args)
 {
        struct eventfd_ctx *eventfd = NULL;
        struct hsm_irqfd *irqfd, *tmp;
-       unsigned int events;
+       __poll_t events;
        struct fd f;
        int ret = 0;
 
@@ -158,9 +158,9 @@ static int acrn_irqfd_assign(struct acrn_vm *vm, struct acrn_irqfd *args)
        mutex_unlock(&vm->irqfds_lock);
 
        /* Check the pending event in this stage */
-       events = f.file->f_op->poll(f.file, &irqfd->pt);
+       events = vfs_poll(f.file, &irqfd->pt);
 
-       if (events & POLLIN)
+       if (events & EPOLLIN)
                acrn_irqfd_inject(irqfd);
 
        fdput(f);
index 42e09cc..4b15c00 100644 (file)
@@ -141,15 +141,14 @@ void virtio_config_changed(struct virtio_device *dev)
 }
 EXPORT_SYMBOL_GPL(virtio_config_changed);
 
-void virtio_config_disable(struct virtio_device *dev)
+static void virtio_config_disable(struct virtio_device *dev)
 {
        spin_lock_irq(&dev->config_lock);
        dev->config_enabled = false;
        spin_unlock_irq(&dev->config_lock);
 }
-EXPORT_SYMBOL_GPL(virtio_config_disable);
 
-void virtio_config_enable(struct virtio_device *dev)
+static void virtio_config_enable(struct virtio_device *dev)
 {
        spin_lock_irq(&dev->config_lock);
        dev->config_enabled = true;
@@ -158,7 +157,6 @@ void virtio_config_enable(struct virtio_device *dev)
        dev->config_change_pending = false;
        spin_unlock_irq(&dev->config_lock);
 }
-EXPORT_SYMBOL_GPL(virtio_config_enable);
 
 void virtio_add_status(struct virtio_device *dev, unsigned int status)
 {
index a286d22..56128b9 100644 (file)
@@ -548,8 +548,7 @@ static void virtio_mmio_release_dev(struct device *_d)
 {
        struct virtio_device *vdev =
                        container_of(_d, struct virtio_device, dev);
-       struct virtio_mmio_device *vm_dev =
-                       container_of(vdev, struct virtio_mmio_device, vdev);
+       struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
        struct platform_device *pdev = vm_dev->pdev;
 
        devm_kfree(&pdev->dev, vm_dev);
index 9867a3a..688b112 100644 (file)
@@ -273,7 +273,6 @@ module_exit(cpu5wdt_exit_module);
 
 MODULE_AUTHOR("Heiko Ronsdorf <hero@ihg.uni-duisburg.de>");
 MODULE_DESCRIPTION("sma cpu5 watchdog driver");
-MODULE_SUPPORTED_DEVICE("sma cpu5 watchdog");
 MODULE_LICENSE("GPL");
 
 module_param_hw(port, int, ioport, 0);
index 808eeb4..1eafe0b 100644 (file)
@@ -172,7 +172,6 @@ MODULE_PARM_DESC(wd2_timeout, "Default watchdog2 timeout in 1/10secs");
 MODULE_AUTHOR("Eric Brower <ebrower@usa.net>");
 MODULE_DESCRIPTION("Hardware watchdog driver for Sun Microsystems CP1400/1500");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("watchdog");
 
 static void cpwd_writew(u16 val, void __iomem *addr)
 {
index 7008596..747e346 100644 (file)
@@ -46,7 +46,6 @@
 
 MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
 MODULE_DESCRIPTION("Hardware watchdog driver for Sun RIO");
-MODULE_SUPPORTED_DEVICE("watchdog");
 MODULE_LICENSE("GPL");
 
 #define DRIVER_NAME    "riowd"
index da87f3a..b8f2f97 100644 (file)
@@ -47,6 +47,11 @@ static unsigned evtchn_2l_max_channels(void)
        return EVTCHN_2L_NR_CHANNELS;
 }
 
+static void evtchn_2l_remove(evtchn_port_t evtchn, unsigned int cpu)
+{
+       clear_bit(evtchn, BM(per_cpu(cpu_evtchn_mask, cpu)));
+}
+
 static void evtchn_2l_bind_to_cpu(evtchn_port_t evtchn, unsigned int cpu,
                                  unsigned int old_cpu)
 {
@@ -72,12 +77,6 @@ static bool evtchn_2l_is_pending(evtchn_port_t port)
        return sync_test_bit(port, BM(&s->evtchn_pending[0]));
 }
 
-static bool evtchn_2l_test_and_set_mask(evtchn_port_t port)
-{
-       struct shared_info *s = HYPERVISOR_shared_info;
-       return sync_test_and_set_bit(port, BM(&s->evtchn_mask[0]));
-}
-
 static void evtchn_2l_mask(evtchn_port_t port)
 {
        struct shared_info *s = HYPERVISOR_shared_info;
@@ -355,18 +354,27 @@ static void evtchn_2l_resume(void)
                                EVTCHN_2L_NR_CHANNELS/BITS_PER_EVTCHN_WORD);
 }
 
+static int evtchn_2l_percpu_deinit(unsigned int cpu)
+{
+       memset(per_cpu(cpu_evtchn_mask, cpu), 0, sizeof(xen_ulong_t) *
+                       EVTCHN_2L_NR_CHANNELS/BITS_PER_EVTCHN_WORD);
+
+       return 0;
+}
+
 static const struct evtchn_ops evtchn_ops_2l = {
        .max_channels      = evtchn_2l_max_channels,
        .nr_channels       = evtchn_2l_max_channels,
+       .remove            = evtchn_2l_remove,
        .bind_to_cpu       = evtchn_2l_bind_to_cpu,
        .clear_pending     = evtchn_2l_clear_pending,
        .set_pending       = evtchn_2l_set_pending,
        .is_pending        = evtchn_2l_is_pending,
-       .test_and_set_mask = evtchn_2l_test_and_set_mask,
        .mask              = evtchn_2l_mask,
        .unmask            = evtchn_2l_unmask,
        .handle_events     = evtchn_2l_handle_events,
        .resume            = evtchn_2l_resume,
+       .percpu_deinit     = evtchn_2l_percpu_deinit,
 };
 
 void __init xen_evtchn_2l_init(void)
index adb7260..8236e23 100644 (file)
@@ -98,13 +98,19 @@ struct irq_info {
        short refcnt;
        u8 spurious_cnt;
        u8 is_accounted;
-       enum xen_irq_type type; /* type */
+       short type;             /* type: IRQT_* */
+       u8 mask_reason;         /* Why is event channel masked */
+#define EVT_MASK_REASON_EXPLICIT       0x01
+#define EVT_MASK_REASON_TEMPORARY      0x02
+#define EVT_MASK_REASON_EOI_PENDING    0x04
+       u8 is_active;           /* Is event just being handled? */
        unsigned irq;
        evtchn_port_t evtchn;   /* event channel */
        unsigned short cpu;     /* cpu bound */
        unsigned short eoi_cpu; /* EOI must happen on this cpu-1 */
        unsigned int irq_epoch; /* If eoi_cpu valid: irq_epoch of event */
        u64 eoi_time;           /* Time in jiffies when to EOI. */
+       spinlock_t lock;
 
        union {
                unsigned short virq;
@@ -154,6 +160,7 @@ static DEFINE_RWLOCK(evtchn_rwlock);
  *   evtchn_rwlock
  *     IRQ-desc lock
  *       percpu eoi_list_lock
+ *         irq_info->lock
  */
 
 static LIST_HEAD(xen_irq_list_head);
@@ -304,6 +311,8 @@ static int xen_irq_info_common_setup(struct irq_info *info,
        info->irq = irq;
        info->evtchn = evtchn;
        info->cpu = cpu;
+       info->mask_reason = EVT_MASK_REASON_EXPLICIT;
+       spin_lock_init(&info->lock);
 
        ret = set_evtchn_to_irq(evtchn, irq);
        if (ret < 0)
@@ -377,6 +386,7 @@ static int xen_irq_info_pirq_setup(unsigned irq,
 static void xen_irq_info_cleanup(struct irq_info *info)
 {
        set_evtchn_to_irq(info->evtchn, -1);
+       xen_evtchn_port_remove(info->evtchn, info->cpu);
        info->evtchn = 0;
        channels_on_cpu_dec(info);
 }
@@ -458,6 +468,34 @@ unsigned int cpu_from_evtchn(evtchn_port_t evtchn)
        return ret;
 }
 
+static void do_mask(struct irq_info *info, u8 reason)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&info->lock, flags);
+
+       if (!info->mask_reason)
+               mask_evtchn(info->evtchn);
+
+       info->mask_reason |= reason;
+
+       spin_unlock_irqrestore(&info->lock, flags);
+}
+
+static void do_unmask(struct irq_info *info, u8 reason)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&info->lock, flags);
+
+       info->mask_reason &= ~reason;
+
+       if (!info->mask_reason)
+               unmask_evtchn(info->evtchn);
+
+       spin_unlock_irqrestore(&info->lock, flags);
+}
+
 #ifdef CONFIG_X86
 static bool pirq_check_eoi_map(unsigned irq)
 {
@@ -604,7 +642,7 @@ static void xen_irq_lateeoi_locked(struct irq_info *info, bool spurious)
        }
 
        info->eoi_time = 0;
-       unmask_evtchn(evtchn);
+       do_unmask(info, EVT_MASK_REASON_EOI_PENDING);
 }
 
 static void xen_irq_lateeoi_worker(struct work_struct *work)
@@ -773,6 +811,12 @@ static void xen_evtchn_close(evtchn_port_t port)
                BUG();
 }
 
+static void event_handler_exit(struct irq_info *info)
+{
+       smp_store_release(&info->is_active, 0);
+       clear_evtchn(info->evtchn);
+}
+
 static void pirq_query_unmask(int irq)
 {
        struct physdev_irq_status_query irq_status;
@@ -791,14 +835,15 @@ static void pirq_query_unmask(int irq)
 
 static void eoi_pirq(struct irq_data *data)
 {
-       evtchn_port_t evtchn = evtchn_from_irq(data->irq);
+       struct irq_info *info = info_for_irq(data->irq);
+       evtchn_port_t evtchn = info ? info->evtchn : 0;
        struct physdev_eoi eoi = { .irq = pirq_from_irq(data->irq) };
        int rc = 0;
 
        if (!VALID_EVTCHN(evtchn))
                return;
 
-       clear_evtchn(evtchn);
+       event_handler_exit(info);
 
        if (pirq_needs_eoi(data->irq)) {
                rc = HYPERVISOR_physdev_op(PHYSDEVOP_eoi, &eoi);
@@ -849,7 +894,8 @@ static unsigned int __startup_pirq(unsigned int irq)
                goto err;
 
 out:
-       unmask_evtchn(evtchn);
+       do_unmask(info, EVT_MASK_REASON_EXPLICIT);
+
        eoi_pirq(irq_get_irq_data(irq));
 
        return 0;
@@ -876,7 +922,7 @@ static void shutdown_pirq(struct irq_data *data)
        if (!VALID_EVTCHN(evtchn))
                return;
 
-       mask_evtchn(evtchn);
+       do_mask(info, EVT_MASK_REASON_EXPLICIT);
        xen_evtchn_close(evtchn);
        xen_irq_info_cleanup(info);
 }
@@ -1628,6 +1674,8 @@ void handle_irq_for_port(evtchn_port_t port, struct evtchn_loop_ctrl *ctrl)
        }
 
        info = info_for_irq(irq);
+       if (xchg_acquire(&info->is_active, 1))
+               return;
 
        dev = (info->type == IRQT_EVTCHN) ? info->u.interdomain : NULL;
        if (dev)
@@ -1720,10 +1768,10 @@ void rebind_evtchn_irq(evtchn_port_t evtchn, int irq)
 }
 
 /* Rebind an evtchn so that it gets delivered to a specific cpu */
-static int xen_rebind_evtchn_to_cpu(evtchn_port_t evtchn, unsigned int tcpu)
+static int xen_rebind_evtchn_to_cpu(struct irq_info *info, unsigned int tcpu)
 {
        struct evtchn_bind_vcpu bind_vcpu;
-       int masked;
+       evtchn_port_t evtchn = info ? info->evtchn : 0;
 
        if (!VALID_EVTCHN(evtchn))
                return -1;
@@ -1739,7 +1787,7 @@ static int xen_rebind_evtchn_to_cpu(evtchn_port_t evtchn, unsigned int tcpu)
         * Mask the event while changing the VCPU binding to prevent
         * it being delivered on an unexpected VCPU.
         */
-       masked = test_and_set_mask(evtchn);
+       do_mask(info, EVT_MASK_REASON_TEMPORARY);
 
        /*
         * If this fails, it usually just indicates that we're dealing with a
@@ -1749,8 +1797,7 @@ static int xen_rebind_evtchn_to_cpu(evtchn_port_t evtchn, unsigned int tcpu)
        if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu) >= 0)
                bind_evtchn_to_cpu(evtchn, tcpu, false);
 
-       if (!masked)
-               unmask_evtchn(evtchn);
+       do_unmask(info, EVT_MASK_REASON_TEMPORARY);
 
        return 0;
 }
@@ -1789,7 +1836,7 @@ static int set_affinity_irq(struct irq_data *data, const struct cpumask *dest,
        unsigned int tcpu = select_target_cpu(dest);
        int ret;
 
-       ret = xen_rebind_evtchn_to_cpu(evtchn_from_irq(data->irq), tcpu);
+       ret = xen_rebind_evtchn_to_cpu(info_for_irq(data->irq), tcpu);
        if (!ret)
                irq_data_update_effective_affinity(data, cpumask_of(tcpu));
 
@@ -1798,28 +1845,29 @@ static int set_affinity_irq(struct irq_data *data, const struct cpumask *dest,
 
 static void enable_dynirq(struct irq_data *data)
 {
-       evtchn_port_t evtchn = evtchn_from_irq(data->irq);
+       struct irq_info *info = info_for_irq(data->irq);
+       evtchn_port_t evtchn = info ? info->evtchn : 0;
 
        if (VALID_EVTCHN(evtchn))
-               unmask_evtchn(evtchn);
+               do_unmask(info, EVT_MASK_REASON_EXPLICIT);
 }
 
 static void disable_dynirq(struct irq_data *data)
 {
-       evtchn_port_t evtchn = evtchn_from_irq(data->irq);
+       struct irq_info *info = info_for_irq(data->irq);
+       evtchn_port_t evtchn = info ? info->evtchn : 0;
 
        if (VALID_EVTCHN(evtchn))
-               mask_evtchn(evtchn);
+               do_mask(info, EVT_MASK_REASON_EXPLICIT);
 }
 
 static void ack_dynirq(struct irq_data *data)
 {
-       evtchn_port_t evtchn = evtchn_from_irq(data->irq);
+       struct irq_info *info = info_for_irq(data->irq);
+       evtchn_port_t evtchn = info ? info->evtchn : 0;
 
-       if (!VALID_EVTCHN(evtchn))
-               return;
-
-       clear_evtchn(evtchn);
+       if (VALID_EVTCHN(evtchn))
+               event_handler_exit(info);
 }
 
 static void mask_ack_dynirq(struct irq_data *data)
@@ -1828,18 +1876,39 @@ static void mask_ack_dynirq(struct irq_data *data)
        ack_dynirq(data);
 }
 
+static void lateeoi_ack_dynirq(struct irq_data *data)
+{
+       struct irq_info *info = info_for_irq(data->irq);
+       evtchn_port_t evtchn = info ? info->evtchn : 0;
+
+       if (VALID_EVTCHN(evtchn)) {
+               do_mask(info, EVT_MASK_REASON_EOI_PENDING);
+               event_handler_exit(info);
+       }
+}
+
+static void lateeoi_mask_ack_dynirq(struct irq_data *data)
+{
+       struct irq_info *info = info_for_irq(data->irq);
+       evtchn_port_t evtchn = info ? info->evtchn : 0;
+
+       if (VALID_EVTCHN(evtchn)) {
+               do_mask(info, EVT_MASK_REASON_EXPLICIT);
+               event_handler_exit(info);
+       }
+}
+
 static int retrigger_dynirq(struct irq_data *data)
 {
-       evtchn_port_t evtchn = evtchn_from_irq(data->irq);
-       int masked;
+       struct irq_info *info = info_for_irq(data->irq);
+       evtchn_port_t evtchn = info ? info->evtchn : 0;
 
        if (!VALID_EVTCHN(evtchn))
                return 0;
 
-       masked = test_and_set_mask(evtchn);
+       do_mask(info, EVT_MASK_REASON_TEMPORARY);
        set_evtchn(evtchn);
-       if (!masked)
-               unmask_evtchn(evtchn);
+       do_unmask(info, EVT_MASK_REASON_TEMPORARY);
 
        return 1;
 }
@@ -1938,10 +2007,11 @@ static void restore_cpu_ipis(unsigned int cpu)
 /* Clear an irq's pending state, in preparation for polling on it */
 void xen_clear_irq_pending(int irq)
 {
-       evtchn_port_t evtchn = evtchn_from_irq(irq);
+       struct irq_info *info = info_for_irq(irq);
+       evtchn_port_t evtchn = info ? info->evtchn : 0;
 
        if (VALID_EVTCHN(evtchn))
-               clear_evtchn(evtchn);
+               event_handler_exit(info);
 }
 EXPORT_SYMBOL(xen_clear_irq_pending);
 void xen_set_irq_pending(int irq)
@@ -2053,8 +2123,8 @@ static struct irq_chip xen_lateeoi_chip __read_mostly = {
        .irq_mask               = disable_dynirq,
        .irq_unmask             = enable_dynirq,
 
-       .irq_ack                = mask_ack_dynirq,
-       .irq_mask_ack           = mask_ack_dynirq,
+       .irq_ack                = lateeoi_ack_dynirq,
+       .irq_mask_ack           = lateeoi_mask_ack_dynirq,
 
        .irq_set_affinity       = set_affinity_irq,
        .irq_retrigger          = retrigger_dynirq,
index b234f17..ad9fe51 100644 (file)
@@ -209,12 +209,6 @@ static bool evtchn_fifo_is_pending(evtchn_port_t port)
        return sync_test_bit(EVTCHN_FIFO_BIT(PENDING, word), BM(word));
 }
 
-static bool evtchn_fifo_test_and_set_mask(evtchn_port_t port)
-{
-       event_word_t *word = event_word_from_port(port);
-       return sync_test_and_set_bit(EVTCHN_FIFO_BIT(MASKED, word), BM(word));
-}
-
 static void evtchn_fifo_mask(evtchn_port_t port)
 {
        event_word_t *word = event_word_from_port(port);
@@ -423,7 +417,6 @@ static const struct evtchn_ops evtchn_ops_fifo = {
        .clear_pending     = evtchn_fifo_clear_pending,
        .set_pending       = evtchn_fifo_set_pending,
        .is_pending        = evtchn_fifo_is_pending,
-       .test_and_set_mask = evtchn_fifo_test_and_set_mask,
        .mask              = evtchn_fifo_mask,
        .unmask            = evtchn_fifo_unmask,
        .handle_events     = evtchn_fifo_handle_events,
index 0a97c05..4d3398e 100644 (file)
@@ -14,13 +14,13 @@ struct evtchn_ops {
        unsigned (*nr_channels)(void);
 
        int (*setup)(evtchn_port_t port);
+       void (*remove)(evtchn_port_t port, unsigned int cpu);
        void (*bind_to_cpu)(evtchn_port_t evtchn, unsigned int cpu,
                            unsigned int old_cpu);
 
        void (*clear_pending)(evtchn_port_t port);
        void (*set_pending)(evtchn_port_t port);
        bool (*is_pending)(evtchn_port_t port);
-       bool (*test_and_set_mask)(evtchn_port_t port);
        void (*mask)(evtchn_port_t port);
        void (*unmask)(evtchn_port_t port);
 
@@ -54,6 +54,13 @@ static inline int xen_evtchn_port_setup(evtchn_port_t evtchn)
        return 0;
 }
 
+static inline void xen_evtchn_port_remove(evtchn_port_t evtchn,
+                                         unsigned int cpu)
+{
+       if (evtchn_ops->remove)
+               evtchn_ops->remove(evtchn, cpu);
+}
+
 static inline void xen_evtchn_port_bind_to_cpu(evtchn_port_t evtchn,
                                               unsigned int cpu,
                                               unsigned int old_cpu)
@@ -76,11 +83,6 @@ static inline bool test_evtchn(evtchn_port_t port)
        return evtchn_ops->is_pending(port);
 }
 
-static inline bool test_and_set_mask(evtchn_port_t port)
-{
-       return evtchn_ops->test_and_set_mask(port);
-}
-
 static inline void mask_evtchn(evtchn_port_t port)
 {
        return evtchn_ops->mask(port);
index 5447c51..f01d58c 100644 (file)
@@ -133,20 +133,26 @@ struct gntdev_grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count,
        if (NULL == add)
                return NULL;
 
-       add->grants    = kvcalloc(count, sizeof(add->grants[0]), GFP_KERNEL);
-       add->map_ops   = kvcalloc(count, sizeof(add->map_ops[0]), GFP_KERNEL);
-       add->unmap_ops = kvcalloc(count, sizeof(add->unmap_ops[0]), GFP_KERNEL);
-       add->kmap_ops  = kvcalloc(count, sizeof(add->kmap_ops[0]), GFP_KERNEL);
-       add->kunmap_ops = kvcalloc(count,
-                                  sizeof(add->kunmap_ops[0]), GFP_KERNEL);
+       add->grants    = kvmalloc_array(count, sizeof(add->grants[0]),
+                                       GFP_KERNEL);
+       add->map_ops   = kvmalloc_array(count, sizeof(add->map_ops[0]),
+                                       GFP_KERNEL);
+       add->unmap_ops = kvmalloc_array(count, sizeof(add->unmap_ops[0]),
+                                       GFP_KERNEL);
        add->pages     = kvcalloc(count, sizeof(add->pages[0]), GFP_KERNEL);
        if (NULL == add->grants    ||
            NULL == add->map_ops   ||
            NULL == add->unmap_ops ||
-           NULL == add->kmap_ops  ||
-           NULL == add->kunmap_ops ||
            NULL == add->pages)
                goto err;
+       if (use_ptemod) {
+               add->kmap_ops   = kvmalloc_array(count, sizeof(add->kmap_ops[0]),
+                                                GFP_KERNEL);
+               add->kunmap_ops = kvmalloc_array(count, sizeof(add->kunmap_ops[0]),
+                                                GFP_KERNEL);
+               if (NULL == add->kmap_ops || NULL == add->kunmap_ops)
+                       goto err;
+       }
 
 #ifdef CONFIG_XEN_GRANT_DMA_ALLOC
        add->dma_flags = dma_flags;
@@ -183,10 +189,14 @@ struct gntdev_grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count,
                goto err;
 
        for (i = 0; i < count; i++) {
-               add->map_ops[i].handle = -1;
-               add->unmap_ops[i].handle = -1;
-               add->kmap_ops[i].handle = -1;
-               add->kunmap_ops[i].handle = -1;
+               add->grants[i].domid = DOMID_INVALID;
+               add->grants[i].ref = INVALID_GRANT_REF;
+               add->map_ops[i].handle = INVALID_GRANT_HANDLE;
+               add->unmap_ops[i].handle = INVALID_GRANT_HANDLE;
+               if (use_ptemod) {
+                       add->kmap_ops[i].handle = INVALID_GRANT_HANDLE;
+                       add->kunmap_ops[i].handle = INVALID_GRANT_HANDLE;
+               }
        }
 
        add->index = 0;
@@ -274,7 +284,7 @@ static int find_grant_ptes(pte_t *pte, unsigned long addr, void *data)
                          map->grants[pgnr].ref,
                          map->grants[pgnr].domid);
        gnttab_set_unmap_op(&map->unmap_ops[pgnr], pte_maddr, flags,
-                           -1 /* handle */);
+                           INVALID_GRANT_HANDLE);
        return 0;
 }
 
@@ -292,7 +302,7 @@ int gntdev_map_grant_pages(struct gntdev_grant_map *map)
 
        if (!use_ptemod) {
                /* Note: it could already be mapped */
-               if (map->map_ops[0].handle != -1)
+               if (map->map_ops[0].handle != INVALID_GRANT_HANDLE)
                        return 0;
                for (i = 0; i < map->count; i++) {
                        unsigned long addr = (unsigned long)
@@ -301,7 +311,7 @@ int gntdev_map_grant_pages(struct gntdev_grant_map *map)
                                map->grants[i].ref,
                                map->grants[i].domid);
                        gnttab_set_unmap_op(&map->unmap_ops[i], addr,
-                               map->flags, -1 /* handle */);
+                               map->flags, INVALID_GRANT_HANDLE);
                }
        } else {
                /*
@@ -327,13 +337,13 @@ int gntdev_map_grant_pages(struct gntdev_grant_map *map)
                                map->grants[i].ref,
                                map->grants[i].domid);
                        gnttab_set_unmap_op(&map->kunmap_ops[i], address,
-                               flags, -1);
+                               flags, INVALID_GRANT_HANDLE);
                }
        }
 
        pr_debug("map %d+%d\n", map->index, map->count);
-       err = gnttab_map_refs(map->map_ops, use_ptemod ? map->kmap_ops : NULL,
-                       map->pages, map->count);
+       err = gnttab_map_refs(map->map_ops, map->kmap_ops, map->pages,
+                       map->count);
 
        for (i = 0; i < map->count; i++) {
                if (map->map_ops[i].status == GNTST_okay)
@@ -385,7 +395,7 @@ static int __unmap_grant_pages(struct gntdev_grant_map *map, int offset,
                pr_debug("unmap handle=%d st=%d\n",
                        map->unmap_ops[offset+i].handle,
                        map->unmap_ops[offset+i].status);
-               map->unmap_ops[offset+i].handle = -1;
+               map->unmap_ops[offset+i].handle = INVALID_GRANT_HANDLE;
        }
        return err;
 }
@@ -401,13 +411,15 @@ static int unmap_grant_pages(struct gntdev_grant_map *map, int offset,
         * already unmapped some of the grants. Only unmap valid ranges.
         */
        while (pages && !err) {
-               while (pages && map->unmap_ops[offset].handle == -1) {
+               while (pages &&
+                      map->unmap_ops[offset].handle == INVALID_GRANT_HANDLE) {
                        offset++;
                        pages--;
                }
                range = 0;
                while (range < pages) {
-                       if (map->unmap_ops[offset+range].handle == -1)
+                       if (map->unmap_ops[offset + range].handle ==
+                           INVALID_GRANT_HANDLE)
                                break;
                        range++;
                }
index 462253a..a55bda4 100644 (file)
@@ -203,7 +203,7 @@ config TMPFS_XATTR
 
 config TMPFS_INODE64
        bool "Use 64-bit ino_t by default in tmpfs"
-       depends on TMPFS && 64BIT && !(S390 || ALPHA)
+       depends on TMPFS && 64BIT
        default n
        help
          tmpfs has historically used only inode numbers as wide as an unsigned
index 714fcca..17548c1 100644 (file)
@@ -70,7 +70,6 @@ const struct inode_operations afs_dir_inode_operations = {
        .permission     = afs_permission,
        .getattr        = afs_getattr,
        .setattr        = afs_setattr,
-       .listxattr      = afs_listxattr,
 };
 
 const struct address_space_operations afs_dir_aops = {
index 85f5adf..960b642 100644 (file)
@@ -43,7 +43,6 @@ const struct inode_operations afs_file_inode_operations = {
        .getattr        = afs_getattr,
        .setattr        = afs_setattr,
        .permission     = afs_permission,
-       .listxattr      = afs_listxattr,
 };
 
 const struct address_space_operations afs_fs_aops = {
index 97cab12..71c5872 100644 (file)
@@ -181,10 +181,13 @@ void afs_wait_for_operation(struct afs_operation *op)
                if (test_bit(AFS_SERVER_FL_IS_YFS, &op->server->flags) &&
                    op->ops->issue_yfs_rpc)
                        op->ops->issue_yfs_rpc(op);
-               else
+               else if (op->ops->issue_afs_rpc)
                        op->ops->issue_afs_rpc(op);
+               else
+                       op->ac.error = -ENOTSUPP;
 
-               op->error = afs_wait_for_call_to_complete(op->call, &op->ac);
+               if (op->call)
+                       op->error = afs_wait_for_call_to_complete(op->call, &op->ac);
        }
 
        switch (op->error) {
index 1156b2d..12be887 100644 (file)
@@ -27,7 +27,6 @@
 
 static const struct inode_operations afs_symlink_inode_operations = {
        .get_link       = page_get_link,
-       .listxattr      = afs_listxattr,
 };
 
 static noinline void dump_vnode(struct afs_vnode *vnode, struct afs_vnode *parent_vnode)
index b626e38..1627b18 100644 (file)
@@ -1509,7 +1509,6 @@ extern int afs_launder_page(struct page *);
  * xattr.c
  */
 extern const struct xattr_handler *afs_xattr_handlers[];
-extern ssize_t afs_listxattr(struct dentry *, char *, size_t);
 
 /*
  * yfsclient.c
index 052dab2..bbb2c21 100644 (file)
@@ -32,7 +32,6 @@ const struct inode_operations afs_mntpt_inode_operations = {
        .lookup         = afs_mntpt_lookup,
        .readlink       = page_readlink,
        .getattr        = afs_getattr,
-       .listxattr      = afs_listxattr,
 };
 
 const struct inode_operations afs_autocell_inode_operations = {
index c629caa..7751b0b 100644 (file)
 #include <linux/xattr.h>
 #include "internal.h"
 
-static const char afs_xattr_list[] =
-       "afs.acl\0"
-       "afs.cell\0"
-       "afs.fid\0"
-       "afs.volume\0"
-       "afs.yfs.acl\0"
-       "afs.yfs.acl_inherited\0"
-       "afs.yfs.acl_num_cleaned\0"
-       "afs.yfs.vol_acl";
-
-/*
- * Retrieve a list of the supported xattrs.
- */
-ssize_t afs_listxattr(struct dentry *dentry, char *buffer, size_t size)
-{
-       if (size == 0)
-               return sizeof(afs_xattr_list);
-       if (size < sizeof(afs_xattr_list))
-               return -ERANGE;
-       memcpy(buffer, afs_xattr_list, sizeof(afs_xattr_list));
-       return sizeof(afs_xattr_list);
-}
-
 /*
  * Deal with the result of a successful fetch ACL operation.
  */
@@ -231,6 +208,8 @@ static int afs_xattr_get_yfs(const struct xattr_handler *handler,
                        else
                                ret = -ERANGE;
                }
+       } else if (ret == -ENOTSUPP) {
+               ret = -ENODATA;
        }
 
 error_yacl:
@@ -256,6 +235,7 @@ static int afs_xattr_set_yfs(const struct xattr_handler *handler,
 {
        struct afs_operation *op;
        struct afs_vnode *vnode = AFS_FS_I(inode);
+       int ret;
 
        if (flags == XATTR_CREATE ||
            strcmp(name, "acl") != 0)
@@ -270,7 +250,10 @@ static int afs_xattr_set_yfs(const struct xattr_handler *handler,
                return afs_put_operation(op);
 
        op->ops = &yfs_store_opaque_acl2_operation;
-       return afs_do_sync_operation(op);
+       ret = afs_do_sync_operation(op);
+       if (ret == -ENOTSUPP)
+               ret = -ENODATA;
+       return ret;
 }
 
 static const struct xattr_handler afs_xattr_yfs_handler = {
index c457334..e1eae7e 100644 (file)
@@ -649,12 +649,24 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer,
        struct super_block *sb = file_inode(file)->i_sb;
        struct dentry *root = sb->s_root, *dentry;
        int err = 0;
+       struct file *f = NULL;
 
        e = create_entry(buffer, count);
 
        if (IS_ERR(e))
                return PTR_ERR(e);
 
+       if (e->flags & MISC_FMT_OPEN_FILE) {
+               f = open_exec(e->interpreter);
+               if (IS_ERR(f)) {
+                       pr_notice("register: failed to install interpreter file %s\n",
+                                e->interpreter);
+                       kfree(e);
+                       return PTR_ERR(f);
+               }
+               e->interp_file = f;
+       }
+
        inode_lock(d_inode(root));
        dentry = lookup_one_len(e->name, root, strlen(e->name));
        err = PTR_ERR(dentry);
@@ -678,21 +690,6 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer,
                goto out2;
        }
 
-       if (e->flags & MISC_FMT_OPEN_FILE) {
-               struct file *f;
-
-               f = open_exec(e->interpreter);
-               if (IS_ERR(f)) {
-                       err = PTR_ERR(f);
-                       pr_notice("register: failed to install interpreter file %s\n", e->interpreter);
-                       simple_release_fs(&bm_mnt, &entry_count);
-                       iput(inode);
-                       inode = NULL;
-                       goto out2;
-               }
-               e->interp_file = f;
-       }
-
        e->dentry = dget(dentry);
        inode->i_private = e;
        inode->i_fop = &bm_entry_operations;
@@ -709,6 +706,8 @@ out:
        inode_unlock(d_inode(root));
 
        if (err) {
+               if (f)
+                       filp_close(f, NULL);
                kfree(e);
                return err;
        }
index 4aa1f88..92ed7d5 100644 (file)
@@ -118,13 +118,22 @@ int truncate_bdev_range(struct block_device *bdev, fmode_t mode,
        if (!(mode & FMODE_EXCL)) {
                int err = bd_prepare_to_claim(bdev, truncate_bdev_range);
                if (err)
-                       return err;
+                       goto invalidate;
        }
 
        truncate_inode_pages_range(bdev->bd_inode->i_mapping, lstart, lend);
        if (!(mode & FMODE_EXCL))
                bd_abort_claiming(bdev, truncate_bdev_range);
        return 0;
+
+invalidate:
+       /*
+        * Someone else has handle exclusively open. Try invalidating instead.
+        * The 'end' argument is inclusive so the rounding is safe.
+        */
+       return invalidate_inode_pages2_range(bdev->bd_inode->i_mapping,
+                                            lstart >> PAGE_SHIFT,
+                                            lend >> PAGE_SHIFT);
 }
 
 static void set_init_blocksize(struct block_device *bdev)
@@ -423,7 +432,7 @@ static ssize_t __blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
                dio->size += bio->bi_iter.bi_size;
                pos += bio->bi_iter.bi_size;
 
-               nr_pages = bio_iov_vecs_to_alloc(iter, BIO_MAX_PAGES);
+               nr_pages = bio_iov_vecs_to_alloc(iter, BIO_MAX_VECS);
                if (!nr_pages) {
                        bool polled = false;
 
@@ -491,8 +500,8 @@ blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
        if (!iov_iter_count(iter))
                return 0;
 
-       nr_pages = bio_iov_vecs_to_alloc(iter, BIO_MAX_PAGES + 1);
-       if (is_sync_kiocb(iocb) && nr_pages <= BIO_MAX_PAGES)
+       nr_pages = bio_iov_vecs_to_alloc(iter, BIO_MAX_VECS + 1);
+       if (is_sync_kiocb(iocb) && nr_pages <= BIO_MAX_VECS)
                return __blkdev_direct_IO_simple(iocb, iter, nr_pages);
 
        return __blkdev_direct_IO(iocb, iter, bio_max_segs(nr_pages));
index d56730a..34b929b 100644 (file)
@@ -1365,7 +1365,9 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
                                   "failed to read tree block %llu from get_old_root",
                                   logical);
                } else {
+                       btrfs_tree_read_lock(old);
                        eb = btrfs_clone_extent_buffer(old);
+                       btrfs_tree_read_unlock(old);
                        free_extent_buffer(old);
                }
        } else if (old_root) {
index 78ad31a..36a3c97 100644 (file)
@@ -3323,6 +3323,7 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
 
        if (last_ref && btrfs_header_generation(buf) == trans->transid) {
                struct btrfs_block_group *cache;
+               bool must_pin = false;
 
                if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) {
                        ret = check_ref_cleanup(trans, buf->start);
@@ -3340,7 +3341,27 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
                        goto out;
                }
 
-               if (btrfs_is_zoned(fs_info)) {
+               /*
+                * If this is a leaf and there are tree mod log users, we may
+                * have recorded mod log operations that point to this leaf.
+                * So we must make sure no one reuses this leaf's extent before
+                * mod log operations are applied to a node, otherwise after
+                * rewinding a node using the mod log operations we get an
+                * inconsistent btree, as the leaf's extent may now be used as
+                * a node or leaf for another different btree.
+                * We are safe from races here because at this point no other
+                * node or root points to this extent buffer, so if after this
+                * check a new tree mod log user joins, it will not be able to
+                * find a node pointing to this leaf and record operations that
+                * point to this leaf.
+                */
+               if (btrfs_header_level(buf) == 0) {
+                       read_lock(&fs_info->tree_mod_log_lock);
+                       must_pin = !list_empty(&fs_info->tree_mod_seq_list);
+                       read_unlock(&fs_info->tree_mod_log_lock);
+               }
+
+               if (must_pin || btrfs_is_zoned(fs_info)) {
                        btrfs_redirty_list_add(trans->transaction, buf);
                        pin_down_extent(trans, cache, buf->start, buf->len, 1);
                        btrfs_put_block_group(cache);
index 4671c99..910769d 100644 (file)
@@ -2885,6 +2885,35 @@ static void end_page_read(struct page *page, bool uptodate, u64 start, u32 len)
                btrfs_subpage_end_reader(fs_info, page, start, len);
 }
 
+/*
+ * Find extent buffer for a givne bytenr.
+ *
+ * This is for end_bio_extent_readpage(), thus we can't do any unsafe locking
+ * in endio context.
+ */
+static struct extent_buffer *find_extent_buffer_readpage(
+               struct btrfs_fs_info *fs_info, struct page *page, u64 bytenr)
+{
+       struct extent_buffer *eb;
+
+       /*
+        * For regular sectorsize, we can use page->private to grab extent
+        * buffer
+        */
+       if (fs_info->sectorsize == PAGE_SIZE) {
+               ASSERT(PagePrivate(page) && page->private);
+               return (struct extent_buffer *)page->private;
+       }
+
+       /* For subpage case, we need to lookup buffer radix tree */
+       rcu_read_lock();
+       eb = radix_tree_lookup(&fs_info->buffer_radix,
+                              bytenr >> fs_info->sectorsize_bits);
+       rcu_read_unlock();
+       ASSERT(eb);
+       return eb;
+}
+
 /*
  * after a readpage IO is done, we need to:
  * clear the uptodate bits on error
@@ -2996,7 +3025,7 @@ static void end_bio_extent_readpage(struct bio *bio)
                } else {
                        struct extent_buffer *eb;
 
-                       eb = (struct extent_buffer *)page->private;
+                       eb = find_extent_buffer_readpage(fs_info, page, start);
                        set_bit(EXTENT_BUFFER_READ_ERR, &eb->bflags);
                        eb->read_mirror = mirror;
                        atomic_dec(&eb->io_pages);
@@ -3020,7 +3049,7 @@ readpage_ok:
                         */
                        if (page->index == end_index && i_size <= end) {
                                u32 zero_start = max(offset_in_page(i_size),
-                                                    offset_in_page(end));
+                                                    offset_in_page(start));
 
                                zero_user_segment(page, zero_start,
                                                  offset_in_page(end) + 1);
@@ -3059,7 +3088,7 @@ struct bio *btrfs_bio_alloc(u64 first_byte)
 {
        struct bio *bio;
 
-       bio = bio_alloc_bioset(GFP_NOFS, BIO_MAX_PAGES, &btrfs_bioset);
+       bio = bio_alloc_bioset(GFP_NOFS, BIO_MAX_VECS, &btrfs_bioset);
        bio->bi_iter.bi_sector = first_byte >> 9;
        btrfs_io_bio_init(btrfs_io_bio(bio));
        return bio;
index 35bfa05..7cdf65b 100644 (file)
@@ -9008,7 +9008,7 @@ int __init btrfs_init_cachep(void)
 
        btrfs_free_space_bitmap_cachep = kmem_cache_create("btrfs_free_space_bitmap",
                                                        PAGE_SIZE, PAGE_SIZE,
-                                                       SLAB_RED_ZONE, NULL);
+                                                       SLAB_MEM_SPREAD, NULL);
        if (!btrfs_free_space_bitmap_cachep)
                goto fail;
 
@@ -9877,6 +9877,7 @@ static struct btrfs_trans_handle *insert_prealloc_file_extent(
        struct btrfs_path *path;
        u64 start = ins->objectid;
        u64 len = ins->offset;
+       int qgroup_released;
        int ret;
 
        memset(&stack_fi, 0, sizeof(stack_fi));
@@ -9889,16 +9890,16 @@ static struct btrfs_trans_handle *insert_prealloc_file_extent(
        btrfs_set_stack_file_extent_compression(&stack_fi, BTRFS_COMPRESS_NONE);
        /* Encryption and other encoding is reserved and all 0 */
 
-       ret = btrfs_qgroup_release_data(inode, file_offset, len);
-       if (ret < 0)
-               return ERR_PTR(ret);
+       qgroup_released = btrfs_qgroup_release_data(inode, file_offset, len);
+       if (qgroup_released < 0)
+               return ERR_PTR(qgroup_released);
 
        if (trans) {
                ret = insert_reserved_file_extent(trans, inode,
                                                  file_offset, &stack_fi,
-                                                 true, ret);
+                                                 true, qgroup_released);
                if (ret)
-                       return ERR_PTR(ret);
+                       goto free_qgroup;
                return trans;
        }
 
@@ -9909,21 +9910,35 @@ static struct btrfs_trans_handle *insert_prealloc_file_extent(
        extent_info.file_offset = file_offset;
        extent_info.extent_buf = (char *)&stack_fi;
        extent_info.is_new_extent = true;
-       extent_info.qgroup_reserved = ret;
+       extent_info.qgroup_reserved = qgroup_released;
        extent_info.insertions = 0;
 
        path = btrfs_alloc_path();
-       if (!path)
-               return ERR_PTR(-ENOMEM);
+       if (!path) {
+               ret = -ENOMEM;
+               goto free_qgroup;
+       }
 
        ret = btrfs_replace_file_extents(&inode->vfs_inode, path, file_offset,
                                     file_offset + len - 1, &extent_info,
                                     &trans);
        btrfs_free_path(path);
        if (ret)
-               return ERR_PTR(ret);
-
+               goto free_qgroup;
        return trans;
+
+free_qgroup:
+       /*
+        * We have released qgroup data range at the beginning of the function,
+        * and normally qgroup_released bytes will be freed when committing
+        * transaction.
+        * But if we error out early, we have to free what we have released
+        * or we leak qgroup data reservation.
+        */
+       btrfs_qgroup_free_refroot(inode->root->fs_info,
+                       inode->root->root_key.objectid, qgroup_released,
+                       BTRFS_QGROUP_RSV_DATA);
+       return ERR_PTR(ret);
 }
 
 static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
index 20fd4aa..06713a8 100644 (file)
@@ -209,7 +209,7 @@ int btree_readahead_hook(struct extent_buffer *eb, int err)
        /* find extent */
        spin_lock(&fs_info->reada_lock);
        re = radix_tree_lookup(&fs_info->reada_tree,
-                              eb->start >> PAGE_SHIFT);
+                              eb->start >> fs_info->sectorsize_bits);
        if (re)
                re->refcnt++;
        spin_unlock(&fs_info->reada_lock);
@@ -240,7 +240,7 @@ static struct reada_zone *reada_find_zone(struct btrfs_device *dev, u64 logical,
        zone = NULL;
        spin_lock(&fs_info->reada_lock);
        ret = radix_tree_gang_lookup(&dev->reada_zones, (void **)&zone,
-                                    logical >> PAGE_SHIFT, 1);
+                                    logical >> fs_info->sectorsize_bits, 1);
        if (ret == 1 && logical >= zone->start && logical <= zone->end) {
                kref_get(&zone->refcnt);
                spin_unlock(&fs_info->reada_lock);
@@ -283,13 +283,13 @@ static struct reada_zone *reada_find_zone(struct btrfs_device *dev, u64 logical,
 
        spin_lock(&fs_info->reada_lock);
        ret = radix_tree_insert(&dev->reada_zones,
-                               (unsigned long)(zone->end >> PAGE_SHIFT),
-                               zone);
+                       (unsigned long)(zone->end >> fs_info->sectorsize_bits),
+                       zone);
 
        if (ret == -EEXIST) {
                kfree(zone);
                ret = radix_tree_gang_lookup(&dev->reada_zones, (void **)&zone,
-                                            logical >> PAGE_SHIFT, 1);
+                                       logical >> fs_info->sectorsize_bits, 1);
                if (ret == 1 && logical >= zone->start && logical <= zone->end)
                        kref_get(&zone->refcnt);
                else
@@ -315,7 +315,7 @@ static struct reada_extent *reada_find_extent(struct btrfs_fs_info *fs_info,
        u64 length;
        int real_stripes;
        int nzones = 0;
-       unsigned long index = logical >> PAGE_SHIFT;
+       unsigned long index = logical >> fs_info->sectorsize_bits;
        int dev_replace_is_ongoing;
        int have_zone = 0;
 
@@ -497,7 +497,7 @@ static void reada_extent_put(struct btrfs_fs_info *fs_info,
                             struct reada_extent *re)
 {
        int i;
-       unsigned long index = re->logical >> PAGE_SHIFT;
+       unsigned long index = re->logical >> fs_info->sectorsize_bits;
 
        spin_lock(&fs_info->reada_lock);
        if (--re->refcnt) {
@@ -538,11 +538,12 @@ static void reada_extent_put(struct btrfs_fs_info *fs_info,
 static void reada_zone_release(struct kref *kref)
 {
        struct reada_zone *zone = container_of(kref, struct reada_zone, refcnt);
+       struct btrfs_fs_info *fs_info = zone->device->fs_info;
 
-       lockdep_assert_held(&zone->device->fs_info->reada_lock);
+       lockdep_assert_held(&fs_info->reada_lock);
 
        radix_tree_delete(&zone->device->reada_zones,
-                         zone->end >> PAGE_SHIFT);
+                         zone->end >> fs_info->sectorsize_bits);
 
        kfree(zone);
 }
@@ -593,7 +594,7 @@ static int reada_add_block(struct reada_control *rc, u64 logical,
 static void reada_peer_zones_set_lock(struct reada_zone *zone, int lock)
 {
        int i;
-       unsigned long index = zone->end >> PAGE_SHIFT;
+       unsigned long index = zone->end >> zone->device->fs_info->sectorsize_bits;
 
        for (i = 0; i < zone->ndevs; ++i) {
                struct reada_zone *peer;
@@ -628,7 +629,7 @@ static int reada_pick_zone(struct btrfs_device *dev)
                                             (void **)&zone, index, 1);
                if (ret == 0)
                        break;
-               index = (zone->end >> PAGE_SHIFT) + 1;
+               index = (zone->end >> dev->fs_info->sectorsize_bits) + 1;
                if (zone->locked) {
                        if (zone->elems > top_locked_elems) {
                                top_locked_elems = zone->elems;
@@ -709,7 +710,7 @@ static int reada_start_machine_dev(struct btrfs_device *dev)
         * plugging to speed things up
         */
        ret = radix_tree_gang_lookup(&dev->reada_extents, (void **)&re,
-                                    dev->reada_next >> PAGE_SHIFT, 1);
+                               dev->reada_next >> fs_info->sectorsize_bits, 1);
        if (ret == 0 || re->logical > dev->reada_curr_zone->end) {
                ret = reada_pick_zone(dev);
                if (!ret) {
@@ -718,7 +719,7 @@ static int reada_start_machine_dev(struct btrfs_device *dev)
                }
                re = NULL;
                ret = radix_tree_gang_lookup(&dev->reada_extents, (void **)&re,
-                                       dev->reada_next >> PAGE_SHIFT, 1);
+                               dev->reada_next >> fs_info->sectorsize_bits, 1);
        }
        if (ret == 0) {
                spin_unlock(&fs_info->reada_lock);
@@ -885,7 +886,7 @@ static void dump_devs(struct btrfs_fs_info *fs_info, int all)
                                pr_cont(" curr off %llu",
                                        device->reada_next - zone->start);
                        pr_cont("\n");
-                       index = (zone->end >> PAGE_SHIFT) + 1;
+                       index = (zone->end >> fs_info->sectorsize_bits) + 1;
                }
                cnt = 0;
                index = 0;
@@ -910,7 +911,7 @@ static void dump_devs(struct btrfs_fs_info *fs_info, int all)
                                }
                        }
                        pr_cont("\n");
-                       index = (re->logical >> PAGE_SHIFT) + 1;
+                       index = (re->logical >> fs_info->sectorsize_bits) + 1;
                        if (++cnt > 15)
                                break;
                }
@@ -926,7 +927,7 @@ static void dump_devs(struct btrfs_fs_info *fs_info, int all)
                if (ret == 0)
                        break;
                if (!re->scheduled) {
-                       index = (re->logical >> PAGE_SHIFT) + 1;
+                       index = (re->logical >> fs_info->sectorsize_bits) + 1;
                        continue;
                }
                pr_debug("re: logical %llu size %u list empty %d scheduled %d",
@@ -942,7 +943,7 @@ static void dump_devs(struct btrfs_fs_info *fs_info, int all)
                        }
                }
                pr_cont("\n");
-               index = (re->logical >> PAGE_SHIFT) + 1;
+               index = (re->logical >> fs_info->sectorsize_bits) + 1;
        }
        spin_unlock(&fs_info->reada_lock);
 }
index c2900eb..3d9088e 100644 (file)
@@ -1428,7 +1428,7 @@ static void scrub_recheck_block_on_raid56(struct btrfs_fs_info *fs_info,
        if (!first_page->dev->bdev)
                goto out;
 
-       bio = btrfs_io_bio_alloc(BIO_MAX_PAGES);
+       bio = btrfs_io_bio_alloc(BIO_MAX_VECS);
        bio_set_dev(bio, first_page->dev->bdev);
 
        for (page_num = 0; page_num < sblock->page_count; page_num++) {
index 2f1acc9..92a3686 100644 (file)
@@ -3169,10 +3169,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
 
        mutex_lock(&log_root_tree->log_mutex);
 
-       index2 = log_root_tree->log_transid % 2;
-       list_add_tail(&root_log_ctx.list, &log_root_tree->log_ctxs[index2]);
-       root_log_ctx.log_transid = log_root_tree->log_transid;
-
        if (btrfs_is_zoned(fs_info)) {
                if (!log_root_tree->node) {
                        ret = btrfs_alloc_log_tree_node(trans, log_root_tree);
@@ -3183,6 +3179,10 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
                }
        }
 
+       index2 = log_root_tree->log_transid % 2;
+       list_add_tail(&root_log_ctx.list, &log_root_tree->log_ctxs[index2]);
+       root_log_ctx.log_transid = log_root_tree->log_transid;
+
        /*
         * Now we are safe to update the log_root_tree because we're under the
         * log_mutex, and we're a current writer so we're holding the commit
index 3aedc48..88a7958 100644 (file)
@@ -207,7 +207,7 @@ static int cifs_debug_files_proc_show(struct seq_file *m, void *v)
                                                from_kuid(&init_user_ns, cfile->uid),
                                                cfile->dentry);
 #ifdef CONFIG_CIFS_DEBUG2
-                                       seq_printf(m, " 0x%llx\n", cfile->fid.mid);
+                                       seq_printf(m, " %llu\n", cfile->fid.mid);
 #else
                                        seq_printf(m, "\n");
 #endif /* CIFS_DEBUG2 */
index f2d730f..d829b8b 100644 (file)
@@ -248,7 +248,7 @@ nlmsg_fail:
 
 /*
  * Try to find a matching registration for the tcon's server name and share name.
- * Calls to this funciton must be protected by cifs_swnreg_idr_mutex.
+ * Calls to this function must be protected by cifs_swnreg_idr_mutex.
  * TODO Try to avoid memory allocations
  */
 static struct cifs_swn_reg *cifs_find_swn_reg(struct cifs_tcon *tcon)
index 9d29eb9..2be22a5 100644 (file)
@@ -1118,7 +1118,6 @@ static int set_chmod_dacl(struct cifs_acl *pdacl, struct cifs_acl *pndacl,
        /* Retain old ACEs which we can retain */
        for (i = 0; i < src_num_aces; ++i) {
                pntace = (struct cifs_ace *) (acl_base + size);
-               pnntace = (struct cifs_ace *) (nacl_base + nsize);
 
                if (!new_aces_set && (pntace->flags & INHERITED_ACE)) {
                        /* Place the new ACEs in between existing explicit and inherited */
@@ -1131,14 +1130,18 @@ static int set_chmod_dacl(struct cifs_acl *pdacl, struct cifs_acl *pndacl,
                }
 
                /* If it's any one of the ACE we're replacing, skip! */
-               if ((compare_sids(&pntace->sid, &sid_unix_NFS_mode) == 0) ||
+               if (!mode_from_sid &&
+                               ((compare_sids(&pntace->sid, &sid_unix_NFS_mode) == 0) ||
                                (compare_sids(&pntace->sid, pownersid) == 0) ||
                                (compare_sids(&pntace->sid, pgrpsid) == 0) ||
                                (compare_sids(&pntace->sid, &sid_everyone) == 0) ||
-                               (compare_sids(&pntace->sid, &sid_authusers) == 0)) {
+                               (compare_sids(&pntace->sid, &sid_authusers) == 0))) {
                        goto next_ace;
                }
 
+               /* update the pointer to the next ACE to populate*/
+               pnntace = (struct cifs_ace *) (nacl_base + nsize);
+
                nsize += cifs_copy_ace(pnntace, pntace, NULL);
                num_aces++;
 
index d43e935..099ad9f 100644 (file)
@@ -290,7 +290,7 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
                rc = server->ops->queryfs(xid, tcon, cifs_sb, buf);
 
        free_xid(xid);
-       return 0;
+       return rc;
 }
 
 static long cifs_fallocate(struct file *file, int mode, loff_t off, loff_t len)
index 3de3c59..31fc869 100644 (file)
@@ -257,7 +257,7 @@ struct smb_version_operations {
        /* verify the message */
        int (*check_message)(char *, unsigned int, struct TCP_Server_Info *);
        bool (*is_oplock_break)(char *, struct TCP_Server_Info *);
-       int (*handle_cancelled_mid)(char *, struct TCP_Server_Info *);
+       int (*handle_cancelled_mid)(struct mid_q_entry *, struct TCP_Server_Info *);
        void (*downgrade_oplock)(struct TCP_Server_Info *server,
                                 struct cifsInodeInfo *cinode, __u32 oplock,
                                 unsigned int epoch, bool *purge_cache);
@@ -1705,16 +1705,17 @@ static inline bool is_retryable_error(int error)
 #define   CIFS_NO_RSP_BUF   0x040    /* no response buffer required */
 
 /* Type of request operation */
-#define   CIFS_ECHO_OP      0x080    /* echo request */
-#define   CIFS_OBREAK_OP   0x0100    /* oplock break request */
-#define   CIFS_NEG_OP      0x0200    /* negotiate request */
+#define   CIFS_ECHO_OP            0x080  /* echo request */
+#define   CIFS_OBREAK_OP          0x0100 /* oplock break request */
+#define   CIFS_NEG_OP             0x0200 /* negotiate request */
+#define   CIFS_CP_CREATE_CLOSE_OP 0x0400 /* compound create+close request */
 /* Lower bitmask values are reserved by others below. */
-#define   CIFS_SESS_OP     0x2000    /* session setup request */
-#define   CIFS_OP_MASK     0x2380    /* mask request type */
+#define   CIFS_SESS_OP            0x2000 /* session setup request */
+#define   CIFS_OP_MASK            0x2780 /* mask request type */
 
-#define   CIFS_HAS_CREDITS 0x0400    /* already has credits */
-#define   CIFS_TRANSFORM_REQ 0x0800    /* transform request before sending */
-#define   CIFS_NO_SRV_RSP    0x1000    /* there is no server response */
+#define   CIFS_HAS_CREDITS        0x0400 /* already has credits */
+#define   CIFS_TRANSFORM_REQ      0x0800 /* transform request before sending */
+#define   CIFS_NO_SRV_RSP         0x1000 /* there is no server response */
 
 /* Security Flags: indicate type of session setup needed */
 #define   CIFSSEC_MAY_SIGN     0x00001
index 1126923..eec8a20 100644 (file)
@@ -741,7 +741,7 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server)
                spin_lock(&GlobalMid_Lock);
                list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
                        mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
-                       cifs_dbg(FYI, "Clearing mid 0x%llx\n", mid_entry->mid);
+                       cifs_dbg(FYI, "Clearing mid %llu\n", mid_entry->mid);
                        kref_get(&mid_entry->refcount);
                        mid_entry->mid_state = MID_SHUTDOWN;
                        list_move(&mid_entry->qhead, &dispose_list);
@@ -752,7 +752,7 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server)
                /* now walk dispose list and issue callbacks */
                list_for_each_safe(tmp, tmp2, &dispose_list) {
                        mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
-                       cifs_dbg(FYI, "Callback mid 0x%llx\n", mid_entry->mid);
+                       cifs_dbg(FYI, "Callback mid %llu\n", mid_entry->mid);
                        list_del_init(&mid_entry->qhead);
                        mid_entry->callback(mid_entry);
                        cifs_mid_q_entry_release(mid_entry);
@@ -1429,6 +1429,11 @@ smbd_connected:
        tcp_ses->min_offload = ctx->min_offload;
        tcp_ses->tcpStatus = CifsNeedNegotiate;
 
+       if ((ctx->max_credits < 20) || (ctx->max_credits > 60000))
+               tcp_ses->max_credits = SMB2_MAX_CREDITS_AVAILABLE;
+       else
+               tcp_ses->max_credits = ctx->max_credits;
+
        tcp_ses->nr_targets = 1;
        tcp_ses->ignore_signature = ctx->ignore_signature;
        /* thread spawned, put it on the list */
@@ -2832,11 +2837,6 @@ static int mount_get_conns(struct smb3_fs_context *ctx, struct cifs_sb_info *cif
 
        *nserver = server;
 
-       if ((ctx->max_credits < 20) || (ctx->max_credits > 60000))
-               server->max_credits = SMB2_MAX_CREDITS_AVAILABLE;
-       else
-               server->max_credits = ctx->max_credits;
-
        /* get a reference to a SMB session */
        ses = cifs_get_smb_ses(server, ctx);
        if (IS_ERR(ses)) {
index 892f51a..7888902 100644 (file)
@@ -1196,9 +1196,11 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
                pr_warn_once("Witness protocol support is experimental\n");
                break;
        case Opt_rootfs:
-#ifdef CONFIG_CIFS_ROOT
-               ctx->rootfs = true;
+#ifndef CONFIG_CIFS_ROOT
+               cifs_dbg(VFS, "rootfs support requires CONFIG_CIFS_ROOT config option\n");
+               goto cifs_parse_mount_err;
 #endif
+               ctx->rootfs = true;
                break;
        case Opt_posixpaths:
                if (result.negated)
index 7c61bc9..f2df442 100644 (file)
@@ -2395,7 +2395,7 @@ int cifs_getattr(struct user_namespace *mnt_userns, const struct path *path,
         * We need to be sure that all dirty pages are written and the server
         * has actual ctime, mtime and file length.
         */
-       if ((request_mask & (STATX_CTIME | STATX_MTIME | STATX_SIZE)) &&
+       if ((request_mask & (STATX_CTIME | STATX_MTIME | STATX_SIZE | STATX_BLOCKS)) &&
            !CIFS_CACHE_READ(CIFS_I(inode)) &&
            inode->i_mapping && inode->i_mapping->nrpages != 0) {
                rc = filemap_fdatawait(inode->i_mapping);
@@ -2585,6 +2585,14 @@ set_size_out:
        if (rc == 0) {
                cifsInode->server_eof = attrs->ia_size;
                cifs_setsize(inode, attrs->ia_size);
+               /*
+                * i_blocks is not related to (i_size / i_blksize), but instead
+                * 512 byte (2**9) size is required for calculating num blocks.
+                * Until we can query the server for actual allocation size,
+                * this is best estimate we have for blocks allocated for a file
+                * Number of blocks must be rounded up so size 1 is not 0 blocks
+                */
+               inode->i_blocks = (512 - 1 + attrs->ia_size) >> 9;
 
                /*
                 * The man page of truncate says if the size changed,
index 183a3a8..63d517b 100644 (file)
@@ -230,6 +230,7 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
        ctx.noautotune = ses->server->noautotune;
        ctx.sockopt_tcp_nodelay = ses->server->tcp_nodelay;
        ctx.echo_interval = ses->server->echo_interval / HZ;
+       ctx.max_credits = ses->server->max_credits;
 
        /*
         * This will be used for encoding/decoding user/domain/pw
index 1f900b8..a718dc7 100644 (file)
@@ -358,6 +358,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
        if (cfile)
                goto after_close;
        /* Close */
+       flags |= CIFS_CP_CREATE_CLOSE_OP;
        rqst[num_rqst].rq_iov = &vars->close_iov[0];
        rqst[num_rqst].rq_nvec = 1;
        rc = SMB2_close_init(tcon, server,
index 60d4bd1..b50164e 100644 (file)
@@ -767,7 +767,7 @@ smb2_cancelled_close_fid(struct work_struct *work)
        int rc;
 
        if (cancelled->mid)
-               cifs_tcon_dbg(VFS, "Close unmatched open for MID:%llx\n",
+               cifs_tcon_dbg(VFS, "Close unmatched open for MID:%llu\n",
                              cancelled->mid);
        else
                cifs_tcon_dbg(VFS, "Close interrupted close\n");
@@ -844,14 +844,14 @@ smb2_handle_cancelled_close(struct cifs_tcon *tcon, __u64 persistent_fid,
 }
 
 int
-smb2_handle_cancelled_mid(char *buffer, struct TCP_Server_Info *server)
+smb2_handle_cancelled_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server)
 {
-       struct smb2_sync_hdr *sync_hdr = (struct smb2_sync_hdr *)buffer;
-       struct smb2_create_rsp *rsp = (struct smb2_create_rsp *)buffer;
+       struct smb2_sync_hdr *sync_hdr = mid->resp_buf;
+       struct smb2_create_rsp *rsp = mid->resp_buf;
        struct cifs_tcon *tcon;
        int rc;
 
-       if (sync_hdr->Command != SMB2_CREATE ||
+       if ((mid->optype & CIFS_CP_CREATE_CLOSE_OP) || sync_hdr->Command != SMB2_CREATE ||
            sync_hdr->Status != STATUS_SUCCESS)
                return 0;
 
index f508729..9bae7e8 100644 (file)
@@ -1195,7 +1195,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
        struct TCP_Server_Info *server = cifs_pick_channel(ses);
        __le16 *utf16_path = NULL;
        int ea_name_len = strlen(ea_name);
-       int flags = 0;
+       int flags = CIFS_CP_CREATE_CLOSE_OP;
        int len;
        struct smb_rqst rqst[3];
        int resp_buftype[3];
@@ -1573,7 +1573,7 @@ smb2_ioctl_query_info(const unsigned int xid,
        struct smb_query_info qi;
        struct smb_query_info __user *pqi;
        int rc = 0;
-       int flags = 0;
+       int flags = CIFS_CP_CREATE_CLOSE_OP;
        struct smb2_query_info_rsp *qi_rsp = NULL;
        struct smb2_ioctl_rsp *io_rsp = NULL;
        void *buffer = NULL;
@@ -2577,7 +2577,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
 {
        struct cifs_ses *ses = tcon->ses;
        struct TCP_Server_Info *server = cifs_pick_channel(ses);
-       int flags = 0;
+       int flags = CIFS_CP_CREATE_CLOSE_OP;
        struct smb_rqst rqst[3];
        int resp_buftype[3];
        struct kvec rsp_iov[3];
@@ -2975,7 +2975,7 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
        unsigned int sub_offset;
        unsigned int print_len;
        unsigned int print_offset;
-       int flags = 0;
+       int flags = CIFS_CP_CREATE_CLOSE_OP;
        struct smb_rqst rqst[3];
        int resp_buftype[3];
        struct kvec rsp_iov[3];
@@ -3157,7 +3157,7 @@ smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
        struct cifs_open_parms oparms;
        struct cifs_fid fid;
        struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses);
-       int flags = 0;
+       int flags = CIFS_CP_CREATE_CLOSE_OP;
        struct smb_rqst rqst[3];
        int resp_buftype[3];
        struct kvec rsp_iov[3];
index 4bbb612..2199a9b 100644 (file)
@@ -4041,8 +4041,7 @@ smb2_async_readv(struct cifs_readdata *rdata)
        if (rdata->credits.value > 0) {
                shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->bytes,
                                                SMB2_MAX_BUFFER_SIZE));
-               shdr->CreditRequest =
-                       cpu_to_le16(le16_to_cpu(shdr->CreditCharge) + 1);
+               shdr->CreditRequest = cpu_to_le16(le16_to_cpu(shdr->CreditCharge) + 8);
 
                rc = adjust_credits(server, &rdata->credits, rdata->bytes);
                if (rc)
@@ -4348,8 +4347,7 @@ smb2_async_writev(struct cifs_writedata *wdata,
        if (wdata->credits.value > 0) {
                shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(wdata->bytes,
                                                    SMB2_MAX_BUFFER_SIZE));
-               shdr->CreditRequest =
-                       cpu_to_le16(le16_to_cpu(shdr->CreditCharge) + 1);
+               shdr->CreditRequest = cpu_to_le16(le16_to_cpu(shdr->CreditCharge) + 8);
 
                rc = adjust_credits(server, &wdata->credits, wdata->bytes);
                if (rc)
index 9565e27..a2eb34a 100644 (file)
@@ -246,8 +246,7 @@ extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
 extern int smb2_handle_cancelled_close(struct cifs_tcon *tcon,
                                       __u64 persistent_fid,
                                       __u64 volatile_fid);
-extern int smb2_handle_cancelled_mid(char *buffer,
-                                       struct TCP_Server_Info *server);
+extern int smb2_handle_cancelled_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server);
 void smb2_cancelled_close_fid(struct work_struct *work);
 extern int SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
                         u64 persistent_file_id, u64 volatile_file_id,
index e90a1d1..c1725b5 100644 (file)
@@ -101,7 +101,7 @@ static void _cifs_mid_q_entry_release(struct kref *refcount)
        if (midEntry->resp_buf && (midEntry->mid_flags & MID_WAIT_CANCELLED) &&
            midEntry->mid_state == MID_RESPONSE_RECEIVED &&
            server->ops->handle_cancelled_mid)
-               server->ops->handle_cancelled_mid(midEntry->resp_buf, server);
+               server->ops->handle_cancelled_mid(midEntry, server);
 
        midEntry->mid_state = MID_FREE;
        atomic_dec(&midCount);
@@ -1196,9 +1196,12 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
        /*
         * Compounding is never used during session establish.
         */
-       if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP) || (optype & CIFS_SESS_OP))
+       if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP) || (optype & CIFS_SESS_OP)) {
+               mutex_lock(&server->srv_mutex);
                smb311_update_preauth_hash(ses, rqst[0].rq_iov,
                                           rqst[0].rq_nvec);
+               mutex_unlock(&server->srv_mutex);
+       }
 
        for (i = 0; i < num_rqst; i++) {
                rc = wait_for_response(server, midQ[i]);
@@ -1207,7 +1210,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
        }
        if (rc != 0) {
                for (; i < num_rqst; i++) {
-                       cifs_server_dbg(VFS, "Cancelling wait for mid %llu cmd: %d\n",
+                       cifs_server_dbg(FYI, "Cancelling wait for mid %llu cmd: %d\n",
                                 midQ[i]->mid, le16_to_cpu(midQ[i]->command));
                        send_cancel(server, &rqst[i], midQ[i]);
                        spin_lock(&GlobalMid_Lock);
@@ -1266,7 +1269,9 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
                        .iov_base = resp_iov[0].iov_base,
                        .iov_len = resp_iov[0].iov_len
                };
+               mutex_lock(&server->srv_mutex);
                smb311_update_preauth_hash(ses, &iov, 1);
+               mutex_unlock(&server->srv_mutex);
        }
 
 out:
index 1f02702..da8351d 100644 (file)
@@ -378,7 +378,7 @@ static int __configfs_open_file(struct inode *inode, struct file *file, int type
 
        attr = to_attr(dentry);
        if (!attr)
-               goto out_put_item;
+               goto out_free_buffer;
 
        if (type & CONFIGFS_ITEM_BIN_ATTR) {
                buffer->bin_attr = to_bin_attr(dentry);
@@ -391,7 +391,7 @@ static int __configfs_open_file(struct inode *inode, struct file *file, int type
        /* Grab the module reference for this attribute if we have one */
        error = -ENODEV;
        if (!try_module_get(buffer->owner))
-               goto out_put_item;
+               goto out_free_buffer;
 
        error = -EACCES;
        if (!buffer->item->ci_type)
@@ -435,8 +435,6 @@ static int __configfs_open_file(struct inode *inode, struct file *file, int type
 
 out_put_module:
        module_put(buffer->owner);
-out_put_item:
-       config_item_put(buffer->item);
 out_free_buffer:
        up_read(&frag->frag_sem);
        kfree(buffer);
index b048a0e..68a2de6 100644 (file)
@@ -52,7 +52,7 @@ static int fscrypt_zeroout_range_inline_crypt(const struct inode *inode,
        int num_pages = 0;
 
        /* This always succeeds since __GFP_DIRECT_RECLAIM is set. */
-       bio = bio_alloc(GFP_NOFS, BIO_MAX_PAGES);
+       bio = bio_alloc(GFP_NOFS, BIO_MAX_VECS);
 
        while (len) {
                unsigned int blocks_this_page = min(len, blocks_per_page);
@@ -74,7 +74,7 @@ static int fscrypt_zeroout_range_inline_crypt(const struct inode *inode,
                len -= blocks_this_page;
                lblk += blocks_this_page;
                pblk += blocks_this_page;
-               if (num_pages == BIO_MAX_PAGES || !len ||
+               if (num_pages == BIO_MAX_VECS || !len ||
                    !fscrypt_mergeable_bio(bio, inode, lblk)) {
                        err = submit_bio_wait(bio);
                        if (err)
@@ -126,7 +126,7 @@ int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk,
                return fscrypt_zeroout_range_inline_crypt(inode, lblk, pblk,
                                                          len);
 
-       BUILD_BUG_ON(ARRAY_SIZE(pages) > BIO_MAX_PAGES);
+       BUILD_BUG_ON(ARRAY_SIZE(pages) > BIO_MAX_VECS);
        nr_pages = min_t(unsigned int, ARRAY_SIZE(pages),
                         (len + blocks_per_page - 1) >> blocks_per_page_bits);
 
index f88851c..1249e74 100644 (file)
@@ -129,6 +129,7 @@ static inline struct bio *erofs_read_raw_page(struct bio *bio,
                                              struct page *page,
                                              erofs_off_t *last_block,
                                              unsigned int nblocks,
+                                             unsigned int *eblks,
                                              bool ra)
 {
        struct inode *const inode = mapping->host;
@@ -145,8 +146,7 @@ static inline struct bio *erofs_read_raw_page(struct bio *bio,
 
        /* note that for readpage case, bio also equals to NULL */
        if (bio &&
-           /* not continuous */
-           *last_block + 1 != current_block) {
+           (*last_block + 1 != current_block || !*eblks)) {
 submit_bio_retry:
                submit_bio(bio);
                bio = NULL;
@@ -216,7 +216,8 @@ submit_bio_retry:
                if (nblocks > DIV_ROUND_UP(map.m_plen, PAGE_SIZE))
                        nblocks = DIV_ROUND_UP(map.m_plen, PAGE_SIZE);
 
-               bio = bio_alloc(GFP_NOIO, bio_max_segs(nblocks));
+               *eblks = bio_max_segs(nblocks);
+               bio = bio_alloc(GFP_NOIO, *eblks);
 
                bio->bi_end_io = erofs_readendio;
                bio_set_dev(bio, sb->s_bdev);
@@ -229,16 +230,8 @@ submit_bio_retry:
        /* out of the extent or bio is full */
        if (err < PAGE_SIZE)
                goto submit_bio_retry;
-
+       --*eblks;
        *last_block = current_block;
-
-       /* shift in advance in case of it followed by too many gaps */
-       if (bio->bi_iter.bi_size >= bio->bi_max_vecs * PAGE_SIZE) {
-               /* err should reassign to 0 after submitting */
-               err = 0;
-               goto submit_bio_out;
-       }
-
        return bio;
 
 err_out:
@@ -252,7 +245,6 @@ has_updated:
 
        /* if updated manually, continuous pages has a gap */
        if (bio)
-submit_bio_out:
                submit_bio(bio);
        return err ? ERR_PTR(err) : NULL;
 }
@@ -264,23 +256,26 @@ submit_bio_out:
 static int erofs_raw_access_readpage(struct file *file, struct page *page)
 {
        erofs_off_t last_block;
+       unsigned int eblks;
        struct bio *bio;
 
        trace_erofs_readpage(page, true);
 
        bio = erofs_read_raw_page(NULL, page->mapping,
-                                 page, &last_block, 1, false);
+                                 page, &last_block, 1, &eblks, false);
 
        if (IS_ERR(bio))
                return PTR_ERR(bio);
 
-       DBG_BUGON(bio); /* since we have only one bio -- must be NULL */
+       if (bio)
+               submit_bio(bio);
        return 0;
 }
 
 static void erofs_raw_access_readahead(struct readahead_control *rac)
 {
        erofs_off_t last_block;
+       unsigned int eblks;
        struct bio *bio = NULL;
        struct page *page;
 
@@ -291,7 +286,7 @@ static void erofs_raw_access_readahead(struct readahead_control *rac)
                prefetchw(&page->flags);
 
                bio = erofs_read_raw_page(bio, rac->mapping, page, &last_block,
-                               readahead_count(rac), true);
+                               readahead_count(rac), &eblks, true);
 
                /* all the page errors are ignored when readahead */
                if (IS_ERR(bio)) {
@@ -305,7 +300,6 @@ static void erofs_raw_access_readahead(struct readahead_control *rac)
                put_page(page);
        }
 
-       /* the rare case (end in gaps) */
        if (bio)
                submit_bio(bio);
 }
index 6cb356c..3851e1a 100644 (file)
@@ -1235,7 +1235,7 @@ submit_bio_retry:
                        }
 
                        if (!bio) {
-                               bio = bio_alloc(GFP_NOIO, BIO_MAX_PAGES);
+                               bio = bio_alloc(GFP_NOIO, BIO_MAX_VECS);
 
                                bio->bi_end_io = z_erofs_decompressqueue_endio;
                                bio_set_dev(bio, sb->s_bdev);
index f45f9fe..74a5172 100644 (file)
@@ -626,27 +626,41 @@ int ext4_claim_free_clusters(struct ext4_sb_info *sbi,
 
 /**
  * ext4_should_retry_alloc() - check if a block allocation should be retried
- * @sb:                        super block
- * @retries:           number of attemps has been made
+ * @sb:                        superblock
+ * @retries:           number of retry attempts made so far
  *
- * ext4_should_retry_alloc() is called when ENOSPC is returned, and if
- * it is profitable to retry the operation, this function will wait
- * for the current or committing transaction to complete, and then
- * return TRUE.  We will only retry once.
+ * ext4_should_retry_alloc() is called when ENOSPC is returned while
+ * attempting to allocate blocks.  If there's an indication that a pending
+ * journal transaction might free some space and allow another attempt to
+ * succeed, this function will wait for the current or committing transaction
+ * to complete and then return TRUE.
  */
 int ext4_should_retry_alloc(struct super_block *sb, int *retries)
 {
-       if (!ext4_has_free_clusters(EXT4_SB(sb), 1, 0) ||
-           (*retries)++ > 1 ||
-           !EXT4_SB(sb)->s_journal)
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+
+       if (!sbi->s_journal)
                return 0;
 
-       smp_mb();
-       if (EXT4_SB(sb)->s_mb_free_pending == 0)
+       if (++(*retries) > 3) {
+               percpu_counter_inc(&sbi->s_sra_exceeded_retry_limit);
                return 0;
+       }
 
+       /*
+        * if there's no indication that blocks are about to be freed it's
+        * possible we just missed a transaction commit that did so
+        */
+       smp_mb();
+       if (sbi->s_mb_free_pending == 0)
+               return ext4_has_free_clusters(sbi, 1, 0);
+
+       /*
+        * it's possible we've just missed a transaction commit here,
+        * so ignore the returned status
+        */
        jbd_debug(1, "%s: retrying operation after ENOSPC\n", sb->s_id);
-       jbd2_journal_force_commit_nested(EXT4_SB(sb)->s_journal);
+       (void) jbd2_journal_force_commit_nested(sbi->s_journal);
        return 1;
 }
 
index 644fd69..826a56e 100644 (file)
@@ -1484,6 +1484,7 @@ struct ext4_sb_info {
        struct percpu_counter s_freeinodes_counter;
        struct percpu_counter s_dirs_counter;
        struct percpu_counter s_dirtyclusters_counter;
+       struct percpu_counter s_sra_exceeded_retry_limit;
        struct blockgroup_lock *s_blockgroup_lock;
        struct proc_dir_entry *s_proc;
        struct kobject s_kobj;
@@ -2793,6 +2794,8 @@ void __ext4_fc_track_link(handle_t *handle, struct inode *inode,
        struct dentry *dentry);
 void ext4_fc_track_unlink(handle_t *handle, struct dentry *dentry);
 void ext4_fc_track_link(handle_t *handle, struct dentry *dentry);
+void __ext4_fc_track_create(handle_t *handle, struct inode *inode,
+                           struct dentry *dentry);
 void ext4_fc_track_create(handle_t *handle, struct dentry *dentry);
 void ext4_fc_track_inode(handle_t *handle, struct inode *inode);
 void ext4_fc_mark_ineligible(struct super_block *sb, int reason);
index 77c7c8a..77c84d6 100644 (file)
@@ -4382,7 +4382,7 @@ static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset,
 {
        struct inode *inode = file_inode(file);
        handle_t *handle;
-       int ret, ret2 = 0, ret3 = 0;
+       int ret = 0, ret2 = 0, ret3 = 0;
        int retries = 0;
        int depth = 0;
        struct ext4_map_blocks map;
index 6c4f19b..7541d0b 100644 (file)
@@ -513,10 +513,10 @@ void ext4_fc_track_link(handle_t *handle, struct dentry *dentry)
        __ext4_fc_track_link(handle, d_inode(dentry), dentry);
 }
 
-void ext4_fc_track_create(handle_t *handle, struct dentry *dentry)
+void __ext4_fc_track_create(handle_t *handle, struct inode *inode,
+                         struct dentry *dentry)
 {
        struct __track_dentry_update_args args;
-       struct inode *inode = d_inode(dentry);
        int ret;
 
        args.dentry = dentry;
@@ -527,6 +527,11 @@ void ext4_fc_track_create(handle_t *handle, struct dentry *dentry)
        trace_ext4_fc_track_create(inode, dentry, ret);
 }
 
+void ext4_fc_track_create(handle_t *handle, struct dentry *dentry)
+{
+       __ext4_fc_track_create(handle, d_inode(dentry), dentry);
+}
+
 /* __track_fn for inode tracking */
 static int __track_inode(struct inode *inode, void *arg, bool update)
 {
index 650c5ac..0948a43 100644 (file)
@@ -1938,13 +1938,13 @@ static int __ext4_journalled_writepage(struct page *page,
        if (!ret)
                ret = err;
 
-       if (!ext4_has_inline_data(inode))
-               ext4_walk_page_buffers(NULL, page_bufs, 0, len,
-                                      NULL, bput_one);
        ext4_set_inode_state(inode, EXT4_STATE_JDATA);
 out:
        unlock_page(page);
 out_no_pagelock:
+       if (!inline_data && page_bufs)
+               ext4_walk_page_buffers(NULL, page_bufs, 0, len,
+                                      NULL, bput_one);
        brelse(inode_bh);
        return ret;
 }
@@ -5026,7 +5026,7 @@ static int ext4_do_update_inode(handle_t *handle,
        struct ext4_inode_info *ei = EXT4_I(inode);
        struct buffer_head *bh = iloc->bh;
        struct super_block *sb = inode->i_sb;
-       int err = 0, rc, block;
+       int err = 0, block;
        int need_datasync = 0, set_large_file = 0;
        uid_t i_uid;
        gid_t i_gid;
@@ -5138,9 +5138,9 @@ static int ext4_do_update_inode(handle_t *handle,
                                              bh->b_data);
 
        BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
-       rc = ext4_handle_dirty_metadata(handle, NULL, bh);
-       if (!err)
-               err = rc;
+       err = ext4_handle_dirty_metadata(handle, NULL, bh);
+       if (err)
+               goto out_brelse;
        ext4_clear_inode_state(inode, EXT4_STATE_NEW);
        if (set_large_file) {
                BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "get write access");
@@ -5387,8 +5387,10 @@ int ext4_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
                        inode->i_gid = attr->ia_gid;
                error = ext4_mark_inode_dirty(handle, inode);
                ext4_journal_stop(handle);
-               if (unlikely(error))
+               if (unlikely(error)) {
+                       ext4_fc_stop_update(inode);
                        return error;
+               }
        }
 
        if (attr->ia_valid & ATTR_SIZE) {
index 99bf091..a02fadf 100644 (file)
@@ -2709,8 +2709,15 @@ static int ext4_mb_init_backend(struct super_block *sb)
        }
 
        if (ext4_has_feature_flex_bg(sb)) {
-               /* a single flex group is supposed to be read by a single IO */
-               sbi->s_mb_prefetch = min(1 << sbi->s_es->s_log_groups_per_flex,
+               /* a single flex group is supposed to be read by a single IO.
+                * 2 ^ s_log_groups_per_flex != UINT_MAX as s_mb_prefetch is
+                * unsigned integer, so the maximum shift is 32.
+                */
+               if (sbi->s_es->s_log_groups_per_flex >= 32) {
+                       ext4_msg(sb, KERN_ERR, "too many log groups per flexible block group");
+                       goto err_freesgi;
+               }
+               sbi->s_mb_prefetch = min_t(uint, 1 << sbi->s_es->s_log_groups_per_flex,
                        BLK_MAX_SEGMENT_SIZE >> (sb->s_blocksize_bits - 9));
                sbi->s_mb_prefetch *= 8; /* 8 prefetch IOs in flight at most */
        } else {
index 686bf98..883e2a7 100644 (file)
@@ -3613,6 +3613,31 @@ static int ext4_setent(handle_t *handle, struct ext4_renament *ent,
        return retval;
 }
 
+static void ext4_resetent(handle_t *handle, struct ext4_renament *ent,
+                         unsigned ino, unsigned file_type)
+{
+       struct ext4_renament old = *ent;
+       int retval = 0;
+
+       /*
+        * old->de could have moved from under us during make indexed dir,
+        * so the old->de may no longer valid and need to find it again
+        * before reset old inode info.
+        */
+       old.bh = ext4_find_entry(old.dir, &old.dentry->d_name, &old.de, NULL);
+       if (IS_ERR(old.bh))
+               retval = PTR_ERR(old.bh);
+       if (!old.bh)
+               retval = -ENOENT;
+       if (retval) {
+               ext4_std_error(old.dir->i_sb, retval);
+               return;
+       }
+
+       ext4_setent(handle, &old, ino, file_type);
+       brelse(old.bh);
+}
+
 static int ext4_find_delete_entry(handle_t *handle, struct inode *dir,
                                  const struct qstr *d_name)
 {
@@ -3774,14 +3799,14 @@ static int ext4_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
         */
        retval = -ENOENT;
        if (!old.bh || le32_to_cpu(old.de->inode) != old.inode->i_ino)
-               goto end_rename;
+               goto release_bh;
 
        new.bh = ext4_find_entry(new.dir, &new.dentry->d_name,
                                 &new.de, &new.inlined);
        if (IS_ERR(new.bh)) {
                retval = PTR_ERR(new.bh);
                new.bh = NULL;
-               goto end_rename;
+               goto release_bh;
        }
        if (new.bh) {
                if (!new.inode) {
@@ -3798,15 +3823,13 @@ static int ext4_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
                handle = ext4_journal_start(old.dir, EXT4_HT_DIR, credits);
                if (IS_ERR(handle)) {
                        retval = PTR_ERR(handle);
-                       handle = NULL;
-                       goto end_rename;
+                       goto release_bh;
                }
        } else {
                whiteout = ext4_whiteout_for_rename(mnt_userns, &old, credits, &handle);
                if (IS_ERR(whiteout)) {
                        retval = PTR_ERR(whiteout);
-                       whiteout = NULL;
-                       goto end_rename;
+                       goto release_bh;
                }
        }
 
@@ -3850,6 +3873,7 @@ static int ext4_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
                retval = ext4_mark_inode_dirty(handle, whiteout);
                if (unlikely(retval))
                        goto end_rename;
+
        }
        if (!new.bh) {
                retval = ext4_add_entry(handle, new.dentry, old.inode);
@@ -3923,6 +3947,8 @@ static int ext4_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
                        ext4_fc_track_unlink(handle, new.dentry);
                __ext4_fc_track_link(handle, old.inode, new.dentry);
                __ext4_fc_track_unlink(handle, old.inode, old.dentry);
+               if (whiteout)
+                       __ext4_fc_track_create(handle, whiteout, old.dentry);
        }
 
        if (new.inode) {
@@ -3937,19 +3963,21 @@ static int ext4_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
 end_rename:
        if (whiteout) {
                if (retval) {
-                       ext4_setent(handle, &old,
-                               old.inode->i_ino, old_file_type);
+                       ext4_resetent(handle, &old,
+                                     old.inode->i_ino, old_file_type);
                        drop_nlink(whiteout);
+                       ext4_orphan_add(handle, whiteout);
                }
                unlock_new_inode(whiteout);
+               ext4_journal_stop(handle);
                iput(whiteout);
-
+       } else {
+               ext4_journal_stop(handle);
        }
+release_bh:
        brelse(old.dir_bh);
        brelse(old.bh);
        brelse(new.bh);
-       if (handle)
-               ext4_journal_stop(handle);
        return retval;
 }
 
index 03a44a0..f038d57 100644 (file)
@@ -398,7 +398,7 @@ static void io_submit_init_bio(struct ext4_io_submit *io,
         * bio_alloc will _always_ be able to allocate a bio if
         * __GFP_DIRECT_RECLAIM is set, see comments for bio_alloc_bioset().
         */
-       bio = bio_alloc(GFP_NOIO, BIO_MAX_PAGES);
+       bio = bio_alloc(GFP_NOIO, BIO_MAX_VECS);
        fscrypt_set_bio_crypt_ctx_bh(bio, bh, GFP_NOIO);
        bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9);
        bio_set_dev(bio, bh->b_bdev);
index ad34a37..b969368 100644 (file)
@@ -1210,6 +1210,7 @@ static void ext4_put_super(struct super_block *sb)
        percpu_counter_destroy(&sbi->s_freeinodes_counter);
        percpu_counter_destroy(&sbi->s_dirs_counter);
        percpu_counter_destroy(&sbi->s_dirtyclusters_counter);
+       percpu_counter_destroy(&sbi->s_sra_exceeded_retry_limit);
        percpu_free_rwsem(&sbi->s_writepages_rwsem);
 #ifdef CONFIG_QUOTA
        for (i = 0; i < EXT4_MAXQUOTAS; i++)
@@ -5011,6 +5012,9 @@ no_journal:
        if (!err)
                err = percpu_counter_init(&sbi->s_dirtyclusters_counter, 0,
                                          GFP_KERNEL);
+       if (!err)
+               err = percpu_counter_init(&sbi->s_sra_exceeded_retry_limit, 0,
+                                         GFP_KERNEL);
        if (!err)
                err = percpu_init_rwsem(&sbi->s_writepages_rwsem);
 
@@ -5124,6 +5128,7 @@ failed_mount6:
        percpu_counter_destroy(&sbi->s_freeinodes_counter);
        percpu_counter_destroy(&sbi->s_dirs_counter);
        percpu_counter_destroy(&sbi->s_dirtyclusters_counter);
+       percpu_counter_destroy(&sbi->s_sra_exceeded_retry_limit);
        percpu_free_rwsem(&sbi->s_writepages_rwsem);
 failed_mount5:
        ext4_ext_release(sb);
@@ -5149,8 +5154,8 @@ failed_mount_wq:
 failed_mount3a:
        ext4_es_unregister_shrinker(sbi);
 failed_mount3:
-       del_timer_sync(&sbi->s_err_report);
        flush_work(&sbi->s_error_work);
+       del_timer_sync(&sbi->s_err_report);
        if (sbi->s_mmp_tsk)
                kthread_stop(sbi->s_mmp_tsk);
 failed_mount2:
index 075aa3a..a3d0827 100644 (file)
@@ -24,6 +24,7 @@ typedef enum {
        attr_session_write_kbytes,
        attr_lifetime_write_kbytes,
        attr_reserved_clusters,
+       attr_sra_exceeded_retry_limit,
        attr_inode_readahead,
        attr_trigger_test_error,
        attr_first_error_time,
@@ -202,6 +203,7 @@ EXT4_ATTR_FUNC(delayed_allocation_blocks, 0444);
 EXT4_ATTR_FUNC(session_write_kbytes, 0444);
 EXT4_ATTR_FUNC(lifetime_write_kbytes, 0444);
 EXT4_ATTR_FUNC(reserved_clusters, 0644);
+EXT4_ATTR_FUNC(sra_exceeded_retry_limit, 0444);
 
 EXT4_ATTR_OFFSET(inode_readahead_blks, 0644, inode_readahead,
                 ext4_sb_info, s_inode_readahead_blks);
@@ -251,6 +253,7 @@ static struct attribute *ext4_attrs[] = {
        ATTR_LIST(session_write_kbytes),
        ATTR_LIST(lifetime_write_kbytes),
        ATTR_LIST(reserved_clusters),
+       ATTR_LIST(sra_exceeded_retry_limit),
        ATTR_LIST(inode_readahead_blks),
        ATTR_LIST(inode_goal),
        ATTR_LIST(mb_stats),
@@ -374,6 +377,10 @@ static ssize_t ext4_attr_show(struct kobject *kobj,
                return snprintf(buf, PAGE_SIZE, "%llu\n",
                                (unsigned long long)
                                atomic64_read(&sbi->s_resv_clusters));
+       case attr_sra_exceeded_retry_limit:
+               return snprintf(buf, PAGE_SIZE, "%llu\n",
+                               (unsigned long long)
+                       percpu_counter_sum(&sbi->s_sra_exceeded_retry_limit));
        case attr_inode_readahead:
        case attr_pointer_ui:
                if (!ptr)
index 5b7ba8f..00e3cbd 100644 (file)
@@ -201,55 +201,76 @@ static int ext4_end_enable_verity(struct file *filp, const void *desc,
        struct inode *inode = file_inode(filp);
        const int credits = 2; /* superblock and inode for ext4_orphan_del() */
        handle_t *handle;
+       struct ext4_iloc iloc;
        int err = 0;
-       int err2;
 
-       if (desc != NULL) {
-               /* Succeeded; write the verity descriptor. */
-               err = ext4_write_verity_descriptor(inode, desc, desc_size,
-                                                  merkle_tree_size);
-
-               /* Write all pages before clearing VERITY_IN_PROGRESS. */
-               if (!err)
-                       err = filemap_write_and_wait(inode->i_mapping);
-       }
+       /*
+        * If an error already occurred (which fs/verity/ signals by passing
+        * desc == NULL), then only clean-up is needed.
+        */
+       if (desc == NULL)
+               goto cleanup;
 
-       /* If we failed, truncate anything we wrote past i_size. */
-       if (desc == NULL || err)
-               ext4_truncate(inode);
+       /* Append the verity descriptor. */
+       err = ext4_write_verity_descriptor(inode, desc, desc_size,
+                                          merkle_tree_size);
+       if (err)
+               goto cleanup;
 
        /*
-        * We must always clean up by clearing EXT4_STATE_VERITY_IN_PROGRESS and
-        * deleting the inode from the orphan list, even if something failed.
-        * If everything succeeded, we'll also set the verity bit in the same
-        * transaction.
+        * Write all pages (both data and verity metadata).  Note that this must
+        * happen before clearing EXT4_STATE_VERITY_IN_PROGRESS; otherwise pages
+        * beyond i_size won't be written properly.  For crash consistency, this
+        * also must happen before the verity inode flag gets persisted.
         */
+       err = filemap_write_and_wait(inode->i_mapping);
+       if (err)
+               goto cleanup;
 
-       ext4_clear_inode_state(inode, EXT4_STATE_VERITY_IN_PROGRESS);
+       /*
+        * Finally, set the verity inode flag and remove the inode from the
+        * orphan list (in a single transaction).
+        */
 
        handle = ext4_journal_start(inode, EXT4_HT_INODE, credits);
        if (IS_ERR(handle)) {
-               ext4_orphan_del(NULL, inode);
-               return PTR_ERR(handle);
+               err = PTR_ERR(handle);
+               goto cleanup;
        }
 
-       err2 = ext4_orphan_del(handle, inode);
-       if (err2)
-               goto out_stop;
+       err = ext4_orphan_del(handle, inode);
+       if (err)
+               goto stop_and_cleanup;
 
-       if (desc != NULL && !err) {
-               struct ext4_iloc iloc;
+       err = ext4_reserve_inode_write(handle, inode, &iloc);
+       if (err)
+               goto stop_and_cleanup;
 
-               err = ext4_reserve_inode_write(handle, inode, &iloc);
-               if (err)
-                       goto out_stop;
-               ext4_set_inode_flag(inode, EXT4_INODE_VERITY);
-               ext4_set_inode_flags(inode, false);
-               err = ext4_mark_iloc_dirty(handle, inode, &iloc);
-       }
-out_stop:
+       ext4_set_inode_flag(inode, EXT4_INODE_VERITY);
+       ext4_set_inode_flags(inode, false);
+       err = ext4_mark_iloc_dirty(handle, inode, &iloc);
+       if (err)
+               goto stop_and_cleanup;
+
+       ext4_journal_stop(handle);
+
+       ext4_clear_inode_state(inode, EXT4_STATE_VERITY_IN_PROGRESS);
+       return 0;
+
+stop_and_cleanup:
        ext4_journal_stop(handle);
-       return err ?: err2;
+cleanup:
+       /*
+        * Verity failed to be enabled, so clean up by truncating any verity
+        * metadata that was written beyond i_size (both from cache and from
+        * disk), removing the inode from the orphan list (if it wasn't done
+        * already), and clearing EXT4_STATE_VERITY_IN_PROGRESS.
+        */
+       truncate_inode_pages(inode->i_mapping, inode->i_size);
+       ext4_truncate(inode);
+       ext4_orphan_del(NULL, inode);
+       ext4_clear_inode_state(inode, EXT4_STATE_VERITY_IN_PROGRESS);
+       return err;
 }
 
 static int ext4_get_verity_descriptor_location(struct inode *inode,
index 3722085..6c10182 100644 (file)
@@ -1462,6 +1462,9 @@ ext4_xattr_inode_cache_find(struct inode *inode, const void *value,
        if (!ce)
                return NULL;
 
+       WARN_ON_ONCE(ext4_handle_valid(journal_current_handle()) &&
+                    !(current->flags & PF_MEMALLOC_NOFS));
+
        ea_data = kvmalloc(value_len, GFP_KERNEL);
        if (!ea_data) {
                mb_cache_entry_put(ea_inode_cache, ce);
@@ -2327,6 +2330,7 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
                        error = -ENOSPC;
                        goto cleanup;
                }
+               WARN_ON_ONCE(!(current->flags & PF_MEMALLOC_NOFS));
        }
 
        error = ext4_reserve_inode_write(handle, inode, &is.iloc);
@@ -2400,7 +2404,7 @@ retry_inode:
                                 * external inode if possible.
                                 */
                                if (ext4_has_feature_ea_inode(inode->i_sb) &&
-                                   !i.in_inode) {
+                                   i.value_len && !i.in_inode) {
                                        i.in_inode = 1;
                                        goto retry_inode;
                                }
index 174a081..be5415a 100644 (file)
@@ -292,7 +292,7 @@ void f2fs_ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index)
        f2fs_put_page(page, 0);
 
        if (readahead)
-               f2fs_ra_meta_pages(sbi, index, BIO_MAX_PAGES, META_POR, true);
+               f2fs_ra_meta_pages(sbi, index, BIO_MAX_VECS, META_POR, true);
 }
 
 static int __f2fs_write_meta_page(struct page *page,
index 7c95818..4e5257c 100644 (file)
@@ -857,7 +857,7 @@ int f2fs_merge_page_bio(struct f2fs_io_info *fio)
                f2fs_submit_merged_ipu_write(fio->sbi, &bio, NULL);
 alloc_new:
        if (!bio) {
-               bio = __bio_alloc(fio, BIO_MAX_PAGES);
+               bio = __bio_alloc(fio, BIO_MAX_VECS);
                __attach_io_flag(fio);
                f2fs_set_bio_crypt_ctx(bio, fio->page->mapping->host,
                                       fio->page->index, fio, GFP_NOIO);
@@ -932,7 +932,7 @@ alloc_new:
                        fio->retry = true;
                        goto skip;
                }
-               io->bio = __bio_alloc(fio, BIO_MAX_PAGES);
+               io->bio = __bio_alloc(fio, BIO_MAX_VECS);
                f2fs_set_bio_crypt_ctx(io->bio, fio->page->mapping->host,
                                       bio_page->index, fio, GFP_NOIO);
                io->fio = *fio;
index 993004f..c286656 100644 (file)
@@ -4381,7 +4381,7 @@ static int build_sit_entries(struct f2fs_sb_info *sbi)
        block_t total_node_blocks = 0;
 
        do {
-               readed = f2fs_ra_meta_pages(sbi, start_blk, BIO_MAX_PAGES,
+               readed = f2fs_ra_meta_pages(sbi, start_blk, BIO_MAX_VECS,
                                                        META_SIT, true);
 
                start = start_blk * sit_i->sents_per_block;
index 229814b..e9a7a63 100644 (file)
@@ -851,7 +851,7 @@ static inline int nr_pages_to_skip(struct f2fs_sb_info *sbi, int type)
        else if (type == NODE)
                return 8 * sbi->blocks_per_seg;
        else if (type == META)
-               return 8 * BIO_MAX_PAGES;
+               return 8 * BIO_MAX_VECS;
        else
                return 0;
 }
@@ -868,7 +868,7 @@ static inline long nr_pages_to_write(struct f2fs_sb_info *sbi, int type,
                return 0;
 
        nr_to_write = wbc->nr_to_write;
-       desired = BIO_MAX_PAGES;
+       desired = BIO_MAX_VECS;
        if (type == NODE)
                desired <<= 1;
 
index 7069793..82592b1 100644 (file)
@@ -753,9 +753,9 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount)
                case Opt_io_size_bits:
                        if (args->from && match_int(args, &arg))
                                return -EINVAL;
-                       if (arg <= 0 || arg > __ilog2_u32(BIO_MAX_PAGES)) {
+                       if (arg <= 0 || arg > __ilog2_u32(BIO_MAX_VECS)) {
                                f2fs_warn(sbi, "Not support %d, larger than %d",
-                                         1 << arg, BIO_MAX_PAGES);
+                                         1 << arg, BIO_MAX_VECS);
                                return -EINVAL;
                        }
                        F2FS_OPTION(sbi).write_io_size_bits = arg;
index c6636b4..c0fee83 100644 (file)
@@ -2229,19 +2229,21 @@ static int fuse_device_clone(struct fuse_conn *fc, struct file *new)
 static long fuse_dev_ioctl(struct file *file, unsigned int cmd,
                           unsigned long arg)
 {
-       int err = -ENOTTY;
+       int res;
+       int oldfd;
+       struct fuse_dev *fud = NULL;
 
-       if (cmd == FUSE_DEV_IOC_CLONE) {
-               int oldfd;
+       if (_IOC_TYPE(cmd) != FUSE_DEV_IOC_MAGIC)
+               return -ENOTTY;
 
-               err = -EFAULT;
-               if (!get_user(oldfd, (__u32 __user *) arg)) {
+       switch (_IOC_NR(cmd)) {
+       case _IOC_NR(FUSE_DEV_IOC_CLONE):
+               res = -EFAULT;
+               if (!get_user(oldfd, (__u32 __user *)arg)) {
                        struct file *old = fget(oldfd);
 
-                       err = -EINVAL;
+                       res = -EINVAL;
                        if (old) {
-                               struct fuse_dev *fud = NULL;
-
                                /*
                                 * Check against file->f_op because CUSE
                                 * uses the same ioctl handler.
@@ -2252,14 +2254,18 @@ static long fuse_dev_ioctl(struct file *file, unsigned int cmd,
 
                                if (fud) {
                                        mutex_lock(&fuse_mutex);
-                                       err = fuse_device_clone(fud->fc, file);
+                                       res = fuse_device_clone(fud->fc, file);
                                        mutex_unlock(&fuse_mutex);
                                }
                                fput(old);
                        }
                }
+               break;
+       default:
+               res = -ENOTTY;
+               break;
        }
-       return err;
+       return res;
 }
 
 const struct file_operations fuse_dev_operations = {
index 68cca8d..63d97a1 100644 (file)
@@ -863,6 +863,7 @@ static inline u64 fuse_get_attr_version(struct fuse_conn *fc)
 
 static inline void fuse_make_bad(struct inode *inode)
 {
+       remove_inode_hash(inode);
        set_bit(FUSE_I_BAD, &get_fuse_inode(inode)->state);
 }
 
index 8868ac3..4ee6f73 100644 (file)
@@ -1324,8 +1324,15 @@ static int virtio_fs_fill_super(struct super_block *sb, struct fs_context *fsc)
 
        /* virtiofs allocates and installs its own fuse devices */
        ctx->fudptr = NULL;
-       if (ctx->dax)
+       if (ctx->dax) {
+               if (!fs->dax_dev) {
+                       err = -EINVAL;
+                       pr_err("virtio-fs: dax can't be enabled as filesystem"
+                              " device does not support it.\n");
+                       goto err_free_fuse_devs;
+               }
                ctx->dax_dev = fs->dax_dev;
+       }
        err = fuse_fill_super_common(sb, ctx);
        if (err < 0)
                goto err_free_fuse_devs;
index 16937eb..6410281 100644 (file)
@@ -998,12 +998,16 @@ static void trans_drain(struct gfs2_trans *tr)
        while (!list_empty(head)) {
                bd = list_first_entry(head, struct gfs2_bufdata, bd_list);
                list_del_init(&bd->bd_list);
+               if (!list_empty(&bd->bd_ail_st_list))
+                       gfs2_remove_from_ail(bd);
                kmem_cache_free(gfs2_bufdata_cachep, bd);
        }
        head = &tr->tr_databuf;
        while (!list_empty(head)) {
                bd = list_first_entry(head, struct gfs2_bufdata, bd_list);
                list_del_init(&bd->bd_list);
+               if (!list_empty(&bd->bd_ail_st_list))
+                       gfs2_remove_from_ail(bd);
                kmem_cache_free(gfs2_bufdata_cachep, bd);
        }
 }
@@ -1032,7 +1036,7 @@ repeat:
         * Do this check while holding the log_flush_lock to prevent new
         * buffers from being added to the ail via gfs2_pin()
         */
-       if (gfs2_withdrawn(sdp))
+       if (gfs2_withdrawn(sdp) || !test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))
                goto out;
 
        /* Log might have been flushed while we waited for the flush lock */
index dc1b93a..a82f474 100644 (file)
@@ -267,7 +267,7 @@ static struct bio *gfs2_log_alloc_bio(struct gfs2_sbd *sdp, u64 blkno,
                                      bio_end_io_t *end_io)
 {
        struct super_block *sb = sdp->sd_vfs;
-       struct bio *bio = bio_alloc(GFP_NOIO, BIO_MAX_PAGES);
+       struct bio *bio = bio_alloc(GFP_NOIO, BIO_MAX_VECS);
 
        bio->bi_iter.bi_sector = blkno << sdp->sd_fsb2bb_shift;
        bio_set_dev(bio, sb->s_bdev);
index 74c7d01..aa41360 100644 (file)
@@ -1539,9 +1539,7 @@ static int gfs2_reconfigure(struct fs_context *fc)
                        return -EINVAL;
 
                if (fc->sb_flags & SB_RDONLY) {
-                       error = gfs2_make_fs_ro(sdp);
-                       if (error)
-                               errorfc(fc, "unable to remount read-only");
+                       gfs2_make_fs_ro(sdp);
                } else {
                        error = gfs2_make_fs_rw(sdp);
                        if (error)
index 861ed5f..97076d3 100644 (file)
@@ -587,9 +587,8 @@ out:
  * Returns: errno
  */
 
-int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
+void gfs2_make_fs_ro(struct gfs2_sbd *sdp)
 {
-       int error = 0;
        int log_write_allowed = test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
 
        gfs2_flush_delete_work(sdp);
@@ -624,8 +623,6 @@ int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
 
        if (!log_write_allowed)
                sdp->sd_vfs->s_flags |= SB_RDONLY;
-
-       return error;
 }
 
 /**
@@ -637,7 +634,6 @@ int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
 static void gfs2_put_super(struct super_block *sb)
 {
        struct gfs2_sbd *sdp = sb->s_fs_info;
-       int error;
        struct gfs2_jdesc *jd;
 
        /* No more recovery requests */
@@ -658,9 +654,7 @@ restart:
        spin_unlock(&sdp->sd_jindex_spin);
 
        if (!sb_rdonly(sb)) {
-               error = gfs2_make_fs_ro(sdp);
-               if (error)
-                       gfs2_io_error(sdp);
+               gfs2_make_fs_ro(sdp);
        }
        WARN_ON(gfs2_withdrawing(sdp));
 
index 08e502d..ec4affb 100644 (file)
@@ -34,7 +34,7 @@ extern int gfs2_lookup_in_master_dir(struct gfs2_sbd *sdp, char *filename,
                                     struct gfs2_inode **ipp);
 
 extern int gfs2_make_fs_rw(struct gfs2_sbd *sdp);
-extern int gfs2_make_fs_ro(struct gfs2_sbd *sdp);
+extern void gfs2_make_fs_ro(struct gfs2_sbd *sdp);
 extern void gfs2_online_uevent(struct gfs2_sbd *sdp);
 extern int gfs2_statfs_init(struct gfs2_sbd *sdp);
 extern void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free,
index ab96cf0..63fec11 100644 (file)
@@ -169,6 +169,8 @@ static struct gfs2_bufdata *gfs2_alloc_bufdata(struct gfs2_glock *gl,
        bd->bd_bh = bh;
        bd->bd_gl = gl;
        INIT_LIST_HEAD(&bd->bd_list);
+       INIT_LIST_HEAD(&bd->bd_ail_st_list);
+       INIT_LIST_HEAD(&bd->bd_ail_gl_list);
        bh->b_private = bd;
        return bd;
 }
index 8d3c670..4f034b8 100644 (file)
@@ -119,17 +119,22 @@ void gfs2_freeze_unlock(struct gfs2_holder *freeze_gh)
 static void signal_our_withdraw(struct gfs2_sbd *sdp)
 {
        struct gfs2_glock *live_gl = sdp->sd_live_gh.gh_gl;
-       struct inode *inode = sdp->sd_jdesc->jd_inode;
-       struct gfs2_inode *ip = GFS2_I(inode);
-       struct gfs2_glock *i_gl = ip->i_gl;
-       u64 no_formal_ino = ip->i_no_formal_ino;
+       struct inode *inode;
+       struct gfs2_inode *ip;
+       struct gfs2_glock *i_gl;
+       u64 no_formal_ino;
        int log_write_allowed = test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
        int ret = 0;
        int tries;
 
-       if (test_bit(SDF_NORECOVERY, &sdp->sd_flags))
+       if (test_bit(SDF_NORECOVERY, &sdp->sd_flags) || !sdp->sd_jdesc)
                return;
 
+       inode = sdp->sd_jdesc->jd_inode;
+       ip = GFS2_I(inode);
+       i_gl = ip->i_gl;
+       no_formal_ino = ip->i_no_formal_ino;
+
        /* Prevent any glock dq until withdraw recovery is complete */
        set_bit(SDF_WITHDRAW_RECOVERY, &sdp->sd_flags);
        /*
@@ -156,7 +161,7 @@ static void signal_our_withdraw(struct gfs2_sbd *sdp)
                                ret = 0;
                }
                if (!ret)
-                       ret = gfs2_make_fs_ro(sdp);
+                       gfs2_make_fs_ro(sdp);
                gfs2_freeze_unlock(&freeze_gh);
        }
 
index 28868eb..3dc10bf 100644 (file)
@@ -110,7 +110,6 @@ struct io_wq {
        io_wq_work_fn *do_work;
 
        struct task_struct *manager;
-       struct user_struct *user;
 
        struct io_wq_hash *hash;
 
@@ -387,13 +386,16 @@ static struct io_wq_work *io_get_next_work(struct io_wqe *wqe)
        return NULL;
 }
 
-static void io_flush_signals(void)
+static bool io_flush_signals(void)
 {
        if (unlikely(test_tsk_thread_flag(current, TIF_NOTIFY_SIGNAL))) {
+               __set_current_state(TASK_RUNNING);
                if (current->task_works)
                        task_work_run();
                clear_tsk_thread_flag(current, TIF_NOTIFY_SIGNAL);
+               return true;
        }
+       return false;
 }
 
 static void io_assign_current_work(struct io_worker *worker,
@@ -489,6 +491,8 @@ static int io_wqe_worker(void *data)
        set_task_comm(current, buf);
 
        while (!test_bit(IO_WQ_BIT_EXIT, &wq->state)) {
+               long ret;
+
                set_current_state(TASK_INTERRUPTIBLE);
 loop:
                raw_spin_lock_irq(&wqe->lock);
@@ -498,8 +502,10 @@ loop:
                }
                __io_worker_idle(wqe, worker);
                raw_spin_unlock_irq(&wqe->lock);
-               io_flush_signals();
-               if (schedule_timeout(WORKER_IDLE_TIMEOUT))
+               if (io_flush_signals())
+                       continue;
+               ret = schedule_timeout(WORKER_IDLE_TIMEOUT);
+               if (try_to_freeze() || ret)
                        continue;
                if (fatal_signal_pending(current))
                        break;
@@ -592,7 +598,7 @@ static bool create_io_worker(struct io_wq *wq, struct io_wqe *wqe, int index)
        tsk->pf_io_worker = worker;
        worker->task = tsk;
        set_cpus_allowed_ptr(tsk, cpumask_of_node(wqe->node));
-       tsk->flags |= PF_NOFREEZE | PF_NO_SETAFFINITY;
+       tsk->flags |= PF_NO_SETAFFINITY;
 
        raw_spin_lock_irq(&wqe->lock);
        hlist_nulls_add_head_rcu(&worker->nulls_node, &wqe->free_list);
@@ -722,9 +728,9 @@ static int io_wq_manager(void *data)
                io_wq_for_each_worker(wq->wqes[node], io_wq_worker_wake, NULL);
        rcu_read_unlock();
 
-       /* we might not ever have created any workers */
-       if (atomic_read(&wq->worker_refs))
-               wait_for_completion(&wq->worker_done);
+       if (atomic_dec_and_test(&wq->worker_refs))
+               complete(&wq->worker_done);
+       wait_for_completion(&wq->worker_done);
 
        spin_lock_irq(&wq->hash->wait.lock);
        for_each_node(node)
@@ -774,7 +780,10 @@ static int io_wq_fork_manager(struct io_wq *wq)
        if (wq->manager)
                return 0;
 
-       reinit_completion(&wq->worker_done);
+       WARN_ON_ONCE(test_bit(IO_WQ_BIT_EXIT, &wq->state));
+
+       init_completion(&wq->worker_done);
+       atomic_set(&wq->worker_refs, 1);
        tsk = create_io_thread(io_wq_manager, wq, NUMA_NO_NODE);
        if (!IS_ERR(tsk)) {
                wq->manager = get_task_struct(tsk);
@@ -782,6 +791,9 @@ static int io_wq_fork_manager(struct io_wq *wq)
                return 0;
        }
 
+       if (atomic_dec_and_test(&wq->worker_refs))
+               complete(&wq->worker_done);
+
        return PTR_ERR(tsk);
 }
 
@@ -794,8 +806,7 @@ static void io_wqe_enqueue(struct io_wqe *wqe, struct io_wq_work *work)
        /* Can only happen if manager creation fails after exec */
        if (io_wq_fork_manager(wqe->wq) ||
            test_bit(IO_WQ_BIT_EXIT, &wqe->wq->state)) {
-               work->flags |= IO_WQ_WORK_CANCEL;
-               wqe->wq->do_work(work);
+               io_run_cancel(work, wqe);
                return;
        }
 
@@ -1018,13 +1029,9 @@ struct io_wq *io_wq_create(unsigned bounded, struct io_wq_data *data)
        init_completion(&wq->exited);
        refcount_set(&wq->refs, 1);
 
-       init_completion(&wq->worker_done);
-       atomic_set(&wq->worker_refs, 0);
-
        ret = io_wq_fork_manager(wq);
        if (!ret)
                return wq;
-
 err:
        io_wq_put_hash(data->hash);
        cpuhp_state_remove_instance_nocalls(io_wq_online, &wq->cpuhp_node);
index 5fbf799..80d5905 100644 (file)
@@ -2,7 +2,6 @@
 #define INTERNAL_IO_WQ_H
 
 #include <linux/refcount.h>
-#include <linux/io_uring.h>
 
 struct io_wq;
 
@@ -21,6 +20,15 @@ enum io_wq_cancel {
        IO_WQ_CANCEL_NOTFOUND,  /* work not found */
 };
 
+struct io_wq_work_node {
+       struct io_wq_work_node *next;
+};
+
+struct io_wq_work_list {
+       struct io_wq_work_node *first;
+       struct io_wq_work_node *last;
+};
+
 static inline void wq_list_add_after(struct io_wq_work_node *node,
                                     struct io_wq_work_node *pos,
                                     struct io_wq_work_list *list)
@@ -79,8 +87,8 @@ static inline void wq_list_del(struct io_wq_work_list *list,
 
 struct io_wq_work {
        struct io_wq_work_node list;
+       const struct cred *creds;
        unsigned flags;
-       unsigned short personality;
 };
 
 static inline struct io_wq_work *wq_next_work(struct io_wq_work *work)
index 92c25b5..543551d 100644 (file)
@@ -258,12 +258,11 @@ enum {
 
 struct io_sq_data {
        refcount_t              refs;
+       atomic_t                park_pending;
        struct mutex            lock;
 
        /* ctx's that are using this sqd */
        struct list_head        ctx_list;
-       struct list_head        ctx_new_list;
-       struct mutex            ctx_lock;
 
        struct task_struct      *thread;
        struct wait_queue_head  wait;
@@ -271,11 +270,11 @@ struct io_sq_data {
        unsigned                sq_thread_idle;
        int                     sq_cpu;
        pid_t                   task_pid;
+       pid_t                   task_tgid;
 
        unsigned long           state;
-       struct completion       startup;
-       struct completion       parked;
        struct completion       exited;
+       struct callback_head    *park_task_work;
 };
 
 #define IO_IOPOLL_BATCH                        8
@@ -336,7 +335,6 @@ struct io_ring_ctx {
                unsigned int            drain_next: 1;
                unsigned int            eventfd_async: 1;
                unsigned int            restricted: 1;
-               unsigned int            sqo_exec: 1;
 
                /*
                 * Ring buffer of indices into array of io_uring_sqe, which is
@@ -380,6 +378,7 @@ struct io_ring_ctx {
        /* Only used for accounting purposes */
        struct mm_struct        *mm_account;
 
+       const struct cred       *sq_creds;      /* cred used for __io_sq_thread() */
        struct io_sq_data       *sq_data;       /* if using sq thread polling */
 
        struct wait_queue_head  sqo_sq_wait;
@@ -400,15 +399,15 @@ struct io_ring_ctx {
        struct user_struct      *user;
 
        struct completion       ref_comp;
-       struct completion       sq_thread_comp;
 
 #if defined(CONFIG_UNIX)
        struct socket           *ring_sock;
 #endif
 
-       struct idr              io_buffer_idr;
+       struct xarray           io_buffers;
 
-       struct idr              personality_idr;
+       struct xarray           personalities;
+       u32                     pers_next;
 
        struct {
                unsigned                cached_cq_tail;
@@ -454,6 +453,23 @@ struct io_ring_ctx {
 
        /* Keep this last, we don't need it for the fast path */
        struct work_struct              exit_work;
+       struct list_head                tctx_list;
+};
+
+struct io_uring_task {
+       /* submission side */
+       struct xarray           xa;
+       struct wait_queue_head  wait;
+       const struct io_ring_ctx *last;
+       struct io_wq            *io_wq;
+       struct percpu_counter   inflight;
+       atomic_t                in_idle;
+       bool                    sqpoll;
+
+       spinlock_t              task_lock;
+       struct io_wq_work_list  task_list;
+       unsigned long           task_state;
+       struct callback_head    task_work;
 };
 
 /*
@@ -805,6 +821,12 @@ struct io_kiocb {
        struct io_wq_work               work;
 };
 
+struct io_tctx_node {
+       struct list_head        ctx_node;
+       struct task_struct      *task;
+       struct io_ring_ctx      *ctx;
+};
+
 struct io_defer_entry {
        struct list_head        list;
        struct io_kiocb         *req;
@@ -979,6 +1001,8 @@ static const struct io_op_def io_op_defs[] = {
        [IORING_OP_UNLINKAT] = {},
 };
 
+static bool io_disarm_next(struct io_kiocb *req);
+static void io_uring_del_task_file(unsigned long index);
 static void io_uring_try_cancel_requests(struct io_ring_ctx *ctx,
                                         struct task_struct *task,
                                         struct files_struct *files);
@@ -1129,9 +1153,8 @@ static struct io_ring_ctx *io_ring_ctx_alloc(struct io_uring_params *p)
        init_waitqueue_head(&ctx->cq_wait);
        INIT_LIST_HEAD(&ctx->cq_overflow_list);
        init_completion(&ctx->ref_comp);
-       init_completion(&ctx->sq_thread_comp);
-       idr_init(&ctx->io_buffer_idr);
-       idr_init(&ctx->personality_idr);
+       xa_init_flags(&ctx->io_buffers, XA_FLAGS_ALLOC1);
+       xa_init_flags(&ctx->personalities, XA_FLAGS_ALLOC1);
        mutex_init(&ctx->uring_lock);
        init_waitqueue_head(&ctx->wait);
        spin_lock_init(&ctx->completion_lock);
@@ -1144,6 +1167,7 @@ static struct io_ring_ctx *io_ring_ctx_alloc(struct io_uring_params *p)
        INIT_LIST_HEAD(&ctx->rsrc_ref_list);
        INIT_DELAYED_WORK(&ctx->rsrc_put_work, io_rsrc_put_work);
        init_llist_head(&ctx->rsrc_put_llist);
+       INIT_LIST_HEAD(&ctx->tctx_list);
        INIT_LIST_HEAD(&ctx->submit_state.comp.free_list);
        INIT_LIST_HEAD(&ctx->submit_state.comp.locked_free_list);
        return ctx;
@@ -1183,6 +1207,9 @@ static void io_prep_async_work(struct io_kiocb *req)
        const struct io_op_def *def = &io_op_defs[req->opcode];
        struct io_ring_ctx *ctx = req->ctx;
 
+       if (!req->work.creds)
+               req->work.creds = get_current_cred();
+
        if (req->flags & REQ_F_FORCE_ASYNC)
                req->work.flags |= IO_WQ_WORK_CONCURRENT;
 
@@ -1514,15 +1541,14 @@ static void io_cqring_fill_event(struct io_kiocb *req, long res)
        __io_cqring_fill_event(req, res, 0);
 }
 
-static inline void io_req_complete_post(struct io_kiocb *req, long res,
-                                       unsigned int cflags)
+static void io_req_complete_post(struct io_kiocb *req, long res,
+                                unsigned int cflags)
 {
        struct io_ring_ctx *ctx = req->ctx;
        unsigned long flags;
 
        spin_lock_irqsave(&ctx->completion_lock, flags);
        __io_cqring_fill_event(req, res, cflags);
-       io_commit_cqring(ctx);
        /*
         * If we're the last reference to this request, add to our locked
         * free_list cache.
@@ -1530,17 +1556,27 @@ static inline void io_req_complete_post(struct io_kiocb *req, long res,
        if (refcount_dec_and_test(&req->refs)) {
                struct io_comp_state *cs = &ctx->submit_state.comp;
 
+               if (req->flags & (REQ_F_LINK | REQ_F_HARDLINK)) {
+                       if (req->flags & (REQ_F_LINK_TIMEOUT | REQ_F_FAIL_LINK))
+                               io_disarm_next(req);
+                       if (req->link) {
+                               io_req_task_queue(req->link);
+                               req->link = NULL;
+                       }
+               }
                io_dismantle_req(req);
                io_put_task(req->task, 1);
                list_add(&req->compl.list, &cs->locked_free_list);
                cs->locked_free_nr++;
-       } else
-               req = NULL;
+       } else {
+               if (!percpu_ref_tryget(&ctx->refs))
+                       req = NULL;
+       }
+       io_commit_cqring(ctx);
        spin_unlock_irqrestore(&ctx->completion_lock, flags);
 
-       io_cqring_ev_posted(ctx);
        if (req) {
-               io_queue_next(req);
+               io_cqring_ev_posted(ctx);
                percpu_ref_put(&ctx->refs);
        }
 }
@@ -1648,6 +1684,10 @@ static void io_dismantle_req(struct io_kiocb *req)
                io_put_file(req, req->file, (req->flags & REQ_F_FIXED_FILE));
        if (req->fixed_rsrc_refs)
                percpu_ref_put(req->fixed_rsrc_refs);
+       if (req->work.creds) {
+               put_cred(req->work.creds);
+               req->work.creds = NULL;
+       }
 
        if (req->flags & REQ_F_INFLIGHT) {
                struct io_ring_ctx *ctx = req->ctx;
@@ -1690,15 +1730,11 @@ static inline void io_remove_next_linked(struct io_kiocb *req)
        nxt->link = NULL;
 }
 
-static void io_kill_linked_timeout(struct io_kiocb *req)
+static bool io_kill_linked_timeout(struct io_kiocb *req)
+       __must_hold(&req->ctx->completion_lock)
 {
-       struct io_ring_ctx *ctx = req->ctx;
-       struct io_kiocb *link;
+       struct io_kiocb *link = req->link;
        bool cancelled = false;
-       unsigned long flags;
-
-       spin_lock_irqsave(&ctx->completion_lock, flags);
-       link = req->link;
 
        /*
         * Can happen if a linked timeout fired and link had been like
@@ -1713,50 +1749,48 @@ static void io_kill_linked_timeout(struct io_kiocb *req)
                ret = hrtimer_try_to_cancel(&io->timer);
                if (ret != -1) {
                        io_cqring_fill_event(link, -ECANCELED);
-                       io_commit_cqring(ctx);
+                       io_put_req_deferred(link, 1);
                        cancelled = true;
                }
        }
        req->flags &= ~REQ_F_LINK_TIMEOUT;
-       spin_unlock_irqrestore(&ctx->completion_lock, flags);
-
-       if (cancelled) {
-               io_cqring_ev_posted(ctx);
-               io_put_req(link);
-       }
+       return cancelled;
 }
 
-
 static void io_fail_links(struct io_kiocb *req)
+       __must_hold(&req->ctx->completion_lock)
 {
-       struct io_kiocb *link, *nxt;
-       struct io_ring_ctx *ctx = req->ctx;
-       unsigned long flags;
+       struct io_kiocb *nxt, *link = req->link;
 
-       spin_lock_irqsave(&ctx->completion_lock, flags);
-       link = req->link;
        req->link = NULL;
-
        while (link) {
                nxt = link->link;
                link->link = NULL;
 
                trace_io_uring_fail_link(req, link);
                io_cqring_fill_event(link, -ECANCELED);
-
                io_put_req_deferred(link, 2);
                link = nxt;
        }
-       io_commit_cqring(ctx);
-       spin_unlock_irqrestore(&ctx->completion_lock, flags);
+}
 
-       io_cqring_ev_posted(ctx);
+static bool io_disarm_next(struct io_kiocb *req)
+       __must_hold(&req->ctx->completion_lock)
+{
+       bool posted = false;
+
+       if (likely(req->flags & REQ_F_LINK_TIMEOUT))
+               posted = io_kill_linked_timeout(req);
+       if (unlikely(req->flags & REQ_F_FAIL_LINK)) {
+               posted |= (req->link != NULL);
+               io_fail_links(req);
+       }
+       return posted;
 }
 
 static struct io_kiocb *__io_req_find_next(struct io_kiocb *req)
 {
-       if (req->flags & REQ_F_LINK_TIMEOUT)
-               io_kill_linked_timeout(req);
+       struct io_kiocb *nxt;
 
        /*
         * If LINK is set, we have dependent requests in this chain. If we
@@ -1764,14 +1798,22 @@ static struct io_kiocb *__io_req_find_next(struct io_kiocb *req)
         * dependencies to the next request. In case of failure, fail the rest
         * of the chain.
         */
-       if (likely(!(req->flags & REQ_F_FAIL_LINK))) {
-               struct io_kiocb *nxt = req->link;
+       if (req->flags & (REQ_F_LINK_TIMEOUT | REQ_F_FAIL_LINK)) {
+               struct io_ring_ctx *ctx = req->ctx;
+               unsigned long flags;
+               bool posted;
 
-               req->link = NULL;
-               return nxt;
+               spin_lock_irqsave(&ctx->completion_lock, flags);
+               posted = io_disarm_next(req);
+               if (posted)
+                       io_commit_cqring(req->ctx);
+               spin_unlock_irqrestore(&ctx->completion_lock, flags);
+               if (posted)
+                       io_cqring_ev_posted(ctx);
        }
-       io_fail_links(req);
-       return NULL;
+       nxt = req->link;
+       req->link = NULL;
+       return nxt;
 }
 
 static inline struct io_kiocb *io_req_find_next(struct io_kiocb *req)
@@ -1904,17 +1946,44 @@ static int io_req_task_work_add(struct io_kiocb *req)
        return ret;
 }
 
-static void io_req_task_work_add_fallback(struct io_kiocb *req,
-                                         task_work_func_t cb)
+static bool io_run_task_work_head(struct callback_head **work_head)
+{
+       struct callback_head *work, *next;
+       bool executed = false;
+
+       do {
+               work = xchg(work_head, NULL);
+               if (!work)
+                       break;
+
+               do {
+                       next = work->next;
+                       work->func(work);
+                       work = next;
+                       cond_resched();
+               } while (work);
+               executed = true;
+       } while (1);
+
+       return executed;
+}
+
+static void io_task_work_add_head(struct callback_head **work_head,
+                                 struct callback_head *task_work)
 {
-       struct io_ring_ctx *ctx = req->ctx;
        struct callback_head *head;
 
-       init_task_work(&req->task_work, cb);
        do {
-               head = READ_ONCE(ctx->exit_task_work);
-               req->task_work.next = head;
-       } while (cmpxchg(&ctx->exit_task_work, head, &req->task_work) != head);
+               head = READ_ONCE(*work_head);
+               task_work->next = head;
+       } while (cmpxchg(work_head, head, task_work) != head);
+}
+
+static void io_req_task_work_add_fallback(struct io_kiocb *req,
+                                         task_work_func_t cb)
+{
+       init_task_work(&req->task_work, cb);
+       io_task_work_add_head(&req->ctx->exit_task_work, &req->task_work);
 }
 
 static void __io_req_task_cancel(struct io_kiocb *req, int error)
@@ -2822,7 +2891,7 @@ static struct io_buffer *io_buffer_select(struct io_kiocb *req, size_t *len,
 
        lockdep_assert_held(&req->ctx->uring_lock);
 
-       head = idr_find(&req->ctx->io_buffer_idr, bgid);
+       head = xa_load(&req->ctx->io_buffers, bgid);
        if (head) {
                if (!list_empty(&head->list)) {
                        kbuf = list_last_entry(&head->list, struct io_buffer,
@@ -2830,7 +2899,7 @@ static struct io_buffer *io_buffer_select(struct io_kiocb *req, size_t *len,
                        list_del(&kbuf->list);
                } else {
                        kbuf = head;
-                       idr_remove(&req->ctx->io_buffer_idr, bgid);
+                       xa_erase(&req->ctx->io_buffers, bgid);
                }
                if (*len > kbuf->len)
                        *len = kbuf->len;
@@ -3871,7 +3940,7 @@ static int __io_remove_buffers(struct io_ring_ctx *ctx, struct io_buffer *buf,
        }
        i++;
        kfree(buf);
-       idr_remove(&ctx->io_buffer_idr, bgid);
+       xa_erase(&ctx->io_buffers, bgid);
 
        return i;
 }
@@ -3889,7 +3958,7 @@ static int io_remove_buffers(struct io_kiocb *req, unsigned int issue_flags)
        lockdep_assert_held(&ctx->uring_lock);
 
        ret = -ENOENT;
-       head = idr_find(&ctx->io_buffer_idr, p->bgid);
+       head = xa_load(&ctx->io_buffers, p->bgid);
        if (head)
                ret = __io_remove_buffers(ctx, head, p->bgid, p->nbufs);
        if (ret < 0)
@@ -3972,21 +4041,14 @@ static int io_provide_buffers(struct io_kiocb *req, unsigned int issue_flags)
 
        lockdep_assert_held(&ctx->uring_lock);
 
-       list = head = idr_find(&ctx->io_buffer_idr, p->bgid);
+       list = head = xa_load(&ctx->io_buffers, p->bgid);
 
        ret = io_add_buffers(p, &head);
-       if (ret < 0)
-               goto out;
-
-       if (!list) {
-               ret = idr_alloc(&ctx->io_buffer_idr, head, p->bgid, p->bgid + 1,
-                                       GFP_KERNEL);
-               if (ret < 0) {
+       if (ret >= 0 && !list) {
+               ret = xa_insert(&ctx->io_buffers, p->bgid, head, GFP_KERNEL);
+               if (ret < 0)
                        __io_remove_buffers(ctx, head, p->bgid, -1U);
-                       goto out;
-               }
        }
-out:
        if (ret < 0)
                req_set_fail_links(req);
 
@@ -4324,6 +4386,7 @@ static int io_sendmsg(struct io_kiocb *req, unsigned int issue_flags)
        struct io_async_msghdr iomsg, *kmsg;
        struct socket *sock;
        unsigned flags;
+       int min_ret = 0;
        int ret;
 
        sock = sock_from_file(req->file);
@@ -4338,12 +4401,15 @@ static int io_sendmsg(struct io_kiocb *req, unsigned int issue_flags)
                kmsg = &iomsg;
        }
 
-       flags = req->sr_msg.msg_flags;
+       flags = req->sr_msg.msg_flags | MSG_NOSIGNAL;
        if (flags & MSG_DONTWAIT)
                req->flags |= REQ_F_NOWAIT;
        else if (issue_flags & IO_URING_F_NONBLOCK)
                flags |= MSG_DONTWAIT;
 
+       if (flags & MSG_WAITALL)
+               min_ret = iov_iter_count(&kmsg->msg.msg_iter);
+
        ret = __sys_sendmsg_sock(sock, &kmsg->msg, flags);
        if ((issue_flags & IO_URING_F_NONBLOCK) && ret == -EAGAIN)
                return io_setup_async_msg(req, kmsg);
@@ -4354,7 +4420,7 @@ static int io_sendmsg(struct io_kiocb *req, unsigned int issue_flags)
        if (kmsg->free_iov)
                kfree(kmsg->free_iov);
        req->flags &= ~REQ_F_NEED_CLEANUP;
-       if (ret < 0)
+       if (ret < min_ret)
                req_set_fail_links(req);
        __io_req_complete(req, issue_flags, ret, 0);
        return 0;
@@ -4367,6 +4433,7 @@ static int io_send(struct io_kiocb *req, unsigned int issue_flags)
        struct iovec iov;
        struct socket *sock;
        unsigned flags;
+       int min_ret = 0;
        int ret;
 
        sock = sock_from_file(req->file);
@@ -4382,12 +4449,15 @@ static int io_send(struct io_kiocb *req, unsigned int issue_flags)
        msg.msg_controllen = 0;
        msg.msg_namelen = 0;
 
-       flags = req->sr_msg.msg_flags;
+       flags = req->sr_msg.msg_flags | MSG_NOSIGNAL;
        if (flags & MSG_DONTWAIT)
                req->flags |= REQ_F_NOWAIT;
        else if (issue_flags & IO_URING_F_NONBLOCK)
                flags |= MSG_DONTWAIT;
 
+       if (flags & MSG_WAITALL)
+               min_ret = iov_iter_count(&msg.msg_iter);
+
        msg.msg_flags = flags;
        ret = sock_sendmsg(sock, &msg);
        if ((issue_flags & IO_URING_F_NONBLOCK) && ret == -EAGAIN)
@@ -4395,7 +4465,7 @@ static int io_send(struct io_kiocb *req, unsigned int issue_flags)
        if (ret == -ERESTARTSYS)
                ret = -EINTR;
 
-       if (ret < 0)
+       if (ret < min_ret)
                req_set_fail_links(req);
        __io_req_complete(req, issue_flags, ret, 0);
        return 0;
@@ -4547,6 +4617,7 @@ static int io_recvmsg(struct io_kiocb *req, unsigned int issue_flags)
        struct socket *sock;
        struct io_buffer *kbuf;
        unsigned flags;
+       int min_ret = 0;
        int ret, cflags = 0;
        bool force_nonblock = issue_flags & IO_URING_F_NONBLOCK;
 
@@ -4572,12 +4643,15 @@ static int io_recvmsg(struct io_kiocb *req, unsigned int issue_flags)
                                1, req->sr_msg.len);
        }
 
-       flags = req->sr_msg.msg_flags;
+       flags = req->sr_msg.msg_flags | MSG_NOSIGNAL;
        if (flags & MSG_DONTWAIT)
                req->flags |= REQ_F_NOWAIT;
        else if (force_nonblock)
                flags |= MSG_DONTWAIT;
 
+       if (flags & MSG_WAITALL)
+               min_ret = iov_iter_count(&kmsg->msg.msg_iter);
+
        ret = __sys_recvmsg_sock(sock, &kmsg->msg, req->sr_msg.umsg,
                                        kmsg->uaddr, flags);
        if (force_nonblock && ret == -EAGAIN)
@@ -4591,7 +4665,7 @@ static int io_recvmsg(struct io_kiocb *req, unsigned int issue_flags)
        if (kmsg->free_iov)
                kfree(kmsg->free_iov);
        req->flags &= ~REQ_F_NEED_CLEANUP;
-       if (ret < 0)
+       if (ret < min_ret || ((flags & MSG_WAITALL) && (kmsg->msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC))))
                req_set_fail_links(req);
        __io_req_complete(req, issue_flags, ret, cflags);
        return 0;
@@ -4606,6 +4680,7 @@ static int io_recv(struct io_kiocb *req, unsigned int issue_flags)
        struct socket *sock;
        struct iovec iov;
        unsigned flags;
+       int min_ret = 0;
        int ret, cflags = 0;
        bool force_nonblock = issue_flags & IO_URING_F_NONBLOCK;
 
@@ -4631,12 +4706,15 @@ static int io_recv(struct io_kiocb *req, unsigned int issue_flags)
        msg.msg_iocb = NULL;
        msg.msg_flags = 0;
 
-       flags = req->sr_msg.msg_flags;
+       flags = req->sr_msg.msg_flags | MSG_NOSIGNAL;
        if (flags & MSG_DONTWAIT)
                req->flags |= REQ_F_NOWAIT;
        else if (force_nonblock)
                flags |= MSG_DONTWAIT;
 
+       if (flags & MSG_WAITALL)
+               min_ret = iov_iter_count(&msg.msg_iter);
+
        ret = sock_recvmsg(sock, &msg, flags);
        if (force_nonblock && ret == -EAGAIN)
                return -EAGAIN;
@@ -4645,7 +4723,7 @@ static int io_recv(struct io_kiocb *req, unsigned int issue_flags)
 out_free:
        if (req->flags & REQ_F_BUFFER_SELECTED)
                cflags = io_put_recv_kbuf(req);
-       if (ret < 0)
+       if (ret < min_ret || ((flags & MSG_WAITALL) && (msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC))))
                req_set_fail_links(req);
        __io_req_complete(req, issue_flags, ret, cflags);
        return 0;
@@ -5559,22 +5637,30 @@ add:
        return 0;
 }
 
+struct io_cancel_data {
+       struct io_ring_ctx *ctx;
+       u64 user_data;
+};
+
 static bool io_cancel_cb(struct io_wq_work *work, void *data)
 {
        struct io_kiocb *req = container_of(work, struct io_kiocb, work);
+       struct io_cancel_data *cd = data;
 
-       return req->user_data == (unsigned long) data;
+       return req->ctx == cd->ctx && req->user_data == cd->user_data;
 }
 
-static int io_async_cancel_one(struct io_uring_task *tctx, void *sqe_addr)
+static int io_async_cancel_one(struct io_uring_task *tctx, u64 user_data,
+                              struct io_ring_ctx *ctx)
 {
+       struct io_cancel_data data = { .ctx = ctx, .user_data = user_data, };
        enum io_wq_cancel cancel_ret;
        int ret = 0;
 
-       if (!tctx->io_wq)
+       if (!tctx || !tctx->io_wq)
                return -ENOENT;
 
-       cancel_ret = io_wq_cancel_cb(tctx->io_wq, io_cancel_cb, sqe_addr, false);
+       cancel_ret = io_wq_cancel_cb(tctx->io_wq, io_cancel_cb, &data, false);
        switch (cancel_ret) {
        case IO_WQ_CANCEL_OK:
                ret = 0;
@@ -5597,8 +5683,7 @@ static void io_async_find_and_cancel(struct io_ring_ctx *ctx,
        unsigned long flags;
        int ret;
 
-       ret = io_async_cancel_one(req->task->io_uring,
-                                       (void *) (unsigned long) sqe_addr);
+       ret = io_async_cancel_one(req->task->io_uring, sqe_addr, ctx);
        if (ret != -ENOENT) {
                spin_lock_irqsave(&ctx->completion_lock, flags);
                goto done;
@@ -5639,8 +5724,47 @@ static int io_async_cancel_prep(struct io_kiocb *req,
 static int io_async_cancel(struct io_kiocb *req, unsigned int issue_flags)
 {
        struct io_ring_ctx *ctx = req->ctx;
+       u64 sqe_addr = req->cancel.addr;
+       struct io_tctx_node *node;
+       int ret;
 
-       io_async_find_and_cancel(ctx, req, req->cancel.addr, 0);
+       /* tasks should wait for their io-wq threads, so safe w/o sync */
+       ret = io_async_cancel_one(req->task->io_uring, sqe_addr, ctx);
+       spin_lock_irq(&ctx->completion_lock);
+       if (ret != -ENOENT)
+               goto done;
+       ret = io_timeout_cancel(ctx, sqe_addr);
+       if (ret != -ENOENT)
+               goto done;
+       ret = io_poll_cancel(ctx, sqe_addr);
+       if (ret != -ENOENT)
+               goto done;
+       spin_unlock_irq(&ctx->completion_lock);
+
+       /* slow path, try all io-wq's */
+       io_ring_submit_lock(ctx, !(issue_flags & IO_URING_F_NONBLOCK));
+       ret = -ENOENT;
+       list_for_each_entry(node, &ctx->tctx_list, ctx_node) {
+               struct io_uring_task *tctx = node->task->io_uring;
+
+               if (!tctx || !tctx->io_wq)
+                       continue;
+               ret = io_async_cancel_one(tctx, req->cancel.addr, ctx);
+               if (ret != -ENOENT)
+                       break;
+       }
+       io_ring_submit_unlock(ctx, !(issue_flags & IO_URING_F_NONBLOCK));
+
+       spin_lock_irq(&ctx->completion_lock);
+done:
+       io_cqring_fill_event(req, ret);
+       io_commit_cqring(ctx);
+       spin_unlock_irq(&ctx->completion_lock);
+       io_cqring_ev_posted(ctx);
+
+       if (ret < 0)
+               req_set_fail_links(req);
+       io_put_req(req);
        return 0;
 }
 
@@ -5916,18 +6040,8 @@ static int io_issue_sqe(struct io_kiocb *req, unsigned int issue_flags)
        const struct cred *creds = NULL;
        int ret;
 
-       if (req->work.personality) {
-               const struct cred *new_creds;
-
-               if (!(issue_flags & IO_URING_F_NONBLOCK))
-                       mutex_lock(&ctx->uring_lock);
-               new_creds = idr_find(&ctx->personality_idr, req->work.personality);
-               if (!(issue_flags & IO_URING_F_NONBLOCK))
-                       mutex_unlock(&ctx->uring_lock);
-               if (!new_creds)
-                       return -EINVAL;
-               creds = override_creds(new_creds);
-       }
+       if (req->work.creds && req->work.creds != current_cred())
+               creds = override_creds(req->work.creds);
 
        switch (req->opcode) {
        case IORING_OP_NOP:
@@ -6147,7 +6261,6 @@ static enum hrtimer_restart io_link_timeout_fn(struct hrtimer *timer)
        spin_unlock_irqrestore(&ctx->completion_lock, flags);
 
        if (prev) {
-               req_set_fail_links(prev);
                io_async_find_and_cancel(ctx, req, prev->user_data, -ETIME);
                io_put_req_deferred(prev, 1);
        } else {
@@ -6291,7 +6404,7 @@ static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req,
 {
        struct io_submit_state *state;
        unsigned int sqe_flags;
-       int ret = 0;
+       int personality, ret = 0;
 
        req->opcode = READ_ONCE(sqe->opcode);
        /* same numerical values with corresponding REQ_F_*, safe to copy */
@@ -6306,6 +6419,9 @@ static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req,
        refcount_set(&req->refs, 2);
        req->task = current;
        req->result = 0;
+       req->work.list.next = NULL;
+       req->work.creds = NULL;
+       req->work.flags = 0;
 
        /* enforce forwards compatibility on users */
        if (unlikely(sqe_flags & ~SQE_VALID_FLAGS)) {
@@ -6323,9 +6439,13 @@ static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req,
            !io_op_defs[req->opcode].buffer_select)
                return -EOPNOTSUPP;
 
-       req->work.list.next = NULL;
-       req->work.flags = 0;
-       req->work.personality = READ_ONCE(sqe->personality);
+       personality = READ_ONCE(sqe->personality);
+       if (personality) {
+               req->work.creds = xa_load(&ctx->personalities, personality);
+               if (!req->work.creds)
+                       return -EINVAL;
+               get_cred(req->work.creds);
+       }
        state = &ctx->submit_state;
 
        /*
@@ -6587,7 +6707,8 @@ static int __io_sq_thread(struct io_ring_ctx *ctx, bool cap_entries)
                if (!list_empty(&ctx->iopoll_list))
                        io_do_iopoll(ctx, &nr_events, 0);
 
-               if (to_submit && likely(!percpu_ref_is_dying(&ctx->refs)))
+               if (to_submit && likely(!percpu_ref_is_dying(&ctx->refs)) &&
+                   !(ctx->flags & IORING_SETUP_R_DISABLED))
                        ret = io_submit_sqes(ctx, to_submit);
                mutex_unlock(&ctx->uring_lock);
        }
@@ -6611,58 +6732,6 @@ static void io_sqd_update_thread_idle(struct io_sq_data *sqd)
        sqd->sq_thread_idle = sq_thread_idle;
 }
 
-static void io_sqd_init_new(struct io_sq_data *sqd)
-{
-       struct io_ring_ctx *ctx;
-
-       while (!list_empty(&sqd->ctx_new_list)) {
-               ctx = list_first_entry(&sqd->ctx_new_list, struct io_ring_ctx, sqd_list);
-               list_move_tail(&ctx->sqd_list, &sqd->ctx_list);
-               complete(&ctx->sq_thread_comp);
-       }
-
-       io_sqd_update_thread_idle(sqd);
-}
-
-static bool io_sq_thread_should_stop(struct io_sq_data *sqd)
-{
-       return test_bit(IO_SQ_THREAD_SHOULD_STOP, &sqd->state);
-}
-
-static bool io_sq_thread_should_park(struct io_sq_data *sqd)
-{
-       return test_bit(IO_SQ_THREAD_SHOULD_PARK, &sqd->state);
-}
-
-static void io_sq_thread_parkme(struct io_sq_data *sqd)
-{
-       for (;;) {
-               /*
-                * TASK_PARKED is a special state; we must serialize against
-                * possible pending wakeups to avoid store-store collisions on
-                * task->state.
-                *
-                * Such a collision might possibly result in the task state
-                * changin from TASK_PARKED and us failing the
-                * wait_task_inactive() in kthread_park().
-                */
-               set_special_state(TASK_PARKED);
-               if (!test_bit(IO_SQ_THREAD_SHOULD_PARK, &sqd->state))
-                       break;
-
-               /*
-                * Thread is going to call schedule(), do not preempt it,
-                * or the caller of kthread_park() may spend more time in
-                * wait_task_inactive().
-                */
-               preempt_disable();
-               complete(&sqd->parked);
-               schedule_preempt_disabled();
-               preempt_enable();
-       }
-       __set_current_state(TASK_RUNNING);
-}
-
 static int io_sq_thread(void *data)
 {
        struct io_sq_data *sqd = data;
@@ -6681,31 +6750,32 @@ static int io_sq_thread(void *data)
                set_cpus_allowed_ptr(current, cpu_online_mask);
        current->flags |= PF_NO_SETAFFINITY;
 
-       wait_for_completion(&sqd->startup);
-
-       while (!io_sq_thread_should_stop(sqd)) {
+       mutex_lock(&sqd->lock);
+       while (!test_bit(IO_SQ_THREAD_SHOULD_STOP, &sqd->state)) {
                int ret;
                bool cap_entries, sqt_spin, needs_sched;
 
-               /*
-                * Any changes to the sqd lists are synchronized through the
-                * thread parking. This synchronizes the thread vs users,
-                * the users are synchronized on the sqd->ctx_lock.
-                */
-               if (io_sq_thread_should_park(sqd)) {
-                       io_sq_thread_parkme(sqd);
-                       continue;
-               }
-               if (unlikely(!list_empty(&sqd->ctx_new_list))) {
-                       io_sqd_init_new(sqd);
+               if (test_bit(IO_SQ_THREAD_SHOULD_PARK, &sqd->state)) {
+                       mutex_unlock(&sqd->lock);
+                       cond_resched();
+                       mutex_lock(&sqd->lock);
+                       io_run_task_work();
+                       io_run_task_work_head(&sqd->park_task_work);
                        timeout = jiffies + sqd->sq_thread_idle;
+                       continue;
                }
                if (fatal_signal_pending(current))
                        break;
                sqt_spin = false;
                cap_entries = !list_is_singular(&sqd->ctx_list);
                list_for_each_entry(ctx, &sqd->ctx_list, sqd_list) {
+                       const struct cred *creds = NULL;
+
+                       if (ctx->sq_creds != current_cred())
+                               creds = override_creds(ctx->sq_creds);
                        ret = __io_sq_thread(ctx, cap_entries);
+                       if (creds)
+                               revert_creds(creds);
                        if (!sqt_spin && (ret > 0 || !list_empty(&ctx->iopoll_list)))
                                sqt_spin = true;
                }
@@ -6732,45 +6802,33 @@ static int io_sq_thread(void *data)
                        }
                }
 
-               if (needs_sched && !io_sq_thread_should_park(sqd)) {
+               if (needs_sched && !test_bit(IO_SQ_THREAD_SHOULD_PARK, &sqd->state)) {
                        list_for_each_entry(ctx, &sqd->ctx_list, sqd_list)
                                io_ring_set_wakeup_flag(ctx);
 
+                       mutex_unlock(&sqd->lock);
                        schedule();
                        try_to_freeze();
+                       mutex_lock(&sqd->lock);
                        list_for_each_entry(ctx, &sqd->ctx_list, sqd_list)
                                io_ring_clear_wakeup_flag(ctx);
                }
 
                finish_wait(&sqd->wait, &wait);
+               io_run_task_work_head(&sqd->park_task_work);
                timeout = jiffies + sqd->sq_thread_idle;
        }
 
        list_for_each_entry(ctx, &sqd->ctx_list, sqd_list)
                io_uring_cancel_sqpoll(ctx);
-
-       io_run_task_work();
-
-       /*
-        * Ensure that we park properly if racing with someone trying to park
-        * while we're exiting. If we fail to grab the lock, check park and
-        * park if necessary. The ordering with the park bit and the lock
-        * ensures that we catch this reliably.
-        */
-       if (!mutex_trylock(&sqd->lock)) {
-               if (io_sq_thread_should_park(sqd))
-                       io_sq_thread_parkme(sqd);
-               mutex_lock(&sqd->lock);
-       }
-
        sqd->thread = NULL;
-       list_for_each_entry(ctx, &sqd->ctx_list, sqd_list) {
-               ctx->sqo_exec = 1;
+       list_for_each_entry(ctx, &sqd->ctx_list, sqd_list)
                io_ring_set_wakeup_flag(ctx);
-       }
+       mutex_unlock(&sqd->lock);
 
+       io_run_task_work();
+       io_run_task_work_head(&sqd->park_task_work);
        complete(&sqd->exited);
-       mutex_unlock(&sqd->lock);
        do_exit(0);
 }
 
@@ -7071,47 +7129,47 @@ static int io_sqe_files_unregister(struct io_ring_ctx *ctx)
 static void io_sq_thread_unpark(struct io_sq_data *sqd)
        __releases(&sqd->lock)
 {
-       if (sqd->thread == current)
-               return;
+       WARN_ON_ONCE(sqd->thread == current);
+
+       /*
+        * Do the dance but not conditional clear_bit() because it'd race with
+        * other threads incrementing park_pending and setting the bit.
+        */
        clear_bit(IO_SQ_THREAD_SHOULD_PARK, &sqd->state);
-       if (sqd->thread)
-               wake_up_state(sqd->thread, TASK_PARKED);
+       if (atomic_dec_return(&sqd->park_pending))
+               set_bit(IO_SQ_THREAD_SHOULD_PARK, &sqd->state);
        mutex_unlock(&sqd->lock);
 }
 
 static void io_sq_thread_park(struct io_sq_data *sqd)
        __acquires(&sqd->lock)
 {
-       if (sqd->thread == current)
-               return;
+       WARN_ON_ONCE(sqd->thread == current);
+
+       atomic_inc(&sqd->park_pending);
        set_bit(IO_SQ_THREAD_SHOULD_PARK, &sqd->state);
        mutex_lock(&sqd->lock);
-       if (sqd->thread) {
+       if (sqd->thread)
                wake_up_process(sqd->thread);
-               wait_for_completion(&sqd->parked);
-       }
 }
 
 static void io_sq_thread_stop(struct io_sq_data *sqd)
 {
-       if (test_bit(IO_SQ_THREAD_SHOULD_STOP, &sqd->state))
-               return;
+       WARN_ON_ONCE(sqd->thread == current);
+
        mutex_lock(&sqd->lock);
-       if (sqd->thread) {
-               set_bit(IO_SQ_THREAD_SHOULD_STOP, &sqd->state);
-               WARN_ON_ONCE(test_bit(IO_SQ_THREAD_SHOULD_PARK, &sqd->state));
+       set_bit(IO_SQ_THREAD_SHOULD_STOP, &sqd->state);
+       if (sqd->thread)
                wake_up_process(sqd->thread);
-               mutex_unlock(&sqd->lock);
-               wait_for_completion(&sqd->exited);
-               WARN_ON_ONCE(sqd->thread);
-       } else {
-               mutex_unlock(&sqd->lock);
-       }
+       mutex_unlock(&sqd->lock);
+       wait_for_completion(&sqd->exited);
 }
 
 static void io_put_sq_data(struct io_sq_data *sqd)
 {
        if (refcount_dec_and_test(&sqd->refs)) {
+               WARN_ON_ONCE(atomic_read(&sqd->park_pending));
+
                io_sq_thread_stop(sqd);
                kfree(sqd);
        }
@@ -7122,22 +7180,15 @@ static void io_sq_thread_finish(struct io_ring_ctx *ctx)
        struct io_sq_data *sqd = ctx->sq_data;
 
        if (sqd) {
-               complete(&sqd->startup);
-               if (sqd->thread) {
-                       wait_for_completion(&ctx->sq_thread_comp);
-                       io_sq_thread_park(sqd);
-               }
-
-               mutex_lock(&sqd->ctx_lock);
-               list_del(&ctx->sqd_list);
+               io_sq_thread_park(sqd);
+               list_del_init(&ctx->sqd_list);
                io_sqd_update_thread_idle(sqd);
-               mutex_unlock(&sqd->ctx_lock);
-
-               if (sqd->thread)
-                       io_sq_thread_unpark(sqd);
+               io_sq_thread_unpark(sqd);
 
                io_put_sq_data(sqd);
                ctx->sq_data = NULL;
+               if (ctx->sq_creds)
+                       put_cred(ctx->sq_creds);
        }
 }
 
@@ -7161,31 +7212,42 @@ static struct io_sq_data *io_attach_sq_data(struct io_uring_params *p)
                fdput(f);
                return ERR_PTR(-EINVAL);
        }
+       if (sqd->task_tgid != current->tgid) {
+               fdput(f);
+               return ERR_PTR(-EPERM);
+       }
 
        refcount_inc(&sqd->refs);
        fdput(f);
        return sqd;
 }
 
-static struct io_sq_data *io_get_sq_data(struct io_uring_params *p)
+static struct io_sq_data *io_get_sq_data(struct io_uring_params *p,
+                                        bool *attached)
 {
        struct io_sq_data *sqd;
 
-       if (p->flags & IORING_SETUP_ATTACH_WQ)
-               return io_attach_sq_data(p);
+       *attached = false;
+       if (p->flags & IORING_SETUP_ATTACH_WQ) {
+               sqd = io_attach_sq_data(p);
+               if (!IS_ERR(sqd)) {
+                       *attached = true;
+                       return sqd;
+               }
+               /* fall through for EPERM case, setup new sqd/task */
+               if (PTR_ERR(sqd) != -EPERM)
+                       return sqd;
+       }
 
        sqd = kzalloc(sizeof(*sqd), GFP_KERNEL);
        if (!sqd)
                return ERR_PTR(-ENOMEM);
 
+       atomic_set(&sqd->park_pending, 0);
        refcount_set(&sqd->refs, 1);
        INIT_LIST_HEAD(&sqd->ctx_list);
-       INIT_LIST_HEAD(&sqd->ctx_new_list);
-       mutex_init(&sqd->ctx_lock);
        mutex_init(&sqd->lock);
        init_waitqueue_head(&sqd->wait);
-       init_completion(&sqd->startup);
-       init_completion(&sqd->parked);
        init_completion(&sqd->exited);
        return sqd;
 }
@@ -7802,7 +7864,6 @@ static int io_uring_alloc_task_context(struct task_struct *task,
        init_waitqueue_head(&tctx->wait);
        tctx->last = NULL;
        atomic_set(&tctx->in_idle, 0);
-       tctx->sqpoll = false;
        task->io_uring = tctx;
        spin_lock_init(&tctx->task_lock);
        INIT_WQ_LIST(&tctx->task_list);
@@ -7823,26 +7884,6 @@ void __io_uring_free(struct task_struct *tsk)
        tsk->io_uring = NULL;
 }
 
-static int io_sq_thread_fork(struct io_sq_data *sqd, struct io_ring_ctx *ctx)
-{
-       struct task_struct *tsk;
-       int ret;
-
-       clear_bit(IO_SQ_THREAD_SHOULD_STOP, &sqd->state);
-       reinit_completion(&sqd->parked);
-       ctx->sqo_exec = 0;
-       sqd->task_pid = current->pid;
-       tsk = create_io_thread(io_sq_thread, sqd, NUMA_NO_NODE);
-       if (IS_ERR(tsk))
-               return PTR_ERR(tsk);
-       ret = io_uring_alloc_task_context(tsk, ctx);
-       if (ret)
-               set_bit(IO_SQ_THREAD_SHOULD_STOP, &sqd->state);
-       sqd->thread = tsk;
-       wake_up_new_task(tsk);
-       return ret;
-}
-
 static int io_sq_offload_create(struct io_ring_ctx *ctx,
                                struct io_uring_params *p)
 {
@@ -7865,29 +7906,36 @@ static int io_sq_offload_create(struct io_ring_ctx *ctx,
        if (ctx->flags & IORING_SETUP_SQPOLL) {
                struct task_struct *tsk;
                struct io_sq_data *sqd;
+               bool attached;
 
                ret = -EPERM;
                if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_NICE))
                        goto err;
 
-               sqd = io_get_sq_data(p);
+               sqd = io_get_sq_data(p, &attached);
                if (IS_ERR(sqd)) {
                        ret = PTR_ERR(sqd);
                        goto err;
                }
 
+               ctx->sq_creds = get_current_cred();
                ctx->sq_data = sqd;
-               io_sq_thread_park(sqd);
-               mutex_lock(&sqd->ctx_lock);
-               list_add(&ctx->sqd_list, &sqd->ctx_new_list);
-               mutex_unlock(&sqd->ctx_lock);
-               io_sq_thread_unpark(sqd);
-
                ctx->sq_thread_idle = msecs_to_jiffies(p->sq_thread_idle);
                if (!ctx->sq_thread_idle)
                        ctx->sq_thread_idle = HZ;
 
-               if (sqd->thread)
+               ret = 0;
+               io_sq_thread_park(sqd);
+               list_add(&ctx->sqd_list, &sqd->ctx_list);
+               io_sqd_update_thread_idle(sqd);
+               /* don't attach to a dying SQPOLL thread, would be racy */
+               if (attached && !sqd->thread)
+                       ret = -ENXIO;
+               io_sq_thread_unpark(sqd);
+
+               if (ret < 0)
+                       goto err;
+               if (attached)
                        return 0;
 
                if (p->flags & IORING_SETUP_SQ_AFF) {
@@ -7895,9 +7943,9 @@ static int io_sq_offload_create(struct io_ring_ctx *ctx,
 
                        ret = -EINVAL;
                        if (cpu >= nr_cpu_ids)
-                               goto err;
+                               goto err_sqpoll;
                        if (!cpu_online(cpu))
-                               goto err;
+                               goto err_sqpoll;
 
                        sqd->sq_cpu = cpu;
                } else {
@@ -7905,15 +7953,15 @@ static int io_sq_offload_create(struct io_ring_ctx *ctx,
                }
 
                sqd->task_pid = current->pid;
+               sqd->task_tgid = current->tgid;
                tsk = create_io_thread(io_sq_thread, sqd, NUMA_NO_NODE);
                if (IS_ERR(tsk)) {
                        ret = PTR_ERR(tsk);
-                       goto err;
+                       goto err_sqpoll;
                }
-               ret = io_uring_alloc_task_context(tsk, ctx);
-               if (ret)
-                       set_bit(IO_SQ_THREAD_SHOULD_STOP, &sqd->state);
+
                sqd->thread = tsk;
+               ret = io_uring_alloc_task_context(tsk, ctx);
                wake_up_new_task(tsk);
                if (ret)
                        goto err;
@@ -7927,15 +7975,9 @@ static int io_sq_offload_create(struct io_ring_ctx *ctx,
 err:
        io_sq_thread_finish(ctx);
        return ret;
-}
-
-static void io_sq_offload_start(struct io_ring_ctx *ctx)
-{
-       struct io_sq_data *sqd = ctx->sq_data;
-
-       ctx->flags &= ~IORING_SETUP_R_DISABLED;
-       if (ctx->flags & IORING_SETUP_SQPOLL)
-               complete(&sqd->startup);
+err_sqpoll:
+       complete(&ctx->sq_data->exited);
+       goto err;
 }
 
 static inline void __io_unaccount_mem(struct user_struct *user,
@@ -8345,19 +8387,13 @@ static int io_eventfd_unregister(struct io_ring_ctx *ctx)
        return -ENXIO;
 }
 
-static int __io_destroy_buffers(int id, void *p, void *data)
-{
-       struct io_ring_ctx *ctx = data;
-       struct io_buffer *buf = p;
-
-       __io_remove_buffers(ctx, buf, id, -1U);
-       return 0;
-}
-
 static void io_destroy_buffers(struct io_ring_ctx *ctx)
 {
-       idr_for_each(&ctx->io_buffer_idr, __io_destroy_buffers, ctx);
-       idr_destroy(&ctx->io_buffer_idr);
+       struct io_buffer *buf;
+       unsigned long index;
+
+       xa_for_each(&ctx->io_buffers, index, buf)
+               __io_remove_buffers(ctx, buf, index, -1U);
 }
 
 static void io_req_cache_free(struct list_head *list, struct task_struct *tsk)
@@ -8399,11 +8435,13 @@ static void io_ring_ctx_free(struct io_ring_ctx *ctx)
 {
        /*
         * Some may use context even when all refs and requests have been put,
-        * and they are free to do so while still holding uring_lock, see
-        * __io_req_task_submit(). Wait for them to finish.
+        * and they are free to do so while still holding uring_lock or
+        * completion_lock, see __io_req_task_submit(). Wait for them to finish.
         */
        mutex_lock(&ctx->uring_lock);
        mutex_unlock(&ctx->uring_lock);
+       spin_lock_irq(&ctx->completion_lock);
+       spin_unlock_irq(&ctx->completion_lock);
 
        io_sq_thread_finish(ctx);
        io_sqe_buffers_unregister(ctx);
@@ -8418,7 +8456,6 @@ static void io_ring_ctx_free(struct io_ring_ctx *ctx)
        mutex_unlock(&ctx->uring_lock);
        io_eventfd_unregister(ctx);
        io_destroy_buffers(ctx);
-       idr_destroy(&ctx->personality_idr);
 
 #if defined(CONFIG_UNIX)
        if (ctx->ring_sock) {
@@ -8483,7 +8520,7 @@ static int io_unregister_personality(struct io_ring_ctx *ctx, unsigned id)
 {
        const struct cred *creds;
 
-       creds = idr_remove(&ctx->personality_idr, id);
+       creds = xa_erase(&ctx->personalities, id);
        if (creds) {
                put_cred(creds);
                return 0;
@@ -8492,40 +8529,39 @@ static int io_unregister_personality(struct io_ring_ctx *ctx, unsigned id)
        return -EINVAL;
 }
 
-static int io_remove_personalities(int id, void *p, void *data)
+static inline bool io_run_ctx_fallback(struct io_ring_ctx *ctx)
 {
-       struct io_ring_ctx *ctx = data;
-
-       io_unregister_personality(ctx, id);
-       return 0;
+       return io_run_task_work_head(&ctx->exit_task_work);
 }
 
-static bool io_run_ctx_fallback(struct io_ring_ctx *ctx)
-{
-       struct callback_head *work, *next;
-       bool executed = false;
-
-       do {
-               work = xchg(&ctx->exit_task_work, NULL);
-               if (!work)
-                       break;
+struct io_tctx_exit {
+       struct callback_head            task_work;
+       struct completion               completion;
+       struct io_ring_ctx              *ctx;
+};
 
-               do {
-                       next = work->next;
-                       work->func(work);
-                       work = next;
-                       cond_resched();
-               } while (work);
-               executed = true;
-       } while (1);
+static void io_tctx_exit_cb(struct callback_head *cb)
+{
+       struct io_uring_task *tctx = current->io_uring;
+       struct io_tctx_exit *work;
 
-       return executed;
+       work = container_of(cb, struct io_tctx_exit, task_work);
+       /*
+        * When @in_idle, we're in cancellation and it's racy to remove the
+        * node. It'll be removed by the end of cancellation, just ignore it.
+        */
+       if (!atomic_read(&tctx->in_idle))
+               io_uring_del_task_file((unsigned long)work->ctx);
+       complete(&work->completion);
 }
 
 static void io_ring_exit_work(struct work_struct *work)
 {
-       struct io_ring_ctx *ctx = container_of(work, struct io_ring_ctx,
-                                              exit_work);
+       struct io_ring_ctx *ctx = container_of(work, struct io_ring_ctx, exit_work);
+       unsigned long timeout = jiffies + HZ * 60 * 5;
+       struct io_tctx_exit exit;
+       struct io_tctx_node *node;
+       int ret;
 
        /*
         * If we're doing polled IO and end up having requests being
@@ -8535,21 +8571,57 @@ static void io_ring_exit_work(struct work_struct *work)
         */
        do {
                io_uring_try_cancel_requests(ctx, NULL, NULL);
+
+               WARN_ON_ONCE(time_after(jiffies, timeout));
        } while (!wait_for_completion_timeout(&ctx->ref_comp, HZ/20));
+
+       mutex_lock(&ctx->uring_lock);
+       while (!list_empty(&ctx->tctx_list)) {
+               WARN_ON_ONCE(time_after(jiffies, timeout));
+
+               node = list_first_entry(&ctx->tctx_list, struct io_tctx_node,
+                                       ctx_node);
+               exit.ctx = ctx;
+               init_completion(&exit.completion);
+               init_task_work(&exit.task_work, io_tctx_exit_cb);
+               ret = task_work_add(node->task, &exit.task_work, TWA_SIGNAL);
+               if (WARN_ON_ONCE(ret))
+                       continue;
+               wake_up_process(node->task);
+
+               mutex_unlock(&ctx->uring_lock);
+               wait_for_completion(&exit.completion);
+               cond_resched();
+               mutex_lock(&ctx->uring_lock);
+       }
+       mutex_unlock(&ctx->uring_lock);
+
        io_ring_ctx_free(ctx);
 }
 
 static void io_ring_ctx_wait_and_kill(struct io_ring_ctx *ctx)
 {
+       unsigned long index;
+       struct creds *creds;
+
        mutex_lock(&ctx->uring_lock);
        percpu_ref_kill(&ctx->refs);
        /* if force is set, the ring is going away. always drop after that */
        ctx->cq_overflow_flushed = 1;
        if (ctx->rings)
                __io_cqring_overflow_flush(ctx, true, NULL, NULL);
-       idr_for_each(&ctx->personality_idr, io_remove_personalities, ctx);
+       xa_for_each(&ctx->personalities, index, creds)
+               io_unregister_personality(ctx, index);
        mutex_unlock(&ctx->uring_lock);
 
+       /* prevent SQPOLL from submitting new requests */
+       if (ctx->sq_data) {
+               io_sq_thread_park(ctx->sq_data);
+               list_del_init(&ctx->sqd_list);
+               io_sqd_update_thread_idle(ctx->sq_data);
+               io_sq_thread_unpark(ctx->sq_data);
+       }
+
        io_kill_timeouts(ctx, NULL, NULL);
        io_poll_remove_all(ctx, NULL, NULL);
 
@@ -8600,11 +8672,11 @@ static bool io_cancel_task_cb(struct io_wq_work *work, void *data)
        return ret;
 }
 
-static void io_cancel_defer_files(struct io_ring_ctx *ctx,
+static bool io_cancel_defer_files(struct io_ring_ctx *ctx,
                                  struct task_struct *task,
                                  struct files_struct *files)
 {
-       struct io_defer_entry *de = NULL;
+       struct io_defer_entry *de;
        LIST_HEAD(list);
 
        spin_lock_irq(&ctx->completion_lock);
@@ -8615,6 +8687,8 @@ static void io_cancel_defer_files(struct io_ring_ctx *ctx,
                }
        }
        spin_unlock_irq(&ctx->completion_lock);
+       if (list_empty(&list))
+               return false;
 
        while (!list_empty(&list)) {
                de = list_first_entry(&list, struct io_defer_entry, list);
@@ -8624,6 +8698,38 @@ static void io_cancel_defer_files(struct io_ring_ctx *ctx,
                io_req_complete(de->req, -ECANCELED);
                kfree(de);
        }
+       return true;
+}
+
+static bool io_cancel_ctx_cb(struct io_wq_work *work, void *data)
+{
+       struct io_kiocb *req = container_of(work, struct io_kiocb, work);
+
+       return req->ctx == data;
+}
+
+static bool io_uring_try_cancel_iowq(struct io_ring_ctx *ctx)
+{
+       struct io_tctx_node *node;
+       enum io_wq_cancel cret;
+       bool ret = false;
+
+       mutex_lock(&ctx->uring_lock);
+       list_for_each_entry(node, &ctx->tctx_list, ctx_node) {
+               struct io_uring_task *tctx = node->task->io_uring;
+
+               /*
+                * io_wq will stay alive while we hold uring_lock, because it's
+                * killed after ctx nodes, which requires to take the lock.
+                */
+               if (!tctx || !tctx->io_wq)
+                       continue;
+               cret = io_wq_cancel_cb(tctx->io_wq, io_cancel_ctx_cb, ctx, true);
+               ret |= (cret != IO_WQ_CANCEL_NOTFOUND);
+       }
+       mutex_unlock(&ctx->uring_lock);
+
+       return ret;
 }
 
 static void io_uring_try_cancel_requests(struct io_ring_ctx *ctx,
@@ -8631,27 +8737,34 @@ static void io_uring_try_cancel_requests(struct io_ring_ctx *ctx,
                                         struct files_struct *files)
 {
        struct io_task_cancel cancel = { .task = task, .files = files, };
-       struct task_struct *tctx_task = task ?: current;
-       struct io_uring_task *tctx = tctx_task->io_uring;
+       struct io_uring_task *tctx = task ? task->io_uring : NULL;
 
        while (1) {
                enum io_wq_cancel cret;
                bool ret = false;
 
-               if (tctx && tctx->io_wq) {
+               if (!task) {
+                       ret |= io_uring_try_cancel_iowq(ctx);
+               } else if (tctx && tctx->io_wq) {
+                       /*
+                        * Cancels requests of all rings, not only @ctx, but
+                        * it's fine as the task is in exit/exec.
+                        */
                        cret = io_wq_cancel_cb(tctx->io_wq, io_cancel_task_cb,
                                               &cancel, true);
                        ret |= (cret != IO_WQ_CANCEL_NOTFOUND);
                }
 
                /* SQPOLL thread does its own polling */
-               if (!(ctx->flags & IORING_SETUP_SQPOLL) && !files) {
+               if ((!(ctx->flags & IORING_SETUP_SQPOLL) && !files) ||
+                   (ctx->sq_data && ctx->sq_data->thread == current)) {
                        while (!list_empty_careful(&ctx->iopoll_list)) {
                                io_iopoll_try_reap_events(ctx);
                                ret = true;
                        }
                }
 
+               ret |= io_cancel_defer_files(ctx, task, files);
                ret |= io_poll_remove_all(ctx, task, files);
                ret |= io_kill_timeouts(ctx, task, files);
                ret |= io_run_task_work();
@@ -8691,58 +8804,21 @@ static void io_uring_cancel_files(struct io_ring_ctx *ctx,
 
                io_uring_try_cancel_requests(ctx, task, files);
 
-               if (ctx->sq_data)
-                       io_sq_thread_unpark(ctx->sq_data);
                prepare_to_wait(&task->io_uring->wait, &wait,
                                TASK_UNINTERRUPTIBLE);
                if (inflight == io_uring_count_inflight(ctx, task, files))
                        schedule();
                finish_wait(&task->io_uring->wait, &wait);
-               if (ctx->sq_data)
-                       io_sq_thread_park(ctx->sq_data);
-       }
-}
-
-/*
- * We need to iteratively cancel requests, in case a request has dependent
- * hard links. These persist even for failure of cancelations, hence keep
- * looping until none are found.
- */
-static void io_uring_cancel_task_requests(struct io_ring_ctx *ctx,
-                                         struct files_struct *files)
-{
-       struct task_struct *task = current;
-
-       if ((ctx->flags & IORING_SETUP_SQPOLL) && ctx->sq_data) {
-               /* never started, nothing to cancel */
-               if (ctx->flags & IORING_SETUP_R_DISABLED) {
-                       io_sq_offload_start(ctx);
-                       return;
-               }
-               io_sq_thread_park(ctx->sq_data);
-               task = ctx->sq_data->thread;
-               if (task)
-                       atomic_inc(&task->io_uring->in_idle);
        }
-
-       io_cancel_defer_files(ctx, task, files);
-
-       io_uring_cancel_files(ctx, task, files);
-       if (!files)
-               io_uring_try_cancel_requests(ctx, task, NULL);
-
-       if (task)
-               atomic_dec(&task->io_uring->in_idle);
-       if (ctx->sq_data)
-               io_sq_thread_unpark(ctx->sq_data);
 }
 
 /*
  * Note that this task has used io_uring. We use it for cancelation purposes.
  */
-static int io_uring_add_task_file(struct io_ring_ctx *ctx, struct file *file)
+static int io_uring_add_task_file(struct io_ring_ctx *ctx)
 {
        struct io_uring_task *tctx = current->io_uring;
+       struct io_tctx_node *node;
        int ret;
 
        if (unlikely(!tctx)) {
@@ -8751,102 +8827,151 @@ static int io_uring_add_task_file(struct io_ring_ctx *ctx, struct file *file)
                        return ret;
                tctx = current->io_uring;
        }
-       if (tctx->last != file) {
-               void *old = xa_load(&tctx->xa, (unsigned long)file);
+       if (tctx->last != ctx) {
+               void *old = xa_load(&tctx->xa, (unsigned long)ctx);
 
                if (!old) {
-                       get_file(file);
-                       ret = xa_err(xa_store(&tctx->xa, (unsigned long)file,
-                                               file, GFP_KERNEL));
+                       node = kmalloc(sizeof(*node), GFP_KERNEL);
+                       if (!node)
+                               return -ENOMEM;
+                       node->ctx = ctx;
+                       node->task = current;
+
+                       ret = xa_err(xa_store(&tctx->xa, (unsigned long)ctx,
+                                               node, GFP_KERNEL));
                        if (ret) {
-                               fput(file);
+                               kfree(node);
                                return ret;
                        }
+
+                       mutex_lock(&ctx->uring_lock);
+                       list_add(&node->ctx_node, &ctx->tctx_list);
+                       mutex_unlock(&ctx->uring_lock);
                }
-               tctx->last = file;
+               tctx->last = ctx;
        }
-
-       /*
-        * This is race safe in that the task itself is doing this, hence it
-        * cannot be going through the exit/cancel paths at the same time.
-        * This cannot be modified while exit/cancel is running.
-        */
-       if (!tctx->sqpoll && (ctx->flags & IORING_SETUP_SQPOLL))
-               tctx->sqpoll = true;
-
        return 0;
 }
 
 /*
  * Remove this io_uring_file -> task mapping.
  */
-static void io_uring_del_task_file(struct file *file)
+static void io_uring_del_task_file(unsigned long index)
 {
        struct io_uring_task *tctx = current->io_uring;
+       struct io_tctx_node *node;
+
+       if (!tctx)
+               return;
+       node = xa_erase(&tctx->xa, index);
+       if (!node)
+               return;
+
+       WARN_ON_ONCE(current != node->task);
+       WARN_ON_ONCE(list_empty(&node->ctx_node));
+
+       mutex_lock(&node->ctx->uring_lock);
+       list_del(&node->ctx_node);
+       mutex_unlock(&node->ctx->uring_lock);
 
-       if (tctx->last == file)
+       if (tctx->last == node->ctx)
                tctx->last = NULL;
-       file = xa_erase(&tctx->xa, (unsigned long)file);
-       if (file)
-               fput(file);
+       kfree(node);
 }
 
 static void io_uring_clean_tctx(struct io_uring_task *tctx)
 {
-       struct file *file;
+       struct io_tctx_node *node;
        unsigned long index;
 
-       xa_for_each(&tctx->xa, index, file)
-               io_uring_del_task_file(file);
+       xa_for_each(&tctx->xa, index, node)
+               io_uring_del_task_file(index);
        if (tctx->io_wq) {
                io_wq_put_and_exit(tctx->io_wq);
                tctx->io_wq = NULL;
        }
 }
 
+static s64 tctx_inflight(struct io_uring_task *tctx)
+{
+       return percpu_counter_sum(&tctx->inflight);
+}
+
+static void io_sqpoll_cancel_cb(struct callback_head *cb)
+{
+       struct io_tctx_exit *work = container_of(cb, struct io_tctx_exit, task_work);
+       struct io_ring_ctx *ctx = work->ctx;
+       struct io_sq_data *sqd = ctx->sq_data;
+
+       if (sqd->thread)
+               io_uring_cancel_sqpoll(ctx);
+       complete(&work->completion);
+}
+
+static void io_sqpoll_cancel_sync(struct io_ring_ctx *ctx)
+{
+       struct io_sq_data *sqd = ctx->sq_data;
+       struct io_tctx_exit work = { .ctx = ctx, };
+       struct task_struct *task;
+
+       io_sq_thread_park(sqd);
+       list_del_init(&ctx->sqd_list);
+       io_sqd_update_thread_idle(sqd);
+       task = sqd->thread;
+       if (task) {
+               init_completion(&work.completion);
+               init_task_work(&work.task_work, io_sqpoll_cancel_cb);
+               io_task_work_add_head(&sqd->park_task_work, &work.task_work);
+               wake_up_process(task);
+       }
+       io_sq_thread_unpark(sqd);
+
+       if (task)
+               wait_for_completion(&work.completion);
+}
+
 void __io_uring_files_cancel(struct files_struct *files)
 {
        struct io_uring_task *tctx = current->io_uring;
-       struct file *file;
+       struct io_tctx_node *node;
        unsigned long index;
 
        /* make sure overflow events are dropped */
        atomic_inc(&tctx->in_idle);
-       xa_for_each(&tctx->xa, index, file)
-               io_uring_cancel_task_requests(file->private_data, files);
+       xa_for_each(&tctx->xa, index, node) {
+               struct io_ring_ctx *ctx = node->ctx;
+
+               if (ctx->sq_data) {
+                       io_sqpoll_cancel_sync(ctx);
+                       continue;
+               }
+               io_uring_cancel_files(ctx, current, files);
+               if (!files)
+                       io_uring_try_cancel_requests(ctx, current, NULL);
+       }
        atomic_dec(&tctx->in_idle);
 
        if (files)
                io_uring_clean_tctx(tctx);
 }
 
-static s64 tctx_inflight(struct io_uring_task *tctx)
-{
-       return percpu_counter_sum(&tctx->inflight);
-}
-
+/* should only be called by SQPOLL task */
 static void io_uring_cancel_sqpoll(struct io_ring_ctx *ctx)
 {
        struct io_sq_data *sqd = ctx->sq_data;
-       struct io_uring_task *tctx;
+       struct io_uring_task *tctx = current->io_uring;
        s64 inflight;
        DEFINE_WAIT(wait);
 
-       if (!sqd)
-               return;
-       io_sq_thread_park(sqd);
-       if (!sqd->thread || !sqd->thread->io_uring) {
-               io_sq_thread_unpark(sqd);
-               return;
-       }
-       tctx = ctx->sq_data->thread->io_uring;
+       WARN_ON_ONCE(!sqd || ctx->sq_data->thread != current);
+
        atomic_inc(&tctx->in_idle);
        do {
                /* read completions before cancelations */
                inflight = tctx_inflight(tctx);
                if (!inflight)
                        break;
-               io_uring_cancel_task_requests(ctx, NULL);
+               io_uring_try_cancel_requests(ctx, current, NULL);
 
                prepare_to_wait(&tctx->wait, &wait, TASK_UNINTERRUPTIBLE);
                /*
@@ -8859,7 +8984,6 @@ static void io_uring_cancel_sqpoll(struct io_ring_ctx *ctx)
                finish_wait(&tctx->wait, &wait);
        } while (1);
        atomic_dec(&tctx->in_idle);
-       io_sq_thread_unpark(sqd);
 }
 
 /*
@@ -8874,15 +8998,6 @@ void __io_uring_task_cancel(void)
 
        /* make sure overflow events are dropped */
        atomic_inc(&tctx->in_idle);
-
-       if (tctx->sqpoll) {
-               struct file *file;
-               unsigned long index;
-
-               xa_for_each(&tctx->xa, index, file)
-                       io_uring_cancel_sqpoll(file->private_data);
-       }
-
        do {
                /* read completions before cancelations */
                inflight = tctx_inflight(tctx);
@@ -8981,7 +9096,6 @@ static unsigned long io_uring_nommu_get_unmapped_area(struct file *file,
 
 static int io_sqpoll_wait_sq(struct io_ring_ctx *ctx)
 {
-       int ret = 0;
        DEFINE_WAIT(wait);
 
        do {
@@ -8995,7 +9109,7 @@ static int io_sqpoll_wait_sq(struct io_ring_ctx *ctx)
        } while (!signal_pending(current));
 
        finish_wait(&ctx->sqo_sq_wait, &wait);
-       return ret;
+       return 0;
 }
 
 static int io_get_ext_arg(unsigned flags, const void __user *argp, size_t *argsz,
@@ -9069,13 +9183,10 @@ SYSCALL_DEFINE6(io_uring_enter, unsigned int, fd, u32, to_submit,
        if (ctx->flags & IORING_SETUP_SQPOLL) {
                io_cqring_overflow_flush(ctx, false, NULL, NULL);
 
-               if (unlikely(ctx->sqo_exec)) {
-                       ret = io_sq_thread_fork(ctx->sq_data, ctx);
-                       if (ret)
-                               goto out;
-                       ctx->sqo_exec = 0;
-               }
                ret = -EOWNERDEAD;
+               if (unlikely(ctx->sq_data->thread == NULL)) {
+                       goto out;
+               }
                if (flags & IORING_ENTER_SQ_WAKEUP)
                        wake_up(&ctx->sq_data->wait);
                if (flags & IORING_ENTER_SQ_WAIT) {
@@ -9085,7 +9196,7 @@ SYSCALL_DEFINE6(io_uring_enter, unsigned int, fd, u32, to_submit,
                }
                submitted = to_submit;
        } else if (to_submit) {
-               ret = io_uring_add_task_file(ctx, f.file);
+               ret = io_uring_add_task_file(ctx);
                if (unlikely(ret))
                        goto out;
                mutex_lock(&ctx->uring_lock);
@@ -9127,10 +9238,9 @@ out_fput:
 }
 
 #ifdef CONFIG_PROC_FS
-static int io_uring_show_cred(int id, void *p, void *data)
+static int io_uring_show_cred(struct seq_file *m, unsigned int id,
+               const struct cred *cred)
 {
-       const struct cred *cred = p;
-       struct seq_file *m = data;
        struct user_namespace *uns = seq_user_ns(m);
        struct group_info *gi;
        kernel_cap_t cap;
@@ -9198,9 +9308,13 @@ static void __io_uring_show_fdinfo(struct io_ring_ctx *ctx, struct seq_file *m)
                seq_printf(m, "%5u: 0x%llx/%u\n", i, buf->ubuf,
                                                (unsigned int) buf->len);
        }
-       if (has_lock && !idr_is_empty(&ctx->personality_idr)) {
+       if (has_lock && !xa_empty(&ctx->personalities)) {
+               unsigned long index;
+               const struct cred *cred;
+
                seq_printf(m, "Personalities:\n");
-               idr_for_each(&ctx->personality_idr, io_uring_show_cred, m);
+               xa_for_each(&ctx->personalities, index, cred)
+                       io_uring_show_cred(m, index, cred);
        }
        seq_printf(m, "PollList:\n");
        spin_lock_irq(&ctx->completion_lock);
@@ -9294,7 +9408,7 @@ static int io_uring_install_fd(struct io_ring_ctx *ctx, struct file *file)
        if (fd < 0)
                return fd;
 
-       ret = io_uring_add_task_file(ctx, file);
+       ret = io_uring_add_task_file(ctx);
        if (ret) {
                put_unused_fd(fd);
                return ret;
@@ -9402,9 +9516,6 @@ static int io_uring_create(unsigned entries, struct io_uring_params *p,
        if (ret)
                goto err;
 
-       if (!(p->flags & IORING_SETUP_R_DISABLED))
-               io_sq_offload_start(ctx);
-
        memset(&p->sq_off, 0, sizeof(p->sq_off));
        p->sq_off.head = offsetof(struct io_rings, sq.head);
        p->sq_off.tail = offsetof(struct io_rings, sq.tail);
@@ -9532,14 +9643,16 @@ out:
 static int io_register_personality(struct io_ring_ctx *ctx)
 {
        const struct cred *creds;
+       u32 id;
        int ret;
 
        creds = get_current_cred();
 
-       ret = idr_alloc_cyclic(&ctx->personality_idr, (void *) creds, 1,
-                               USHRT_MAX, GFP_KERNEL);
-       if (ret < 0)
-               put_cred(creds);
+       ret = xa_alloc_cyclic(&ctx->personalities, &id, (void *)creds,
+                       XA_LIMIT(0, USHRT_MAX), &ctx->pers_next, GFP_KERNEL);
+       if (!ret)
+               return id;
+       put_cred(creds);
        return ret;
 }
 
@@ -9621,7 +9734,9 @@ static int io_register_enable_rings(struct io_ring_ctx *ctx)
        if (ctx->restrictions.registered)
                ctx->restricted = 1;
 
-       io_sq_offload_start(ctx);
+       ctx->flags &= ~IORING_SETUP_R_DISABLED;
+       if (ctx->sq_data && wq_has_sleeper(&ctx->sq_data->wait))
+               wake_up(&ctx->sq_data->wait);
        return 0;
 }
 
index 7ffcd7e..414769a 100644 (file)
@@ -1221,7 +1221,7 @@ iomap_alloc_ioend(struct inode *inode, struct iomap_writepage_ctx *wpc,
        struct iomap_ioend *ioend;
        struct bio *bio;
 
-       bio = bio_alloc_bioset(GFP_NOFS, BIO_MAX_PAGES, &iomap_ioend_bioset);
+       bio = bio_alloc_bioset(GFP_NOFS, BIO_MAX_VECS, &iomap_ioend_bioset);
        bio_set_dev(bio, wpc->iomap.bdev);
        bio->bi_iter.bi_sector = sector;
        bio->bi_opf = REQ_OP_WRITE | wbc_to_write_flags(wbc);
@@ -1252,7 +1252,7 @@ iomap_chain_bio(struct bio *prev)
 {
        struct bio *new;
 
-       new = bio_alloc(GFP_NOFS, BIO_MAX_PAGES);
+       new = bio_alloc(GFP_NOFS, BIO_MAX_VECS);
        bio_copy_dev(new, prev);/* also copies over blkcg information */
        new->bi_iter.bi_sector = bio_end_sector(prev);
        new->bi_opf = prev->bi_opf;
index e2c4991..bdd0d89 100644 (file)
@@ -296,7 +296,7 @@ iomap_dio_bio_actor(struct inode *inode, loff_t pos, loff_t length,
         */
        bio_opf = iomap_dio_bio_opflags(dio, iomap, use_fua);
 
-       nr_pages = bio_iov_vecs_to_alloc(dio->submit.iter, BIO_MAX_PAGES);
+       nr_pages = bio_iov_vecs_to_alloc(dio->submit.iter, BIO_MAX_VECS);
        do {
                size_t n;
                if (dio->error) {
@@ -338,7 +338,7 @@ iomap_dio_bio_actor(struct inode *inode, loff_t pos, loff_t length,
                copied += n;
 
                nr_pages = bio_iov_vecs_to_alloc(dio->submit.iter,
-                                                BIO_MAX_PAGES);
+                                                BIO_MAX_VECS);
                iomap_dio_submit_bio(dio, iomap, bio, pos);
                pos += n;
        } while (nr_pages);
index a648dbf..a5e478d 100644 (file)
@@ -170,6 +170,16 @@ int iomap_swapfile_activate(struct swap_info_struct *sis,
                        return ret;
        }
 
+       /*
+        * If this swapfile doesn't contain even a single page-aligned
+        * contiguous range of blocks, reject this useless swapfile to
+        * prevent confusion later on.
+        */
+       if (isi.nr_pages == 0) {
+               pr_warn("swapon: Cannot find a single usable page in file.\n");
+               return -EINVAL;
+       }
+
        *pagespan = 1 + isi.highest_ppage - isi.lowest_ppage;
        sis->max = isi.nr_pages;
        sis->pages = isi.nr_pages - 1;
index 99ca97e..6125d2d 100644 (file)
@@ -1808,9 +1808,6 @@ check_conflicting_open(struct file *filp, const long arg, int flags)
 
        if (flags & FL_LAYOUT)
                return 0;
-       if (flags & FL_DELEG)
-               /* We leave these checks to the caller. */
-               return 0;
 
        if (arg == F_RDLCK)
                return inode_is_open_for_write(inode) ? -EAGAIN : 0;
index 961234d..334e7d0 100644 (file)
@@ -616,7 +616,7 @@ alloc_new:
                                goto out;
                }
                bio = mpage_alloc(bdev, blocks[0] << (blkbits - 9),
-                               BIO_MAX_PAGES, GFP_NOFS|__GFP_HIGH);
+                               BIO_MAX_VECS, GFP_NOFS|__GFP_HIGH);
                if (bio == NULL)
                        goto confused;
 
index e2a488d..14a7222 100644 (file)
@@ -127,7 +127,7 @@ config PNFS_BLOCK
 config PNFS_FLEXFILE_LAYOUT
        tristate
        depends on NFS_V4_1 && NFS_V3
-       default m
+       default NFS_V4
 
 config NFS_V4_1_IMPLEMENTATION_ID_DOMAIN
        string "NFSv4.1 Implementation ID Domain"
index 19a9f43..fc4f490 100644 (file)
@@ -81,8 +81,9 @@ static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct inode *dir
                spin_lock(&dir->i_lock);
                if (list_empty(&nfsi->open_files) &&
                    (nfsi->cache_validity & NFS_INO_DATA_INVAL_DEFER))
-                       nfsi->cache_validity |= NFS_INO_INVALID_DATA |
-                               NFS_INO_REVAL_FORCED;
+                       nfs_set_cache_invalid(dir,
+                                             NFS_INO_INVALID_DATA |
+                                                     NFS_INO_REVAL_FORCED);
                list_add(&ctx->list, &nfsi->open_files);
                spin_unlock(&dir->i_lock);
                return ctx;
@@ -1401,6 +1402,13 @@ out_force:
        goto out;
 }
 
+static void nfs_mark_dir_for_revalidate(struct inode *inode)
+{
+       spin_lock(&inode->i_lock);
+       nfs_set_cache_invalid(inode, NFS_INO_REVAL_PAGECACHE);
+       spin_unlock(&inode->i_lock);
+}
+
 /*
  * We judge how long we want to trust negative
  * dentries by looking at the parent inode mtime.
@@ -1435,19 +1443,14 @@ nfs_lookup_revalidate_done(struct inode *dir, struct dentry *dentry,
                        __func__, dentry);
                return 1;
        case 0:
-               nfs_mark_for_revalidate(dir);
-               if (inode && S_ISDIR(inode->i_mode)) {
-                       /* Purge readdir caches. */
-                       nfs_zap_caches(inode);
-                       /*
-                        * We can't d_drop the root of a disconnected tree:
-                        * its d_hash is on the s_anon list and d_drop() would hide
-                        * it from shrink_dcache_for_unmount(), leading to busy
-                        * inodes on unmount and further oopses.
-                        */
-                       if (IS_ROOT(dentry))
-                               return 1;
-               }
+               /*
+                * We can't d_drop the root of a disconnected tree:
+                * its d_hash is on the s_anon list and d_drop() would hide
+                * it from shrink_dcache_for_unmount(), leading to busy
+                * inodes on unmount and further oopses.
+                */
+               if (inode && IS_ROOT(dentry))
+                       return 1;
                dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is invalid\n",
                                __func__, dentry);
                return 0;
@@ -1525,6 +1528,13 @@ out:
        nfs_free_fattr(fattr);
        nfs_free_fhandle(fhandle);
        nfs4_label_free(label);
+
+       /*
+        * If the lookup failed despite the dentry change attribute being
+        * a match, then we should revalidate the directory cache.
+        */
+       if (!ret && nfs_verify_change_attribute(dir, dentry->d_time))
+               nfs_mark_dir_for_revalidate(dir);
        return nfs_lookup_revalidate_done(dir, dentry, inode, ret);
 }
 
@@ -1567,7 +1577,7 @@ nfs_do_lookup_revalidate(struct inode *dir, struct dentry *dentry,
                error = nfs_lookup_verify_inode(inode, flags);
                if (error) {
                        if (error == -ESTALE)
-                               nfs_zap_caches(dir);
+                               nfs_mark_dir_for_revalidate(dir);
                        goto out_bad;
                }
                nfs_advise_use_readdirplus(dir);
@@ -1691,10 +1701,9 @@ static void nfs_drop_nlink(struct inode *inode)
        if (inode->i_nlink > 0)
                drop_nlink(inode);
        NFS_I(inode)->attr_gencount = nfs_inc_attr_generation_counter();
-       NFS_I(inode)->cache_validity |= NFS_INO_INVALID_CHANGE
-               | NFS_INO_INVALID_CTIME
-               | NFS_INO_INVALID_OTHER
-               | NFS_INO_REVAL_FORCED;
+       nfs_set_cache_invalid(
+               inode, NFS_INO_INVALID_CHANGE | NFS_INO_INVALID_CTIME |
+                              NFS_INO_INVALID_OTHER | NFS_INO_REVAL_FORCED);
        spin_unlock(&inode->i_lock);
 }
 
@@ -1706,7 +1715,7 @@ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode)
 {
        if (S_ISDIR(inode->i_mode))
                /* drop any readdir cache as it could easily be old */
-               NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA;
+               nfs_set_cache_invalid(inode, NFS_INO_INVALID_DATA);
 
        if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
                nfs_complete_unlink(dentry, inode);
@@ -2064,7 +2073,6 @@ out:
        dput(parent);
        return d;
 out_error:
-       nfs_mark_for_revalidate(dir);
        d = ERR_PTR(error);
        goto out;
 }
@@ -2473,9 +2481,9 @@ int nfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
        if (error == 0) {
                spin_lock(&old_inode->i_lock);
                NFS_I(old_inode)->attr_gencount = nfs_inc_attr_generation_counter();
-               NFS_I(old_inode)->cache_validity |= NFS_INO_INVALID_CHANGE
-                       | NFS_INO_INVALID_CTIME
-                       | NFS_INO_REVAL_FORCED;
+               nfs_set_cache_invalid(old_inode, NFS_INO_INVALID_CHANGE |
+                                                        NFS_INO_INVALID_CTIME |
+                                                        NFS_INO_REVAL_FORCED);
                spin_unlock(&old_inode->i_lock);
        }
 out:
index 749bbea..a7fb076 100644 (file)
@@ -207,7 +207,7 @@ static bool nfs_has_xattr_cache(const struct nfs_inode *nfsi)
 }
 #endif
 
-static void nfs_set_cache_invalid(struct inode *inode, unsigned long flags)
+void nfs_set_cache_invalid(struct inode *inode, unsigned long flags)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
        bool have_delegation = NFS_PROTO(inode)->have_delegation(inode, FMODE_READ);
@@ -229,6 +229,7 @@ static void nfs_set_cache_invalid(struct inode *inode, unsigned long flags)
        if (flags & NFS_INO_INVALID_DATA)
                nfs_fscache_invalidate(inode);
 }
+EXPORT_SYMBOL_GPL(nfs_set_cache_invalid);
 
 /*
  * Invalidate the local caches
@@ -1067,8 +1068,8 @@ void nfs_inode_attach_open_context(struct nfs_open_context *ctx)
        spin_lock(&inode->i_lock);
        if (list_empty(&nfsi->open_files) &&
            (nfsi->cache_validity & NFS_INO_DATA_INVAL_DEFER))
-               nfsi->cache_validity |= NFS_INO_INVALID_DATA |
-                       NFS_INO_REVAL_FORCED;
+               nfs_set_cache_invalid(inode, NFS_INO_INVALID_DATA |
+                                                    NFS_INO_REVAL_FORCED);
        list_add_tail_rcu(&ctx->list, &nfsi->open_files);
        spin_unlock(&inode->i_lock);
 }
index 25fb43b..7b644d6 100644 (file)
@@ -411,7 +411,8 @@ extern int nfs_write_inode(struct inode *, struct writeback_control *);
 extern int nfs_drop_inode(struct inode *);
 extern void nfs_clear_inode(struct inode *);
 extern void nfs_evict_inode(struct inode *);
-void nfs_zap_acl_cache(struct inode *inode);
+extern void nfs_zap_acl_cache(struct inode *inode);
+extern void nfs_set_cache_invalid(struct inode *inode, unsigned long flags);
 extern bool nfs_check_cache_invalid(struct inode *, unsigned long);
 extern int nfs_wait_bit_killable(struct wait_bit_key *key, int mode);
 extern int nfs_wait_atomic_killable(atomic_t *p, unsigned int mode);
index ca10072..ed1c837 100644 (file)
@@ -36,6 +36,7 @@
 #define NFS3_pagepad_sz                (1) /* Page padding */
 #define NFS3_fhandle_sz                (1+16)
 #define NFS3_fh_sz             (NFS3_fhandle_sz)       /* shorthand */
+#define NFS3_post_op_fh_sz     (1+NFS3_fh_sz)
 #define NFS3_sattr_sz          (15)
 #define NFS3_filename_sz       (1+(NFS3_MAXNAMLEN>>2))
 #define NFS3_path_sz           (1+(NFS3_MAXPATHLEN>>2))
@@ -73,7 +74,7 @@
 #define NFS3_readlinkres_sz    (1+NFS3_post_op_attr_sz+1+NFS3_pagepad_sz)
 #define NFS3_readres_sz                (1+NFS3_post_op_attr_sz+3+NFS3_pagepad_sz)
 #define NFS3_writeres_sz       (1+NFS3_wcc_data_sz+4)
-#define NFS3_createres_sz      (1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
+#define NFS3_createres_sz      (1+NFS3_post_op_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
 #define NFS3_renameres_sz      (1+(2 * NFS3_wcc_data_sz))
 #define NFS3_linkres_sz                (1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
 #define NFS3_readdirres_sz     (1+NFS3_post_op_attr_sz+2+NFS3_pagepad_sz)
index f3fd935..094024b 100644 (file)
@@ -357,13 +357,15 @@ static ssize_t _nfs42_proc_copy(struct file *src,
        truncate_pagecache_range(dst_inode, pos_dst,
                                 pos_dst + res->write_res.count);
        spin_lock(&dst_inode->i_lock);
-       NFS_I(dst_inode)->cache_validity |= (NFS_INO_REVAL_PAGECACHE |
-                       NFS_INO_REVAL_FORCED | NFS_INO_INVALID_SIZE |
-                       NFS_INO_INVALID_ATTR | NFS_INO_INVALID_DATA);
+       nfs_set_cache_invalid(
+               dst_inode, NFS_INO_REVAL_PAGECACHE | NFS_INO_REVAL_FORCED |
+                                  NFS_INO_INVALID_SIZE | NFS_INO_INVALID_ATTR |
+                                  NFS_INO_INVALID_DATA);
        spin_unlock(&dst_inode->i_lock);
        spin_lock(&src_inode->i_lock);
-       NFS_I(src_inode)->cache_validity |= (NFS_INO_REVAL_PAGECACHE |
-                       NFS_INO_REVAL_FORCED | NFS_INO_INVALID_ATIME);
+       nfs_set_cache_invalid(src_inode, NFS_INO_REVAL_PAGECACHE |
+                                                NFS_INO_REVAL_FORCED |
+                                                NFS_INO_INVALID_ATIME);
        spin_unlock(&src_inode->i_lock);
        status = res->write_res.count;
 out:
index 74bc512..c65c4b4 100644 (file)
@@ -1169,14 +1169,14 @@ int nfs4_call_sync(struct rpc_clnt *clnt,
 static void
 nfs4_inc_nlink_locked(struct inode *inode)
 {
-       NFS_I(inode)->cache_validity |= NFS_INO_INVALID_OTHER;
+       nfs_set_cache_invalid(inode, NFS_INO_INVALID_OTHER);
        inc_nlink(inode);
 }
 
 static void
 nfs4_dec_nlink_locked(struct inode *inode)
 {
-       NFS_I(inode)->cache_validity |= NFS_INO_INVALID_OTHER;
+       nfs_set_cache_invalid(inode, NFS_INO_INVALID_OTHER);
        drop_nlink(inode);
 }
 
@@ -1187,35 +1187,31 @@ nfs4_update_changeattr_locked(struct inode *inode,
 {
        struct nfs_inode *nfsi = NFS_I(inode);
 
-       nfsi->cache_validity |= NFS_INO_INVALID_CTIME
-               | NFS_INO_INVALID_MTIME
-               | cache_validity;
+       cache_validity |= NFS_INO_INVALID_CTIME | NFS_INO_INVALID_MTIME;
 
        if (cinfo->atomic && cinfo->before == inode_peek_iversion_raw(inode)) {
                nfsi->cache_validity &= ~NFS_INO_REVAL_PAGECACHE;
                nfsi->attrtimeo_timestamp = jiffies;
        } else {
                if (S_ISDIR(inode->i_mode)) {
-                       nfsi->cache_validity |= NFS_INO_INVALID_DATA;
+                       cache_validity |= NFS_INO_INVALID_DATA;
                        nfs_force_lookup_revalidate(inode);
                } else {
                        if (!NFS_PROTO(inode)->have_delegation(inode,
                                                               FMODE_READ))
-                               nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE;
+                               cache_validity |= NFS_INO_REVAL_PAGECACHE;
                }
 
                if (cinfo->before != inode_peek_iversion_raw(inode))
-                       nfsi->cache_validity |= NFS_INO_INVALID_ACCESS |
-                                               NFS_INO_INVALID_ACL |
-                                               NFS_INO_INVALID_XATTR;
+                       cache_validity |= NFS_INO_INVALID_ACCESS |
+                                         NFS_INO_INVALID_ACL |
+                                         NFS_INO_INVALID_XATTR;
        }
        inode_set_iversion_raw(inode, cinfo->after);
        nfsi->read_cache_jiffies = timestamp;
        nfsi->attr_gencount = nfs_inc_attr_generation_counter();
+       nfs_set_cache_invalid(inode, cache_validity);
        nfsi->cache_validity &= ~NFS_INO_INVALID_CHANGE;
-
-       if (nfsi->cache_validity & NFS_INO_INVALID_DATA)
-               nfs_fscache_invalidate(inode);
 }
 
 void
@@ -5893,6 +5889,9 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl
        unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE);
        int ret, i;
 
+       /* You can't remove system.nfs4_acl: */
+       if (buflen == 0)
+               return -EINVAL;
        if (!nfs4_server_supports_acls(server))
                return -EOPNOTSUPP;
        if (npages > ARRAY_SIZE(pages))
@@ -5915,9 +5914,9 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl
         * so mark the attribute cache invalid.
         */
        spin_lock(&inode->i_lock);
-       NFS_I(inode)->cache_validity |= NFS_INO_INVALID_CHANGE
-               | NFS_INO_INVALID_CTIME
-               | NFS_INO_REVAL_FORCED;
+       nfs_set_cache_invalid(inode, NFS_INO_INVALID_CHANGE |
+                                            NFS_INO_INVALID_CTIME |
+                                            NFS_INO_REVAL_FORCED);
        spin_unlock(&inode->i_lock);
        nfs_access_zap_cache(inode);
        nfs_zap_acl_cache(inode);
@@ -5969,7 +5968,7 @@ static int _nfs4_get_security_label(struct inode *inode, void *buf,
                return ret;
        if (!(fattr.valid & NFS_ATTR_FATTR_V4_SECURITY_LABEL))
                return -ENOENT;
-       return 0;
+       return label.len;
 }
 
 static int nfs4_get_security_label(struct inode *inode, void *buf,
index b27ebdc..5fa11e1 100644 (file)
@@ -500,9 +500,9 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry)
                nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
                spin_lock(&inode->i_lock);
                NFS_I(inode)->attr_gencount = nfs_inc_attr_generation_counter();
-               NFS_I(inode)->cache_validity |= NFS_INO_INVALID_CHANGE
-                       | NFS_INO_INVALID_CTIME
-                       | NFS_INO_REVAL_FORCED;
+               nfs_set_cache_invalid(inode, NFS_INO_INVALID_CHANGE |
+                                                    NFS_INO_INVALID_CTIME |
+                                                    NFS_INO_REVAL_FORCED);
                spin_unlock(&inode->i_lock);
                d_move(dentry, sdentry);
                break;
index 82bdcb9..f05a903 100644 (file)
@@ -303,9 +303,9 @@ static void nfs_set_pageerror(struct address_space *mapping)
        nfs_zap_mapping(mapping->host, mapping);
        /* Force file size revalidation */
        spin_lock(&inode->i_lock);
-       NFS_I(inode)->cache_validity |= NFS_INO_REVAL_FORCED |
-                                       NFS_INO_REVAL_PAGECACHE |
-                                       NFS_INO_INVALID_SIZE;
+       nfs_set_cache_invalid(inode, NFS_INO_REVAL_FORCED |
+                                            NFS_INO_REVAL_PAGECACHE |
+                                            NFS_INO_INVALID_SIZE);
        spin_unlock(&inode->i_lock);
 }
 
@@ -1604,7 +1604,7 @@ static int nfs_writeback_done(struct rpc_task *task,
        /* Deal with the suid/sgid bit corner case */
        if (nfs_should_remove_suid(inode)) {
                spin_lock(&inode->i_lock);
-               NFS_I(inode)->cache_validity |= NFS_INO_INVALID_OTHER;
+               nfs_set_cache_invalid(inode, NFS_INO_INVALID_OTHER);
                spin_unlock(&inode->i_lock);
        }
        return 0;
index 821e591..d6cff5f 100644 (file)
@@ -73,6 +73,7 @@ config NFSD_V4
        select NFSD_V3
        select FS_POSIX_ACL
        select SUNRPC_GSS
+       select CRYPTO
        select CRYPTO_MD5
        select CRYPTO_SHA256
        select GRACE_PERIOD
index 53fcbf7..7629248 100644 (file)
@@ -898,6 +898,8 @@ nfsd_file_find_locked(struct inode *inode, unsigned int may_flags,
                        continue;
                if (!nfsd_match_cred(nf->nf_cred, current_cred()))
                        continue;
+               if (!test_bit(NFSD_FILE_HASHED, &nf->nf_flags))
+                       continue;
                if (nfsd_file_get(nf) != NULL)
                        return nf;
        }
index 052be5b..7325592 100644 (file)
@@ -1189,6 +1189,7 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata)
                switch (task->tk_status) {
                case -EIO:
                case -ETIMEDOUT:
+               case -EACCES:
                        nfsd4_mark_cb_down(clp, task->tk_status);
                }
                break;
index acdb3cd..dd9f38d 100644 (file)
@@ -1302,7 +1302,7 @@ nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct nfsd_file *src,
                        struct nfsd_file *dst)
 {
        nfs42_ssc_close(src->nf_file);
-       /* 'src' is freed by nfsd4_do_async_copy */
+       fput(src->nf_file);
        nfsd_file_put(dst);
        mntput(ss_mnt);
 }
index 423fd66..97447a6 100644 (file)
@@ -4940,31 +4940,6 @@ static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp,
        return fl;
 }
 
-static int nfsd4_check_conflicting_opens(struct nfs4_client *clp,
-                                               struct nfs4_file *fp)
-{
-       struct nfs4_clnt_odstate *co;
-       struct file *f = fp->fi_deleg_file->nf_file;
-       struct inode *ino = locks_inode(f);
-       int writes = atomic_read(&ino->i_writecount);
-
-       if (fp->fi_fds[O_WRONLY])
-               writes--;
-       if (fp->fi_fds[O_RDWR])
-               writes--;
-       if (writes > 0)
-               return -EAGAIN;
-       spin_lock(&fp->fi_lock);
-       list_for_each_entry(co, &fp->fi_clnt_odstate, co_perfile) {
-               if (co->co_client != clp) {
-                       spin_unlock(&fp->fi_lock);
-                       return -EAGAIN;
-               }
-       }
-       spin_unlock(&fp->fi_lock);
-       return 0;
-}
-
 static struct nfs4_delegation *
 nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh,
                    struct nfs4_file *fp, struct nfs4_clnt_odstate *odstate)
@@ -4984,12 +4959,9 @@ nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh,
 
        nf = find_readable_file(fp);
        if (!nf) {
-               /*
-                * We probably could attempt another open and get a read
-                * delegation, but for now, don't bother until the
-                * client actually sends us one.
-                */
-               return ERR_PTR(-EAGAIN);
+               /* We should always have a readable file here */
+               WARN_ON_ONCE(1);
+               return ERR_PTR(-EBADF);
        }
        spin_lock(&state_lock);
        spin_lock(&fp->fi_lock);
@@ -5019,19 +4991,11 @@ nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh,
        if (!fl)
                goto out_clnt_odstate;
 
-       status = nfsd4_check_conflicting_opens(clp, fp);
-       if (status) {
-               locks_free_lock(fl);
-               goto out_clnt_odstate;
-       }
        status = vfs_setlease(fp->fi_deleg_file->nf_file, fl->fl_type, &fl, NULL);
        if (fl)
                locks_free_lock(fl);
        if (status)
                goto out_clnt_odstate;
-       status = nfsd4_check_conflicting_opens(clp, fp);
-       if (status)
-               goto out_clnt_odstate;
 
        spin_lock(&state_lock);
        spin_lock(&fp->fi_lock);
@@ -5113,6 +5077,17 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open,
                                goto out_no_deleg;
                        if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED))
                                goto out_no_deleg;
+                       /*
+                        * Also, if the file was opened for write or
+                        * create, there's a good chance the client's
+                        * about to write to it, resulting in an
+                        * immediate recall (since we don't support
+                        * write delegations):
+                        */
+                       if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
+                               goto out_no_deleg;
+                       if (open->op_create == NFS4_OPEN_CREATE)
+                               goto out_no_deleg;
                        break;
                default:
                        goto out_no_deleg;
@@ -5389,7 +5364,7 @@ nfs4_laundromat(struct nfsd_net *nn)
        idr_for_each_entry(&nn->s2s_cp_stateids, cps_t, i) {
                cps = container_of(cps_t, struct nfs4_cpntf_state, cp_stateid);
                if (cps->cp_stateid.sc_type == NFS4_COPYNOTIFY_STID &&
-                               cps->cpntf_time > cutoff)
+                               cps->cpntf_time < cutoff)
                        _free_cpntf_state_locked(nn, cps);
        }
        spin_unlock(&nn->s2s_cp_lock);
index 1e75417..56872e9 100644 (file)
@@ -399,7 +399,7 @@ static void nilfs_segbuf_prepare_write(struct nilfs_segment_buffer *segbuf,
 {
        wi->bio = NULL;
        wi->rest_blocks = segbuf->sb_sum.nblocks;
-       wi->max_pages = BIO_MAX_PAGES;
+       wi->max_pages = BIO_MAX_VECS;
        wi->nr_vecs = min(wi->max_pages, wi->rest_blocks);
        wi->start = wi->end = 0;
        wi->blocknr = segbuf->sb_pseg_start;
index 26f74e0..988f1aa 100644 (file)
@@ -12,7 +12,7 @@
 
 #define IS_MNT_SHARED(m) ((m)->mnt.mnt_flags & MNT_SHARED)
 #define IS_MNT_SLAVE(m) ((m)->mnt_master)
-#define IS_MNT_NEW(m)  (!(m)->mnt_ns)
+#define IS_MNT_NEW(m)  (!(m)->mnt_ns || is_anon_ns((m)->mnt_ns))
 #define CLEAR_MNT_SHARED(m) ((m)->mnt.mnt_flags &= ~MNT_SHARED)
 #define IS_MNT_UNBINDABLE(m) ((m)->mnt.mnt_flags & MNT_UNBINDABLE)
 #define IS_MNT_MARKED(m) ((m)->mnt.mnt_flags & MNT_MARKED)
index 3cec6fb..e862cab 100644 (file)
@@ -1036,8 +1036,6 @@ struct clear_refs_private {
 
 #ifdef CONFIG_MEM_SOFT_DIRTY
 
-#define is_cow_mapping(flags) (((flags) & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE)
-
 static inline bool pte_is_pinned(struct vm_area_struct *vma, unsigned long addr, pte_t pte)
 {
        struct page *page;
index 37aaa83..945896d 100644 (file)
@@ -1055,10 +1055,9 @@ static long do_restart_poll(struct restart_block *restart_block)
 
        ret = do_sys_poll(ufds, nfds, to);
 
-       if (ret == -ERESTARTNOHAND) {
-               restart_block->fn = do_restart_poll;
-               ret = -ERESTART_RESTARTBLOCK;
-       }
+       if (ret == -ERESTARTNOHAND)
+               ret = set_restart_fn(restart_block, do_restart_poll);
+
        return ret;
 }
 
@@ -1080,7 +1079,6 @@ SYSCALL_DEFINE3(poll, struct pollfd __user *, ufds, unsigned int, nfds,
                struct restart_block *restart_block;
 
                restart_block = &current->restart_block;
-               restart_block->fn = do_restart_poll;
                restart_block->poll.ufds = ufds;
                restart_block->poll.nfds = nfds;
 
@@ -1091,7 +1089,7 @@ SYSCALL_DEFINE3(poll, struct pollfd __user *, ufds, unsigned int, nfds,
                } else
                        restart_block->poll.has_timeout = 0;
 
-               ret = -ERESTART_RESTARTBLOCK;
+               ret = set_restart_fn(restart_block, do_restart_poll);
        }
        return ret;
 }
index 45f4442..b9e87eb 100644 (file)
@@ -87,7 +87,7 @@ static int squashfs_bio_read(struct super_block *sb, u64 index, int length,
        int error, i;
        struct bio *bio;
 
-       if (page_count <= BIO_MAX_PAGES)
+       if (page_count <= BIO_MAX_VECS)
                bio = bio_alloc(GFP_NOIO, page_count);
        else
                bio = bio_kmalloc(GFP_NOIO, page_count);
index 46a861d..f93370b 100644 (file)
@@ -1007,9 +1007,10 @@ xfs_create(
        /*
         * Make sure that we have allocated dquot(s) on disk.
         */
-       error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid,
-                                       XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT,
-                                       &udqp, &gdqp, &pdqp);
+       error = xfs_qm_vop_dqalloc(dp, fsuid_into_mnt(mnt_userns),
+                       fsgid_into_mnt(mnt_userns), prid,
+                       XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT,
+                       &udqp, &gdqp, &pdqp);
        if (error)
                return error;
 
@@ -1157,9 +1158,10 @@ xfs_create_tmpfile(
        /*
         * Make sure that we have allocated dquot(s) on disk.
         */
-       error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid,
-                               XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT,
-                               &udqp, &gdqp, &pdqp);
+       error = xfs_qm_vop_dqalloc(dp, fsuid_into_mnt(mnt_userns),
+                       fsgid_into_mnt(mnt_userns), prid,
+                       XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT,
+                       &udqp, &gdqp, &pdqp);
        if (error)
                return error;
 
index ca310a1..3498b97 100644 (file)
@@ -168,6 +168,12 @@ xfs_bulkstat_one(
        };
        int                     error;
 
+       if (breq->mnt_userns != &init_user_ns) {
+               xfs_warn_ratelimited(breq->mp,
+                       "bulkstat not supported inside of idmapped mounts.");
+               return -EINVAL;
+       }
+
        ASSERT(breq->icount == 1);
 
        bc.buf = kmem_zalloc(sizeof(struct xfs_bulkstat),
index 52370d0..1c97b15 100644 (file)
@@ -634,6 +634,47 @@ xfs_check_summary_counts(
        return xfs_initialize_perag_data(mp, mp->m_sb.sb_agcount);
 }
 
+/*
+ * Flush and reclaim dirty inodes in preparation for unmount. Inodes and
+ * internal inode structures can be sitting in the CIL and AIL at this point,
+ * so we need to unpin them, write them back and/or reclaim them before unmount
+ * can proceed.
+ *
+ * An inode cluster that has been freed can have its buffer still pinned in
+ * memory because the transaction is still sitting in a iclog. The stale inodes
+ * on that buffer will be pinned to the buffer until the transaction hits the
+ * disk and the callbacks run. Pushing the AIL will skip the stale inodes and
+ * may never see the pinned buffer, so nothing will push out the iclog and
+ * unpin the buffer.
+ *
+ * Hence we need to force the log to unpin everything first. However, log
+ * forces don't wait for the discards they issue to complete, so we have to
+ * explicitly wait for them to complete here as well.
+ *
+ * Then we can tell the world we are unmounting so that error handling knows
+ * that the filesystem is going away and we should error out anything that we
+ * have been retrying in the background.  This will prevent never-ending
+ * retries in AIL pushing from hanging the unmount.
+ *
+ * Finally, we can push the AIL to clean all the remaining dirty objects, then
+ * reclaim the remaining inodes that are still in memory at this point in time.
+ */
+static void
+xfs_unmount_flush_inodes(
+       struct xfs_mount        *mp)
+{
+       xfs_log_force(mp, XFS_LOG_SYNC);
+       xfs_extent_busy_wait_all(mp);
+       flush_workqueue(xfs_discard_wq);
+
+       mp->m_flags |= XFS_MOUNT_UNMOUNTING;
+
+       xfs_ail_push_all_sync(mp->m_ail);
+       cancel_delayed_work_sync(&mp->m_reclaim_work);
+       xfs_reclaim_inodes(mp);
+       xfs_health_unmount(mp);
+}
+
 /*
  * This function does the following on an initial mount of a file system:
  *     - reads the superblock from disk and init the mount struct
@@ -1008,7 +1049,7 @@ xfs_mountfs(
        /* Clean out dquots that might be in memory after quotacheck. */
        xfs_qm_unmount(mp);
        /*
-        * Cancel all delayed reclaim work and reclaim the inodes directly.
+        * Flush all inode reclamation work and flush the log.
         * We have to do this /after/ rtunmount and qm_unmount because those
         * two will have scheduled delayed reclaim for the rt/quota inodes.
         *
@@ -1018,11 +1059,8 @@ xfs_mountfs(
         * qm_unmount_quotas and therefore rely on qm_unmount to release the
         * quota inodes.
         */
-       cancel_delayed_work_sync(&mp->m_reclaim_work);
-       xfs_reclaim_inodes(mp);
-       xfs_health_unmount(mp);
+       xfs_unmount_flush_inodes(mp);
  out_log_dealloc:
-       mp->m_flags |= XFS_MOUNT_UNMOUNTING;
        xfs_log_mount_cancel(mp);
  out_fail_wait:
        if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp)
@@ -1063,47 +1101,7 @@ xfs_unmountfs(
        xfs_rtunmount_inodes(mp);
        xfs_irele(mp->m_rootip);
 
-       /*
-        * We can potentially deadlock here if we have an inode cluster
-        * that has been freed has its buffer still pinned in memory because
-        * the transaction is still sitting in a iclog. The stale inodes
-        * on that buffer will be pinned to the buffer until the
-        * transaction hits the disk and the callbacks run. Pushing the AIL will
-        * skip the stale inodes and may never see the pinned buffer, so
-        * nothing will push out the iclog and unpin the buffer. Hence we
-        * need to force the log here to ensure all items are flushed into the
-        * AIL before we go any further.
-        */
-       xfs_log_force(mp, XFS_LOG_SYNC);
-
-       /*
-        * Wait for all busy extents to be freed, including completion of
-        * any discard operation.
-        */
-       xfs_extent_busy_wait_all(mp);
-       flush_workqueue(xfs_discard_wq);
-
-       /*
-        * We now need to tell the world we are unmounting. This will allow
-        * us to detect that the filesystem is going away and we should error
-        * out anything that we have been retrying in the background. This will
-        * prevent neverending retries in AIL pushing from hanging the unmount.
-        */
-       mp->m_flags |= XFS_MOUNT_UNMOUNTING;
-
-       /*
-        * Flush all pending changes from the AIL.
-        */
-       xfs_ail_push_all_sync(mp->m_ail);
-
-       /*
-        * Reclaim all inodes. At this point there should be no dirty inodes and
-        * none should be pinned or locked. Stop background inode reclaim here
-        * if it is still running.
-        */
-       cancel_delayed_work_sync(&mp->m_reclaim_work);
-       xfs_reclaim_inodes(mp);
-       xfs_health_unmount(mp);
+       xfs_unmount_flush_inodes(mp);
 
        xfs_qm_unmount(mp);
 
index 1379013..7f368b1 100644 (file)
@@ -182,7 +182,8 @@ xfs_symlink(
        /*
         * Make sure that we have allocated dquot(s) on disk.
         */
-       error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid,
+       error = xfs_qm_vop_dqalloc(dp, fsuid_into_mnt(mnt_userns),
+                       fsgid_into_mnt(mnt_userns), prid,
                        XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT,
                        &udqp, &gdqp, &pdqp);
        if (error)
index b6ff4a2..049e36c 100644 (file)
@@ -165,6 +165,21 @@ static int zonefs_writepages(struct address_space *mapping,
        return iomap_writepages(mapping, wbc, &wpc, &zonefs_writeback_ops);
 }
 
+static int zonefs_swap_activate(struct swap_info_struct *sis,
+                               struct file *swap_file, sector_t *span)
+{
+       struct inode *inode = file_inode(swap_file);
+       struct zonefs_inode_info *zi = ZONEFS_I(inode);
+
+       if (zi->i_ztype != ZONEFS_ZTYPE_CNV) {
+               zonefs_err(inode->i_sb,
+                          "swap file: not a conventional zone file\n");
+               return -EINVAL;
+       }
+
+       return iomap_swapfile_activate(sis, swap_file, span, &zonefs_iomap_ops);
+}
+
 static const struct address_space_operations zonefs_file_aops = {
        .readpage               = zonefs_readpage,
        .readahead              = zonefs_readahead,
@@ -177,6 +192,7 @@ static const struct address_space_operations zonefs_file_aops = {
        .is_partially_uptodate  = iomap_is_partially_uptodate,
        .error_remove_page      = generic_error_remove_page,
        .direct_IO              = noop_direct_IO,
+       .swap_activate          = zonefs_swap_activate,
 };
 
 static void zonefs_update_stats(struct inode *inode, loff_t new_isize)
@@ -684,7 +700,7 @@ static ssize_t zonefs_file_dio_append(struct kiocb *iocb, struct iov_iter *from)
        max = ALIGN_DOWN(max << SECTOR_SHIFT, inode->i_sb->s_blocksize);
        iov_iter_truncate(from, max);
 
-       nr_pages = iov_iter_npages(from, BIO_MAX_PAGES);
+       nr_pages = iov_iter_npages(from, BIO_MAX_VECS);
        if (!nr_pages)
                return 0;
 
@@ -727,6 +743,68 @@ out_release:
        return ret;
 }
 
+/*
+ * Do not exceed the LFS limits nor the file zone size. If pos is under the
+ * limit it becomes a short access. If it exceeds the limit, return -EFBIG.
+ */
+static loff_t zonefs_write_check_limits(struct file *file, loff_t pos,
+                                       loff_t count)
+{
+       struct inode *inode = file_inode(file);
+       struct zonefs_inode_info *zi = ZONEFS_I(inode);
+       loff_t limit = rlimit(RLIMIT_FSIZE);
+       loff_t max_size = zi->i_max_size;
+
+       if (limit != RLIM_INFINITY) {
+               if (pos >= limit) {
+                       send_sig(SIGXFSZ, current, 0);
+                       return -EFBIG;
+               }
+               count = min(count, limit - pos);
+       }
+
+       if (!(file->f_flags & O_LARGEFILE))
+               max_size = min_t(loff_t, MAX_NON_LFS, max_size);
+
+       if (unlikely(pos >= max_size))
+               return -EFBIG;
+
+       return min(count, max_size - pos);
+}
+
+static ssize_t zonefs_write_checks(struct kiocb *iocb, struct iov_iter *from)
+{
+       struct file *file = iocb->ki_filp;
+       struct inode *inode = file_inode(file);
+       struct zonefs_inode_info *zi = ZONEFS_I(inode);
+       loff_t count;
+
+       if (IS_SWAPFILE(inode))
+               return -ETXTBSY;
+
+       if (!iov_iter_count(from))
+               return 0;
+
+       if ((iocb->ki_flags & IOCB_NOWAIT) && !(iocb->ki_flags & IOCB_DIRECT))
+               return -EINVAL;
+
+       if (iocb->ki_flags & IOCB_APPEND) {
+               if (zi->i_ztype != ZONEFS_ZTYPE_SEQ)
+                       return -EINVAL;
+               mutex_lock(&zi->i_truncate_mutex);
+               iocb->ki_pos = zi->i_wpoffset;
+               mutex_unlock(&zi->i_truncate_mutex);
+       }
+
+       count = zonefs_write_check_limits(file, iocb->ki_pos,
+                                         iov_iter_count(from));
+       if (count < 0)
+               return count;
+
+       iov_iter_truncate(from, count);
+       return iov_iter_count(from);
+}
+
 /*
  * Handle direct writes. For sequential zone files, this is the only possible
  * write path. For these files, check that the user is issuing writes
@@ -744,8 +822,7 @@ static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from)
        struct super_block *sb = inode->i_sb;
        bool sync = is_sync_kiocb(iocb);
        bool append = false;
-       size_t count;
-       ssize_t ret;
+       ssize_t ret, count;
 
        /*
         * For async direct IOs to sequential zone files, refuse IOCB_NOWAIT
@@ -763,12 +840,11 @@ static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from)
                inode_lock(inode);
        }
 
-       ret = generic_write_checks(iocb, from);
-       if (ret <= 0)
+       count = zonefs_write_checks(iocb, from);
+       if (count <= 0) {
+               ret = count;
                goto inode_unlock;
-
-       iov_iter_truncate(from, zi->i_max_size - iocb->ki_pos);
-       count = iov_iter_count(from);
+       }
 
        if ((iocb->ki_pos | count) & (sb->s_blocksize - 1)) {
                ret = -EINVAL;
@@ -828,12 +904,10 @@ static ssize_t zonefs_file_buffered_write(struct kiocb *iocb,
                inode_lock(inode);
        }
 
-       ret = generic_write_checks(iocb, from);
+       ret = zonefs_write_checks(iocb, from);
        if (ret <= 0)
                goto inode_unlock;
 
-       iov_iter_truncate(from, zi->i_max_size - iocb->ki_pos);
-
        ret = iomap_file_buffered_write(iocb, from, &zonefs_iomap_ops);
        if (ret > 0)
                iocb->ki_pos += ret;
@@ -966,9 +1040,7 @@ static int zonefs_open_zone(struct inode *inode)
 
        mutex_lock(&zi->i_truncate_mutex);
 
-       zi->i_wr_refcnt++;
-       if (zi->i_wr_refcnt == 1) {
-
+       if (!zi->i_wr_refcnt) {
                if (atomic_inc_return(&sbi->s_open_zones) > sbi->s_max_open_zones) {
                        atomic_dec(&sbi->s_open_zones);
                        ret = -EBUSY;
@@ -978,7 +1050,6 @@ static int zonefs_open_zone(struct inode *inode)
                if (i_size_read(inode) < zi->i_max_size) {
                        ret = zonefs_zone_mgmt(inode, REQ_OP_ZONE_OPEN);
                        if (ret) {
-                               zi->i_wr_refcnt--;
                                atomic_dec(&sbi->s_open_zones);
                                goto unlock;
                        }
@@ -986,6 +1057,8 @@ static int zonefs_open_zone(struct inode *inode)
                }
        }
 
+       zi->i_wr_refcnt++;
+
 unlock:
        mutex_unlock(&zi->i_truncate_mutex);
 
index e17be32..b8ca136 100644 (file)
@@ -612,9 +612,11 @@ static inline void ttm_bo_pin(struct ttm_buffer_object *bo)
 static inline void ttm_bo_unpin(struct ttm_buffer_object *bo)
 {
        dma_resv_assert_held(bo->base.resv);
-       WARN_ON_ONCE(!bo->pin_count);
        WARN_ON_ONCE(!kref_read(&bo->kref));
-       --bo->pin_count;
+       if (bo->pin_count)
+               --bo->pin_count;
+       else
+               WARN_ON_ONCE(true);
 }
 
 int ttm_mem_evict_first(struct ttm_bo_device *bdev,
index 8dcb3e1..6fd3cda 100644 (file)
 #define ARMV8_PMU_CYCLE_IDX            (ARMV8_PMU_MAX_COUNTERS - 1)
 #define ARMV8_PMU_MAX_COUNTER_PAIRS    ((ARMV8_PMU_MAX_COUNTERS + 1) >> 1)
 
+DECLARE_STATIC_KEY_FALSE(kvm_arm_pmu_available);
+
+static __always_inline bool kvm_arm_support_pmu_v3(void)
+{
+       return static_branch_likely(&kvm_arm_pmu_available);
+}
+
 #ifdef CONFIG_HW_PERF_EVENTS
 
 struct kvm_pmc {
@@ -47,7 +54,6 @@ void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
                                    u64 select_idx);
-bool kvm_arm_support_pmu_v3(void);
 int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu,
                            struct kvm_device_attr *attr);
 int kvm_arm_pmu_v3_get_attr(struct kvm_vcpu *vcpu,
@@ -87,7 +93,6 @@ static inline void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val) {}
 static inline void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val) {}
 static inline void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu,
                                                  u64 data, u64 select_idx) {}
-static inline bool kvm_arm_support_pmu_v3(void) { return false; }
 static inline int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu,
                                          struct kvm_device_attr *attr)
 {
index 9f43241..fcdaab7 100644 (file)
@@ -1079,19 +1079,25 @@ void __acpi_handle_debug(struct _ddebug *descriptor, acpi_handle handle, const c
 #if defined(CONFIG_ACPI) && defined(CONFIG_GPIOLIB)
 bool acpi_gpio_get_irq_resource(struct acpi_resource *ares,
                                struct acpi_resource_gpio **agpio);
-int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index);
+int acpi_dev_gpio_irq_get_by(struct acpi_device *adev, const char *name, int index);
 #else
 static inline bool acpi_gpio_get_irq_resource(struct acpi_resource *ares,
                                              struct acpi_resource_gpio **agpio)
 {
        return false;
 }
-static inline int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
+static inline int acpi_dev_gpio_irq_get_by(struct acpi_device *adev,
+                                          const char *name, int index)
 {
        return -ENXIO;
 }
 #endif
 
+static inline int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
+{
+       return acpi_dev_gpio_irq_get_by(adev, NULL, index);
+}
+
 /* Device properties */
 
 #ifdef CONFIG_ACPI
index 6cc93ab..c68d87b 100644 (file)
@@ -105,8 +105,19 @@ extern struct bus_type amba_bustype;
 #define amba_get_drvdata(d)    dev_get_drvdata(&d->dev)
 #define amba_set_drvdata(d,p)  dev_set_drvdata(&d->dev, p)
 
+#ifdef CONFIG_ARM_AMBA
 int amba_driver_register(struct amba_driver *);
 void amba_driver_unregister(struct amba_driver *);
+#else
+static inline int amba_driver_register(struct amba_driver *drv)
+{
+       return -EINVAL;
+}
+static inline void amba_driver_unregister(struct amba_driver *drv)
+{
+}
+#endif
+
 struct amba_device *amba_device_alloc(const char *, resource_size_t, size_t);
 void amba_device_put(struct amba_device *);
 int amba_device_add(struct amba_device *, struct resource *);
index 60cd25c..9b02961 100644 (file)
@@ -151,7 +151,7 @@ struct atm_dev {
        const char      *type;          /* device type name */
        int             number;         /* device index */
        void            *dev_data;      /* per-device data */
-       void            *phy_data;      /* private PHY date */
+       void            *phy_data;      /* private PHY data */
        unsigned long   flags;          /* device flags (ATM_DF_*) */
        struct list_head local;         /* local ATM addresses */
        struct list_head lecs;          /* LECS ATM addresses learned via ILMI */
index 983ed2f..d0246c9 100644 (file)
 #define BIO_BUG_ON
 #endif
 
-#define BIO_MAX_PAGES          256U
+#define BIO_MAX_VECS           256U
 
 static inline unsigned int bio_max_segs(unsigned int nr_segs)
 {
-       return min(nr_segs, BIO_MAX_PAGES);
+       return min(nr_segs, BIO_MAX_VECS);
 }
 
 #define bio_prio(bio)                  (bio)->bi_ioprio
index 685f34c..d438eb0 100644 (file)
@@ -65,8 +65,12 @@ static inline void can_skb_reserve(struct sk_buff *skb)
 
 static inline void can_skb_set_owner(struct sk_buff *skb, struct sock *sk)
 {
-       if (sk) {
-               sock_hold(sk);
+       /* If the socket has already been closed by user space, the
+        * refcount may already be 0 (and the socket will be freed
+        * after the last TX skb has been freed). So only increase
+        * socket refcount if the refcount is > 0.
+        */
+       if (sk && refcount_inc_not_zero(&sk->sk_refcnt)) {
                skb->destructor = sock_efree;
                skb->sk = sk;
        }
index 04c0a5a..d217c38 100644 (file)
 #define __no_sanitize_thread
 #endif
 
+#if defined(CONFIG_ARCH_USE_BUILTIN_BSWAP)
+#define __HAVE_BUILTIN_BSWAP32__
+#define __HAVE_BUILTIN_BSWAP64__
+#define __HAVE_BUILTIN_BSWAP16__
+#endif /* CONFIG_ARCH_USE_BUILTIN_BSWAP */
+
 #if __has_feature(undefined_behavior_sanitizer)
 /* GCC does not have __SANITIZE_UNDEFINED__ */
 #define __no_sanitize_undefined \
diff --git a/include/linux/compiler-version.h b/include/linux/compiler-version.h
new file mode 100644 (file)
index 0000000..2b2972c
--- /dev/null
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifdef  __LINUX_COMPILER_VERSION_H
+#error "Please do not include <linux/compiler-version.h>. This is done by the build system."
+#endif
+#define __LINUX_COMPILER_VERSION_H
+
+/*
+ * This header exists to force full rebuild when the compiler is upgraded.
+ *
+ * When fixdep scans this, it will find this string "CONFIG_CC_VERSION_TEXT"
+ * and add dependency on include/config/cc/version/text.h, which is touched
+ * by Kconfig when the version string from the compiler changes.
+ */
index 3aaa068..94a578a 100644 (file)
@@ -108,6 +108,8 @@ static inline void cpu_maps_update_done(void)
 {
 }
 
+static inline int add_cpu(unsigned int cpu) { return 0;}
+
 #endif /* CONFIG_SMP */
 extern struct bus_type cpu_subsys;
 
@@ -137,6 +139,7 @@ static inline int  cpus_read_trylock(void) { return true; }
 static inline void lockdep_assert_cpus_held(void) { }
 static inline void cpu_hotplug_disable(void) { }
 static inline void cpu_hotplug_enable(void) { }
+static inline int remove_cpu(unsigned int cpu) { return -EPERM; }
 static inline void smp_shutdown_nonboot_cpus(unsigned int primary_cpu) { }
 #endif /* !CONFIG_HOTPLUG_CPU */
 
index 8710f57..6b5d36b 100644 (file)
@@ -72,8 +72,10 @@ typedef void *efi_handle_t;
  */
 typedef guid_t efi_guid_t __aligned(__alignof__(u32));
 
-#define EFI_GUID(a,b,c,d0,d1,d2,d3,d4,d5,d6,d7) \
-       GUID_INIT(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7)
+#define EFI_GUID(a, b, c, d...) (efi_guid_t){ {                                        \
+       (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff,  \
+       (b) & 0xff, ((b) >> 8) & 0xff,                                          \
+       (c) & 0xff, ((c) >> 8) & 0xff, d } }
 
 /*
  * Generic EFI table header
index ef49307..c73b25b 100644 (file)
@@ -674,6 +674,8 @@ struct acpi_gpio_mapping {
  * get GpioIo type explicitly, this quirk may be used.
  */
 #define ACPI_GPIO_QUIRK_ONLY_GPIOIO            BIT(1)
+/* Use given pin as an absolute GPIO number in the system */
+#define ACPI_GPIO_QUIRK_ABSOLUTE_NUMBER                BIT(2)
 
        unsigned int quirks;
 };
index 7cb7bd0..79cde99 100644 (file)
@@ -5,31 +5,6 @@
 #include <linux/sched.h>
 #include <linux/xarray.h>
 
-struct io_wq_work_node {
-       struct io_wq_work_node *next;
-};
-
-struct io_wq_work_list {
-       struct io_wq_work_node *first;
-       struct io_wq_work_node *last;
-};
-
-struct io_uring_task {
-       /* submission side */
-       struct xarray           xa;
-       struct wait_queue_head  wait;
-       struct file             *last;
-       void                    *io_wq;
-       struct percpu_counter   inflight;
-       atomic_t                in_idle;
-       bool                    sqpoll;
-
-       spinlock_t              task_lock;
-       struct io_wq_work_list  task_list;
-       unsigned long           task_state;
-       struct callback_head    task_work;
-};
-
 #if defined(CONFIG_IO_URING)
 struct sock *io_uring_get_socket(struct file *file);
 void __io_uring_task_cancel(void);
index 42d1968..33cacc8 100644 (file)
@@ -150,7 +150,6 @@ struct irq_domain_chip_generic;
  *      setting up one or more generic chips for interrupt controllers
  *      drivers using the generic chip library which uses this pointer.
  * @parent: Pointer to parent irq_domain to support hierarchy irq_domains
- * @debugfs_file: dentry for the domain debugfs file
  *
  * Revmap data, used internally by irq_domain
  * @revmap_direct_max_irq: The largest hwirq that can be set for controllers that
@@ -174,9 +173,6 @@ struct irq_domain {
 #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
        struct irq_domain *parent;
 #endif
-#ifdef CONFIG_GENERIC_IRQ_DEBUGFS
-       struct dentry           *debugfs_file;
-#endif
 
        /* reverse map data. The linear map gets appended to the irq_domain */
        irq_hw_number_t hwirq_max;
index e78e17a..24a59cb 100644 (file)
@@ -2,8 +2,6 @@
 #ifndef __LINUX_KCONFIG_H
 #define __LINUX_KCONFIG_H
 
-/* CONFIG_CC_VERSION_TEXT (Do not delete this comment. See help in Kconfig) */
-
 #include <generated/autoconf.h>
 
 #ifdef CONFIG_CPU_BIG_ENDIAN
index c88bc24..d13e3cd 100644 (file)
@@ -460,7 +460,7 @@ static inline void memblock_free_late(phys_addr_t base, phys_addr_t size)
 /*
  * Set the allocation direction to bottom-up or top-down.
  */
-static inline void memblock_set_bottom_up(bool enable)
+static inline __init void memblock_set_bottom_up(bool enable)
 {
        memblock.bottom_up = enable;
 }
@@ -470,7 +470,7 @@ static inline void memblock_set_bottom_up(bool enable)
  * if this is true, that said, memblock will allocate memory
  * in bottom-up direction.
  */
-static inline bool memblock_bottom_up(void)
+static inline __init bool memblock_bottom_up(void)
 {
        return memblock.bottom_up;
 }
index e6dc793..0c04d39 100644 (file)
@@ -1061,9 +1061,7 @@ static inline void memcg_memory_event_mm(struct mm_struct *mm,
        rcu_read_unlock();
 }
 
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-void mem_cgroup_split_huge_fixup(struct page *head);
-#endif
+void split_page_memcg(struct page *head, unsigned int nr);
 
 #else /* CONFIG_MEMCG */
 
@@ -1400,7 +1398,7 @@ unsigned long mem_cgroup_soft_limit_reclaim(pg_data_t *pgdat, int order,
        return 0;
 }
 
-static inline void mem_cgroup_split_huge_fixup(struct page *head)
+static inline void split_page_memcg(struct page *head, unsigned int nr)
 {
 }
 
index 23040b6..7f07cfe 100644 (file)
@@ -28,282 +28,6 @@ struct abx500_init_settings {
        u8 setting;
 };
 
-/* Battery driver related data */
-/*
- * ADC for the battery thermistor.
- * When using the ABx500_ADC_THERM_BATCTRL the battery ID resistor is combined
- * with a NTC resistor to both identify the battery and to measure its
- * temperature. Different phone manufactures uses different techniques to both
- * identify the battery and to read its temperature.
- */
-enum abx500_adc_therm {
-       ABx500_ADC_THERM_BATCTRL,
-       ABx500_ADC_THERM_BATTEMP,
-};
-
-/**
- * struct abx500_res_to_temp - defines one point in a temp to res curve. To
- * be used in battery packs that combines the identification resistor with a
- * NTC resistor.
- * @temp:                      battery pack temperature in Celsius
- * @resist:                    NTC resistor net total resistance
- */
-struct abx500_res_to_temp {
-       int temp;
-       int resist;
-};
-
-/**
- * struct abx500_v_to_cap - Table for translating voltage to capacity
- * @voltage:           Voltage in mV
- * @capacity:          Capacity in percent
- */
-struct abx500_v_to_cap {
-       int voltage;
-       int capacity;
-};
-
-/* Forward declaration */
-struct abx500_fg;
-
-/**
- * struct abx500_fg_parameters - Fuel gauge algorithm parameters, in seconds
- * if not specified
- * @recovery_sleep_timer:      Time between measurements while recovering
- * @recovery_total_time:       Total recovery time
- * @init_timer:                        Measurement interval during startup
- * @init_discard_time:         Time we discard voltage measurement at startup
- * @init_total_time:           Total init time during startup
- * @high_curr_time:            Time current has to be high to go to recovery
- * @accu_charging:             FG accumulation time while charging
- * @accu_high_curr:            FG accumulation time in high current mode
- * @high_curr_threshold:       High current threshold, in mA
- * @lowbat_threshold:          Low battery threshold, in mV
- * @overbat_threshold:         Over battery threshold, in mV
- * @battok_falling_th_sel0     Threshold in mV for battOk signal sel0
- *                             Resolution in 50 mV step.
- * @battok_raising_th_sel1     Threshold in mV for battOk signal sel1
- *                             Resolution in 50 mV step.
- * @user_cap_limit             Capacity reported from user must be within this
- *                             limit to be considered as sane, in percentage
- *                             points.
- * @maint_thres                        This is the threshold where we stop reporting
- *                             battery full while in maintenance, in per cent
- * @pcut_enable:                       Enable power cut feature in ab8505
- * @pcut_max_time:             Max time threshold
- * @pcut_flag_time:            Flagtime threshold
- * @pcut_max_restart:          Max number of restarts
- * @pcut_debounce_time:                Sets battery debounce time
- */
-struct abx500_fg_parameters {
-       int recovery_sleep_timer;
-       int recovery_total_time;
-       int init_timer;
-       int init_discard_time;
-       int init_total_time;
-       int high_curr_time;
-       int accu_charging;
-       int accu_high_curr;
-       int high_curr_threshold;
-       int lowbat_threshold;
-       int overbat_threshold;
-       int battok_falling_th_sel0;
-       int battok_raising_th_sel1;
-       int user_cap_limit;
-       int maint_thres;
-       bool pcut_enable;
-       u8 pcut_max_time;
-       u8 pcut_flag_time;
-       u8 pcut_max_restart;
-       u8 pcut_debounce_time;
-};
-
-/**
- * struct abx500_charger_maximization - struct used by the board config.
- * @use_maxi:          Enable maximization for this battery type
- * @maxi_chg_curr:     Maximum charger current allowed
- * @maxi_wait_cycles:  cycles to wait before setting charger current
- * @charger_curr_step  delta between two charger current settings (mA)
- */
-struct abx500_maxim_parameters {
-       bool ena_maxi;
-       int chg_curr;
-       int wait_cycles;
-       int charger_curr_step;
-};
-
-/**
- * struct abx500_battery_type - different batteries supported
- * @name:                      battery technology
- * @resis_high:                        battery upper resistance limit
- * @resis_low:                 battery lower resistance limit
- * @charge_full_design:                Maximum battery capacity in mAh
- * @nominal_voltage:           Nominal voltage of the battery in mV
- * @termination_vol:           max voltage upto which battery can be charged
- * @termination_curr           battery charging termination current in mA
- * @recharge_cap               battery capacity limit that will trigger a new
- *                             full charging cycle in the case where maintenan-
- *                             -ce charging has been disabled
- * @normal_cur_lvl:            charger current in normal state in mA
- * @normal_vol_lvl:            charger voltage in normal state in mV
- * @maint_a_cur_lvl:           charger current in maintenance A state in mA
- * @maint_a_vol_lvl:           charger voltage in maintenance A state in mV
- * @maint_a_chg_timer_h:       charge time in maintenance A state
- * @maint_b_cur_lvl:           charger current in maintenance B state in mA
- * @maint_b_vol_lvl:           charger voltage in maintenance B state in mV
- * @maint_b_chg_timer_h:       charge time in maintenance B state
- * @low_high_cur_lvl:          charger current in temp low/high state in mA
- * @low_high_vol_lvl:          charger voltage in temp low/high state in mV'
- * @battery_resistance:                battery inner resistance in mOhm.
- * @n_r_t_tbl_elements:                number of elements in r_to_t_tbl
- * @r_to_t_tbl:                        table containing resistance to temp points
- * @n_v_cap_tbl_elements:      number of elements in v_to_cap_tbl
- * @v_to_cap_tbl:              Voltage to capacity (in %) table
- * @n_batres_tbl_elements      number of elements in the batres_tbl
- * @batres_tbl                 battery internal resistance vs temperature table
- */
-struct abx500_battery_type {
-       int name;
-       int resis_high;
-       int resis_low;
-       int charge_full_design;
-       int nominal_voltage;
-       int termination_vol;
-       int termination_curr;
-       int recharge_cap;
-       int normal_cur_lvl;
-       int normal_vol_lvl;
-       int maint_a_cur_lvl;
-       int maint_a_vol_lvl;
-       int maint_a_chg_timer_h;
-       int maint_b_cur_lvl;
-       int maint_b_vol_lvl;
-       int maint_b_chg_timer_h;
-       int low_high_cur_lvl;
-       int low_high_vol_lvl;
-       int battery_resistance;
-       int n_temp_tbl_elements;
-       const struct abx500_res_to_temp *r_to_t_tbl;
-       int n_v_cap_tbl_elements;
-       const struct abx500_v_to_cap *v_to_cap_tbl;
-       int n_batres_tbl_elements;
-       const struct batres_vs_temp *batres_tbl;
-};
-
-/**
- * struct abx500_bm_capacity_levels - abx500 capacity level data
- * @critical:          critical capacity level in percent
- * @low:               low capacity level in percent
- * @normal:            normal capacity level in percent
- * @high:              high capacity level in percent
- * @full:              full capacity level in percent
- */
-struct abx500_bm_capacity_levels {
-       int critical;
-       int low;
-       int normal;
-       int high;
-       int full;
-};
-
-/**
- * struct abx500_bm_charger_parameters - Charger specific parameters
- * @usb_volt_max:      maximum allowed USB charger voltage in mV
- * @usb_curr_max:      maximum allowed USB charger current in mA
- * @ac_volt_max:       maximum allowed AC charger voltage in mV
- * @ac_curr_max:       maximum allowed AC charger current in mA
- */
-struct abx500_bm_charger_parameters {
-       int usb_volt_max;
-       int usb_curr_max;
-       int ac_volt_max;
-       int ac_curr_max;
-};
-
-/**
- * struct abx500_bm_data - abx500 battery management data
- * @temp_under         under this temp, charging is stopped
- * @temp_low           between this temp and temp_under charging is reduced
- * @temp_high          between this temp and temp_over charging is reduced
- * @temp_over          over this temp, charging is stopped
- * @temp_now           present battery temperature
- * @temp_interval_chg  temperature measurement interval in s when charging
- * @temp_interval_nochg        temperature measurement interval in s when not charging
- * @main_safety_tmr_h  safety timer for main charger
- * @usb_safety_tmr_h   safety timer for usb charger
- * @bkup_bat_v         voltage which we charge the backup battery with
- * @bkup_bat_i         current which we charge the backup battery with
- * @no_maintenance     indicates that maintenance charging is disabled
- * @capacity_scaling    indicates whether capacity scaling is to be used
- * @abx500_adc_therm   placement of thermistor, batctrl or battemp adc
- * @chg_unknown_bat    flag to enable charging of unknown batteries
- * @enable_overshoot   flag to enable VBAT overshoot control
- * @auto_trig          flag to enable auto adc trigger
- * @fg_res             resistance of FG resistor in 0.1mOhm
- * @n_btypes           number of elements in array bat_type
- * @batt_id            index of the identified battery in array bat_type
- * @interval_charging  charge alg cycle period time when charging (sec)
- * @interval_not_charging charge alg cycle period time when not charging (sec)
- * @temp_hysteresis    temperature hysteresis
- * @gnd_lift_resistance        Battery ground to phone ground resistance (mOhm)
- * @n_chg_out_curr             number of elements in array chg_output_curr
- * @n_chg_in_curr              number of elements in array chg_input_curr
- * @chg_output_curr    charger output current level map
- * @chg_input_curr             charger input current level map
- * @maxi               maximization parameters
- * @cap_levels         capacity in percent for the different capacity levels
- * @bat_type           table of supported battery types
- * @chg_params         charger parameters
- * @fg_params          fuel gauge parameters
- */
-struct abx500_bm_data {
-       int temp_under;
-       int temp_low;
-       int temp_high;
-       int temp_over;
-       int temp_now;
-       int temp_interval_chg;
-       int temp_interval_nochg;
-       int main_safety_tmr_h;
-       int usb_safety_tmr_h;
-       int bkup_bat_v;
-       int bkup_bat_i;
-       bool autopower_cfg;
-       bool ac_enabled;
-       bool usb_enabled;
-       bool no_maintenance;
-       bool capacity_scaling;
-       bool chg_unknown_bat;
-       bool enable_overshoot;
-       bool auto_trig;
-       enum abx500_adc_therm adc_therm;
-       int fg_res;
-       int n_btypes;
-       int batt_id;
-       int interval_charging;
-       int interval_not_charging;
-       int temp_hysteresis;
-       int gnd_lift_resistance;
-       int n_chg_out_curr;
-       int n_chg_in_curr;
-       int *chg_output_curr;
-       int *chg_input_curr;
-       const struct abx500_maxim_parameters *maxi;
-       const struct abx500_bm_capacity_levels *cap_levels;
-       struct abx500_battery_type *bat_type;
-       const struct abx500_bm_charger_parameters *chg_params;
-       const struct abx500_fg_parameters *fg_params;
-};
-
-enum {
-       NTC_EXTERNAL = 0,
-       NTC_INTERNAL,
-};
-
-int ab8500_bm_of_probe(struct device *dev,
-                      struct device_node *np,
-                      struct abx500_bm_data *bm);
-
 int abx500_set_register_interruptible(struct device *dev, u8 bank, u8 reg,
        u8 value);
 int abx500_get_register_interruptible(struct device *dev, u8 bank, u8 reg,
diff --git a/include/linux/mfd/abx500/ab8500-bm.h b/include/linux/mfd/abx500/ab8500-bm.h
deleted file mode 100644 (file)
index 903e94c..0000000
+++ /dev/null
@@ -1,476 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright ST-Ericsson 2012.
- *
- * Author: Arun Murthy <arun.murthy@stericsson.com>
- */
-
-#ifndef _AB8500_BM_H
-#define _AB8500_BM_H
-
-#include <linux/kernel.h>
-#include <linux/mfd/abx500.h>
-
-/*
- * System control 2 register offsets.
- * bank = 0x02
- */
-#define AB8500_MAIN_WDOG_CTRL_REG      0x01
-#define AB8500_LOW_BAT_REG             0x03
-#define AB8500_BATT_OK_REG             0x04
-/*
- * USB/ULPI register offsets
- * Bank : 0x5
- */
-#define AB8500_USB_LINE_STAT_REG       0x80
-#define AB8500_USB_LINE_CTRL2_REG      0x82
-#define AB8500_USB_LINK1_STAT_REG      0x94
-
-/*
- * Charger / status register offfsets
- * Bank : 0x0B
- */
-#define AB8500_CH_STATUS1_REG          0x00
-#define AB8500_CH_STATUS2_REG          0x01
-#define AB8500_CH_USBCH_STAT1_REG      0x02
-#define AB8500_CH_USBCH_STAT2_REG      0x03
-#define AB8540_CH_USBCH_STAT3_REG      0x04
-#define AB8500_CH_STAT_REG             0x05
-
-/*
- * Charger / control register offfsets
- * Bank : 0x0B
- */
-#define AB8500_CH_VOLT_LVL_REG         0x40
-#define AB8500_CH_VOLT_LVL_MAX_REG     0x41  /*Only in Cut2.0*/
-#define AB8500_CH_OPT_CRNTLVL_REG      0x42
-#define AB8500_CH_OPT_CRNTLVL_MAX_REG  0x43  /*Only in Cut2.0*/
-#define AB8500_CH_WD_TIMER_REG         0x50
-#define AB8500_CHARG_WD_CTRL           0x51
-#define AB8500_BTEMP_HIGH_TH           0x52
-#define AB8500_LED_INDICATOR_PWM_CTRL  0x53
-#define AB8500_LED_INDICATOR_PWM_DUTY  0x54
-#define AB8500_BATT_OVV                        0x55
-#define AB8500_CHARGER_CTRL            0x56
-#define AB8500_BAT_CTRL_CURRENT_SOURCE 0x60  /*Only in Cut2.0*/
-
-/*
- * Charger / main control register offsets
- * Bank : 0x0B
- */
-#define AB8500_MCH_CTRL1               0x80
-#define AB8500_MCH_CTRL2               0x81
-#define AB8500_MCH_IPT_CURLVL_REG      0x82
-#define AB8500_CH_WD_REG               0x83
-
-/*
- * Charger / USB control register offsets
- * Bank : 0x0B
- */
-#define AB8500_USBCH_CTRL1_REG         0xC0
-#define AB8500_USBCH_CTRL2_REG         0xC1
-#define AB8500_USBCH_IPT_CRNTLVL_REG   0xC2
-#define AB8540_USB_PP_MODE_REG         0xC5
-#define AB8540_USB_PP_CHR_REG          0xC6
-
-/*
- * Gas Gauge register offsets
- * Bank : 0x0C
- */
-#define AB8500_GASG_CC_CTRL_REG                0x00
-#define AB8500_GASG_CC_ACCU1_REG       0x01
-#define AB8500_GASG_CC_ACCU2_REG       0x02
-#define AB8500_GASG_CC_ACCU3_REG       0x03
-#define AB8500_GASG_CC_ACCU4_REG       0x04
-#define AB8500_GASG_CC_SMPL_CNTRL_REG  0x05
-#define AB8500_GASG_CC_SMPL_CNTRH_REG  0x06
-#define AB8500_GASG_CC_SMPL_CNVL_REG   0x07
-#define AB8500_GASG_CC_SMPL_CNVH_REG   0x08
-#define AB8500_GASG_CC_CNTR_AVGOFF_REG 0x09
-#define AB8500_GASG_CC_OFFSET_REG      0x0A
-#define AB8500_GASG_CC_NCOV_ACCU       0x10
-#define AB8500_GASG_CC_NCOV_ACCU_CTRL  0x11
-#define AB8500_GASG_CC_NCOV_ACCU_LOW   0x12
-#define AB8500_GASG_CC_NCOV_ACCU_MED   0x13
-#define AB8500_GASG_CC_NCOV_ACCU_HIGH  0x14
-
-/*
- * Interrupt register offsets
- * Bank : 0x0E
- */
-#define AB8500_IT_SOURCE2_REG          0x01
-#define AB8500_IT_SOURCE21_REG         0x14
-
-/*
- * RTC register offsets
- * Bank: 0x0F
- */
-#define AB8500_RTC_BACKUP_CHG_REG      0x0C
-#define AB8500_RTC_CC_CONF_REG         0x01
-#define AB8500_RTC_CTRL_REG            0x0B
-#define AB8500_RTC_CTRL1_REG           0x11
-
-/*
- * OTP register offsets
- * Bank : 0x15
- */
-#define AB8500_OTP_CONF_15             0x0E
-
-/* GPADC constants from AB8500 spec, UM0836 */
-#define ADC_RESOLUTION                 1024
-#define ADC_CH_MAIN_MIN                        0
-#define ADC_CH_MAIN_MAX                        20030
-#define ADC_CH_VBUS_MIN                        0
-#define ADC_CH_VBUS_MAX                        20030
-#define ADC_CH_VBAT_MIN                        2300
-#define ADC_CH_VBAT_MAX                        4800
-#define ADC_CH_BKBAT_MIN               0
-#define ADC_CH_BKBAT_MAX               3200
-
-/* Main charge i/p current */
-#define MAIN_CH_IP_CUR_0P9A            0x80
-#define MAIN_CH_IP_CUR_1P0A            0x90
-#define MAIN_CH_IP_CUR_1P1A            0xA0
-#define MAIN_CH_IP_CUR_1P2A            0xB0
-#define MAIN_CH_IP_CUR_1P3A            0xC0
-#define MAIN_CH_IP_CUR_1P4A            0xD0
-#define MAIN_CH_IP_CUR_1P5A            0xE0
-
-/* ChVoltLevel */
-#define CH_VOL_LVL_3P5                 0x00
-#define CH_VOL_LVL_4P0                 0x14
-#define CH_VOL_LVL_4P05                        0x16
-#define CH_VOL_LVL_4P1                 0x1B
-#define CH_VOL_LVL_4P15                        0x20
-#define CH_VOL_LVL_4P2                 0x25
-#define CH_VOL_LVL_4P6                 0x4D
-
-/* ChOutputCurrentLevel */
-#define CH_OP_CUR_LVL_0P1              0x00
-#define CH_OP_CUR_LVL_0P2              0x01
-#define CH_OP_CUR_LVL_0P3              0x02
-#define CH_OP_CUR_LVL_0P4              0x03
-#define CH_OP_CUR_LVL_0P5              0x04
-#define CH_OP_CUR_LVL_0P6              0x05
-#define CH_OP_CUR_LVL_0P7              0x06
-#define CH_OP_CUR_LVL_0P8              0x07
-#define CH_OP_CUR_LVL_0P9              0x08
-#define CH_OP_CUR_LVL_1P4              0x0D
-#define CH_OP_CUR_LVL_1P5              0x0E
-#define CH_OP_CUR_LVL_1P6              0x0F
-#define CH_OP_CUR_LVL_2P               0x3F
-
-/* BTEMP High thermal limits */
-#define BTEMP_HIGH_TH_57_0             0x00
-#define BTEMP_HIGH_TH_52               0x01
-#define BTEMP_HIGH_TH_57_1             0x02
-#define BTEMP_HIGH_TH_62               0x03
-
-/* current is mA */
-#define USB_0P1A                       100
-#define USB_0P2A                       200
-#define USB_0P3A                       300
-#define USB_0P4A                       400
-#define USB_0P5A                       500
-
-#define LOW_BAT_3P1V                   0x20
-#define LOW_BAT_2P3V                   0x00
-#define LOW_BAT_RESET                  0x01
-#define LOW_BAT_ENABLE                 0x01
-
-/* Backup battery constants */
-#define BUP_ICH_SEL_50UA               0x00
-#define BUP_ICH_SEL_150UA              0x04
-#define BUP_ICH_SEL_300UA              0x08
-#define BUP_ICH_SEL_700UA              0x0C
-
-enum bup_vch_sel {
-       BUP_VCH_SEL_2P5V,
-       BUP_VCH_SEL_2P6V,
-       BUP_VCH_SEL_2P8V,
-       BUP_VCH_SEL_3P1V,
-       /*
-        * Note that the following 5 values 2.7v, 2.9v, 3.0v, 3.2v, 3.3v
-        * are only available on ab8540. You can't choose these 5
-        * voltage on ab8500/ab8505/ab9540.
-        */
-       BUP_VCH_SEL_2P7V,
-       BUP_VCH_SEL_2P9V,
-       BUP_VCH_SEL_3P0V,
-       BUP_VCH_SEL_3P2V,
-       BUP_VCH_SEL_3P3V,
-};
-
-#define BUP_VCH_RANGE          0x02
-#define VBUP33_VRTCN           0x01
-
-/* Battery OVV constants */
-#define BATT_OVV_ENA                   0x02
-#define BATT_OVV_TH_3P7                        0x00
-#define BATT_OVV_TH_4P75               0x01
-
-/* A value to indicate over voltage */
-#define BATT_OVV_VALUE                 4750
-
-/* VBUS OVV constants */
-#define VBUS_OVV_SELECT_MASK           0x78
-#define VBUS_OVV_SELECT_5P6V           0x00
-#define VBUS_OVV_SELECT_5P7V           0x08
-#define VBUS_OVV_SELECT_5P8V           0x10
-#define VBUS_OVV_SELECT_5P9V           0x18
-#define VBUS_OVV_SELECT_6P0V           0x20
-#define VBUS_OVV_SELECT_6P1V           0x28
-#define VBUS_OVV_SELECT_6P2V           0x30
-#define VBUS_OVV_SELECT_6P3V           0x38
-
-#define VBUS_AUTO_IN_CURR_LIM_ENA      0x04
-
-/* Fuel Gauge constants */
-#define RESET_ACCU                     0x02
-#define READ_REQ                       0x01
-#define CC_DEEP_SLEEP_ENA              0x02
-#define CC_PWR_UP_ENA                  0x01
-#define CC_SAMPLES_40                  0x28
-#define RD_NCONV_ACCU_REQ              0x01
-#define CC_CALIB                       0x08
-#define CC_INTAVGOFFSET_ENA            0x10
-#define CC_MUXOFFSET                   0x80
-#define CC_INT_CAL_N_AVG_MASK          0x60
-#define CC_INT_CAL_SAMPLES_16          0x40
-#define CC_INT_CAL_SAMPLES_8           0x20
-#define CC_INT_CAL_SAMPLES_4           0x00
-
-/* RTC constants */
-#define RTC_BUP_CH_ENA                 0x10
-
-/* BatCtrl Current Source Constants */
-#define BAT_CTRL_7U_ENA                        0x01
-#define BAT_CTRL_20U_ENA               0x02
-#define BAT_CTRL_18U_ENA               0x01
-#define BAT_CTRL_16U_ENA               0x02
-#define BAT_CTRL_CMP_ENA               0x04
-#define FORCE_BAT_CTRL_CMP_HIGH                0x08
-#define BAT_CTRL_PULL_UP_ENA           0x10
-
-/* Battery type */
-#define BATTERY_UNKNOWN                        00
-
-/* Registers for pcut feature in ab8505 and ab9540 */
-#define AB8505_RTC_PCUT_CTL_STATUS_REG 0x12
-#define AB8505_RTC_PCUT_TIME_REG       0x13
-#define AB8505_RTC_PCUT_MAX_TIME_REG   0x14
-#define AB8505_RTC_PCUT_FLAG_TIME_REG  0x15
-#define AB8505_RTC_PCUT_RESTART_REG    0x16
-#define AB8505_RTC_PCUT_DEBOUNCE_REG   0x17
-
-/* USB Power Path constants for ab8540 */
-#define BUS_VSYS_VOL_SELECT_MASK               0x06
-#define BUS_VSYS_VOL_SELECT_3P6V               0x00
-#define BUS_VSYS_VOL_SELECT_3P325V             0x02
-#define BUS_VSYS_VOL_SELECT_3P9V               0x04
-#define BUS_VSYS_VOL_SELECT_4P3V               0x06
-#define BUS_POWER_PATH_MODE_ENA                        0x01
-#define BUS_PP_PRECHG_CURRENT_MASK             0x0E
-#define BUS_POWER_PATH_PRECHG_ENA              0x01
-
-/**
- * struct res_to_temp - defines one point in a temp to res curve. To
- * be used in battery packs that combines the identification resistor with a
- * NTC resistor.
- * @temp:                      battery pack temperature in Celsius
- * @resist:                    NTC resistor net total resistance
- */
-struct res_to_temp {
-       int temp;
-       int resist;
-};
-
-/**
- * struct batres_vs_temp - defines one point in a temp vs battery internal
- * resistance curve.
- * @temp:                      battery pack temperature in Celsius
- * @resist:                    battery internal reistance in mOhm
- */
-struct batres_vs_temp {
-       int temp;
-       int resist;
-};
-
-/* Forward declaration */
-struct ab8500_fg;
-
-/**
- * struct ab8500_fg_parameters - Fuel gauge algorithm parameters, in seconds
- * if not specified
- * @recovery_sleep_timer:      Time between measurements while recovering
- * @recovery_total_time:       Total recovery time
- * @init_timer:                        Measurement interval during startup
- * @init_discard_time:         Time we discard voltage measurement at startup
- * @init_total_time:           Total init time during startup
- * @high_curr_time:            Time current has to be high to go to recovery
- * @accu_charging:             FG accumulation time while charging
- * @accu_high_curr:            FG accumulation time in high current mode
- * @high_curr_threshold:       High current threshold, in mA
- * @lowbat_threshold:          Low battery threshold, in mV
- * @battok_falling_th_sel0     Threshold in mV for battOk signal sel0
- *                             Resolution in 50 mV step.
- * @battok_raising_th_sel1     Threshold in mV for battOk signal sel1
- *                             Resolution in 50 mV step.
- * @user_cap_limit             Capacity reported from user must be within this
- *                             limit to be considered as sane, in percentage
- *                             points.
- * @maint_thres                        This is the threshold where we stop reporting
- *                             battery full while in maintenance, in per cent
- * @pcut_enable:                       Enable power cut feature in ab8505
- * @pcut_max_time:             Max time threshold
- * @pcut_flag_time:            Flagtime threshold
- * @pcut_max_restart:          Max number of restarts
- * @pcut_debunce_time: Sets battery debounce time
- */
-struct ab8500_fg_parameters {
-       int recovery_sleep_timer;
-       int recovery_total_time;
-       int init_timer;
-       int init_discard_time;
-       int init_total_time;
-       int high_curr_time;
-       int accu_charging;
-       int accu_high_curr;
-       int high_curr_threshold;
-       int lowbat_threshold;
-       int battok_falling_th_sel0;
-       int battok_raising_th_sel1;
-       int user_cap_limit;
-       int maint_thres;
-       bool pcut_enable;
-       u8 pcut_max_time;
-       u8 pcut_flag_time;
-       u8 pcut_max_restart;
-       u8 pcut_debunce_time;
-};
-
-/**
- * struct ab8500_charger_maximization - struct used by the board config.
- * @use_maxi:          Enable maximization for this battery type
- * @maxi_chg_curr:     Maximum charger current allowed
- * @maxi_wait_cycles:  cycles to wait before setting charger current
- * @charger_curr_step  delta between two charger current settings (mA)
- */
-struct ab8500_maxim_parameters {
-       bool ena_maxi;
-       int chg_curr;
-       int wait_cycles;
-       int charger_curr_step;
-};
-
-/**
- * struct ab8500_bm_capacity_levels - ab8500 capacity level data
- * @critical:          critical capacity level in percent
- * @low:               low capacity level in percent
- * @normal:            normal capacity level in percent
- * @high:              high capacity level in percent
- * @full:              full capacity level in percent
- */
-struct ab8500_bm_capacity_levels {
-       int critical;
-       int low;
-       int normal;
-       int high;
-       int full;
-};
-
-/**
- * struct ab8500_bm_charger_parameters - Charger specific parameters
- * @usb_volt_max:      maximum allowed USB charger voltage in mV
- * @usb_curr_max:      maximum allowed USB charger current in mA
- * @ac_volt_max:       maximum allowed AC charger voltage in mV
- * @ac_curr_max:       maximum allowed AC charger current in mA
- */
-struct ab8500_bm_charger_parameters {
-       int usb_volt_max;
-       int usb_curr_max;
-       int ac_volt_max;
-       int ac_curr_max;
-};
-
-/**
- * struct ab8500_bm_data - ab8500 battery management data
- * @temp_under         under this temp, charging is stopped
- * @temp_low           between this temp and temp_under charging is reduced
- * @temp_high          between this temp and temp_over charging is reduced
- * @temp_over          over this temp, charging is stopped
- * @temp_interval_chg  temperature measurement interval in s when charging
- * @temp_interval_nochg        temperature measurement interval in s when not charging
- * @main_safety_tmr_h  safety timer for main charger
- * @usb_safety_tmr_h   safety timer for usb charger
- * @bkup_bat_v         voltage which we charge the backup battery with
- * @bkup_bat_i         current which we charge the backup battery with
- * @no_maintenance     indicates that maintenance charging is disabled
- * @capacity_scaling    indicates whether capacity scaling is to be used
- * @adc_therm          placement of thermistor, batctrl or battemp adc
- * @chg_unknown_bat    flag to enable charging of unknown batteries
- * @enable_overshoot   flag to enable VBAT overshoot control
- * @fg_res             resistance of FG resistor in 0.1mOhm
- * @n_btypes           number of elements in array bat_type
- * @batt_id            index of the identified battery in array bat_type
- * @interval_charging  charge alg cycle period time when charging (sec)
- * @interval_not_charging charge alg cycle period time when not charging (sec)
- * @temp_hysteresis    temperature hysteresis
- * @gnd_lift_resistance        Battery ground to phone ground resistance (mOhm)
- * @maxi:              maximization parameters
- * @cap_levels         capacity in percent for the different capacity levels
- * @bat_type           table of supported battery types
- * @chg_params         charger parameters
- * @fg_params          fuel gauge parameters
- */
-struct ab8500_bm_data {
-       int temp_under;
-       int temp_low;
-       int temp_high;
-       int temp_over;
-       int temp_interval_chg;
-       int temp_interval_nochg;
-       int main_safety_tmr_h;
-       int usb_safety_tmr_h;
-       int bkup_bat_v;
-       int bkup_bat_i;
-       bool no_maintenance;
-       bool capacity_scaling;
-       bool chg_unknown_bat;
-       bool enable_overshoot;
-       enum abx500_adc_therm adc_therm;
-       int fg_res;
-       int n_btypes;
-       int batt_id;
-       int interval_charging;
-       int interval_not_charging;
-       int temp_hysteresis;
-       int gnd_lift_resistance;
-       const struct ab8500_maxim_parameters *maxi;
-       const struct ab8500_bm_capacity_levels *cap_levels;
-       const struct ab8500_bm_charger_parameters *chg_params;
-       const struct ab8500_fg_parameters *fg_params;
-};
-
-struct ab8500_btemp;
-struct ab8500_gpadc;
-struct ab8500_fg;
-
-#ifdef CONFIG_AB8500_BM
-extern struct abx500_bm_data ab8500_bm_data;
-
-void ab8500_charger_usb_state_changed(u8 bm_usb_state, u16 mA);
-struct ab8500_btemp *ab8500_btemp_get(void);
-int ab8500_btemp_get_batctrl_temp(struct ab8500_btemp *btemp);
-int ab8500_btemp_get_temp(struct ab8500_btemp *btemp);
-struct ab8500_fg *ab8500_fg_get(void);
-int ab8500_fg_inst_curr_blocking(struct ab8500_fg *dev);
-int ab8500_fg_inst_curr_start(struct ab8500_fg *di);
-int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res);
-int ab8500_fg_inst_curr_started(struct ab8500_fg *di);
-int ab8500_fg_inst_curr_done(struct ab8500_fg *di);
-
-#else
-static struct abx500_bm_data ab8500_bm_data;
-#endif
-#endif /* _AB8500_BM_H */
diff --git a/include/linux/mfd/abx500/ux500_chargalg.h b/include/linux/mfd/abx500/ux500_chargalg.h
deleted file mode 100644 (file)
index 9b97d28..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (C) ST-Ericsson SA 2012
- * Author: Johan Gardsmark <johan.gardsmark@stericsson.com> for ST-Ericsson.
- */
-
-#ifndef _UX500_CHARGALG_H
-#define _UX500_CHARGALG_H
-
-#include <linux/power_supply.h>
-
-/*
- * Valid only for supplies of type:
- * - POWER_SUPPLY_TYPE_MAINS,
- * - POWER_SUPPLY_TYPE_USB,
- * because only them store as drv_data pointer to struct ux500_charger.
- */
-#define psy_to_ux500_charger(x) power_supply_get_drvdata(psy)
-
-/* Forward declaration */
-struct ux500_charger;
-
-struct ux500_charger_ops {
-       int (*enable) (struct ux500_charger *, int, int, int);
-       int (*check_enable) (struct ux500_charger *, int, int);
-       int (*kick_wd) (struct ux500_charger *);
-       int (*update_curr) (struct ux500_charger *, int);
-};
-
-/**
- * struct ux500_charger - power supply ux500 charger sub class
- * @psy                        power supply base class
- * @ops                        ux500 charger operations
- * @max_out_volt       maximum output charger voltage in mV
- * @max_out_curr       maximum output charger current in mA
- * @enabled            indicates if this charger is used or not
- * @external           external charger unit (pm2xxx)
- */
-struct ux500_charger {
-       struct power_supply *psy;
-       struct ux500_charger_ops ops;
-       int max_out_volt;
-       int max_out_curr;
-       int wdt_refresh;
-       bool enabled;
-       bool external;
-};
-
-extern struct blocking_notifier_head charger_notifier_list;
-
-#endif
diff --git a/include/linux/mfd/atc260x/atc2603c.h b/include/linux/mfd/atc260x/atc2603c.h
new file mode 100644 (file)
index 0000000..07ac640
--- /dev/null
@@ -0,0 +1,281 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * ATC2603C PMIC register definitions
+ *
+ * Copyright (C) 2020 Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
+ */
+
+#ifndef __LINUX_MFD_ATC260X_ATC2603C_H
+#define __LINUX_MFD_ATC260X_ATC2603C_H
+
+enum atc2603c_irq_def {
+       ATC2603C_IRQ_AUDIO = 0,
+       ATC2603C_IRQ_OV,
+       ATC2603C_IRQ_OC,
+       ATC2603C_IRQ_OT,
+       ATC2603C_IRQ_UV,
+       ATC2603C_IRQ_ALARM,
+       ATC2603C_IRQ_ONOFF,
+       ATC2603C_IRQ_SGPIO,
+       ATC2603C_IRQ_IR,
+       ATC2603C_IRQ_REMCON,
+       ATC2603C_IRQ_POWER_IN,
+};
+
+/* PMU Registers */
+#define ATC2603C_PMU_SYS_CTL0                  0x00
+#define ATC2603C_PMU_SYS_CTL1                  0x01
+#define ATC2603C_PMU_SYS_CTL2                  0x02
+#define ATC2603C_PMU_SYS_CTL3                  0x03
+#define ATC2603C_PMU_SYS_CTL4                  0x04
+#define ATC2603C_PMU_SYS_CTL5                  0x05
+#define ATC2603C_PMU_SYS_CTL6                  0x06
+#define ATC2603C_PMU_SYS_CTL7                  0x07
+#define ATC2603C_PMU_SYS_CTL8                  0x08
+#define ATC2603C_PMU_SYS_CTL9                  0x09
+#define ATC2603C_PMU_BAT_CTL0                  0x0A
+#define ATC2603C_PMU_BAT_CTL1                  0x0B
+#define ATC2603C_PMU_VBUS_CTL0                 0x0C
+#define ATC2603C_PMU_VBUS_CTL1                 0x0D
+#define ATC2603C_PMU_WALL_CTL0                 0x0E
+#define ATC2603C_PMU_WALL_CTL1                 0x0F
+#define ATC2603C_PMU_SYS_PENDING               0x10
+#define ATC2603C_PMU_DC1_CTL0                  0x11
+#define ATC2603C_PMU_DC1_CTL1                  0x12 // Undocumented
+#define ATC2603C_PMU_DC1_CTL2                  0x13 // Undocumented
+#define ATC2603C_PMU_DC2_CTL0                  0x14
+#define ATC2603C_PMU_DC2_CTL1                  0x15 // Undocumented
+#define ATC2603C_PMU_DC2_CTL2                  0x16 // Undocumented
+#define ATC2603C_PMU_DC3_CTL0                  0x17
+#define ATC2603C_PMU_DC3_CTL1                  0x18 // Undocumented
+#define ATC2603C_PMU_DC3_CTL2                  0x19 // Undocumented
+#define ATC2603C_PMU_DC4_CTL0                  0x1A // Undocumented
+#define ATC2603C_PMU_DC4_CTL1                  0x1B // Undocumented
+#define ATC2603C_PMU_DC5_CTL0                  0x1C // Undocumented
+#define ATC2603C_PMU_DC5_CTL1                  0x1D // Undocumented
+#define ATC2603C_PMU_LDO1_CTL                  0x1E
+#define ATC2603C_PMU_LDO2_CTL                  0x1F
+#define ATC2603C_PMU_LDO3_CTL                  0x20
+#define ATC2603C_PMU_LDO4_CTL                  0x21 // Undocumented
+#define ATC2603C_PMU_LDO5_CTL                  0x22
+#define ATC2603C_PMU_LDO6_CTL                  0x23
+#define ATC2603C_PMU_LDO7_CTL                  0x24
+#define ATC2603C_PMU_LDO8_CTL                  0x25 // Undocumented
+#define ATC2603C_PMU_LDO9_CTL                  0x26 // Undocumented
+#define ATC2603C_PMU_LDO10_CTL                 0x27 // Undocumented
+#define ATC2603C_PMU_LDO11_CTL                 0x28
+#define ATC2603C_PMU_SWITCH_CTL                        0x29
+#define ATC2603C_PMU_OV_CTL0                   0x2A
+#define ATC2603C_PMU_OV_CTL1                   0x2B
+#define ATC2603C_PMU_OV_STATUS                 0x2C
+#define ATC2603C_PMU_OV_EN                     0x2D
+#define ATC2603C_PMU_OV_INT_EN                 0x2E
+#define ATC2603C_PMU_OC_CTL                    0x2F
+#define ATC2603C_PMU_OC_STATUS                 0x30
+#define ATC2603C_PMU_OC_EN                     0x31
+#define ATC2603C_PMU_OC_INT_EN                 0x32
+#define ATC2603C_PMU_UV_CTL0                   0x33
+#define ATC2603C_PMU_UV_CTL1                   0x34
+#define ATC2603C_PMU_UV_STATUS                 0x35
+#define ATC2603C_PMU_UV_EN                     0x36
+#define ATC2603C_PMU_UV_INT_EN                 0x37
+#define ATC2603C_PMU_OT_CTL                    0x38
+#define ATC2603C_PMU_CHARGER_CTL0              0x39
+#define ATC2603C_PMU_CHARGER_CTL1              0x3A
+#define ATC2603C_PMU_CHARGER_CTL2              0x3B
+#define ATC2603C_PMU_BAKCHARGER_CTL            0x3C // Undocumented
+#define ATC2603C_PMU_APDS_CTL                  0x3D
+#define ATC2603C_PMU_AUXADC_CTL0               0x3E
+#define ATC2603C_PMU_AUXADC_CTL1               0x3F
+#define ATC2603C_PMU_BATVADC                   0x40
+#define ATC2603C_PMU_BATIADC                   0x41
+#define ATC2603C_PMU_WALLVADC                  0x42
+#define ATC2603C_PMU_WALLIADC                  0x43
+#define ATC2603C_PMU_VBUSVADC                  0x44
+#define ATC2603C_PMU_VBUSIADC                  0x45
+#define ATC2603C_PMU_SYSPWRADC                 0x46
+#define ATC2603C_PMU_REMCONADC                 0x47
+#define ATC2603C_PMU_SVCCADC                   0x48
+#define ATC2603C_PMU_CHGIADC                   0x49
+#define ATC2603C_PMU_IREFADC                   0x4A
+#define ATC2603C_PMU_BAKBATADC                 0x4B
+#define ATC2603C_PMU_ICTEMPADC                 0x4C
+#define ATC2603C_PMU_AUXADC0                   0x4D
+#define ATC2603C_PMU_AUXADC1                   0x4E
+#define ATC2603C_PMU_AUXADC2                   0x4F
+#define        ATC2603C_PMU_ICMADC                     0x50
+#define ATC2603C_PMU_BDG_CTL                   0x51 // Undocumented
+#define ATC2603C_RTC_CTL                       0x52
+#define ATC2603C_RTC_MSALM                     0x53
+#define ATC2603C_RTC_HALM                      0x54
+#define ATC2603C_RTC_YMDALM                    0x55
+#define ATC2603C_RTC_MS                                0x56
+#define ATC2603C_RTC_H                         0x57
+#define ATC2603C_RTC_DC                                0x58
+#define ATC2603C_RTC_YMD                       0x59
+#define ATC2603C_EFUSE_DAT                     0x5A // Undocumented
+#define ATC2603C_EFUSECRTL1                    0x5B // Undocumented
+#define ATC2603C_EFUSECRTL2                    0x5C // Undocumented
+#define ATC2603C_PMU_FW_USE0                   0x5D // Undocumented
+#define ATC2603C_PMU_FW_USE1                   0x5E // Undocumented
+#define ATC2603C_PMU_FW_USE2                   0x5F // Undocumented
+#define ATC2603C_PMU_FW_USE3                   0x60 // Undocumented
+#define ATC2603C_PMU_FW_USE4                   0x61 // Undocumented
+#define ATC2603C_PMU_ABNORMAL_STATUS           0x62
+#define ATC2603C_PMU_WALL_APDS_CTL             0x63
+#define ATC2603C_PMU_REMCON_CTL0               0x64
+#define ATC2603C_PMU_REMCON_CTL1               0x65
+#define ATC2603C_PMU_MUX_CTL0                  0x66
+#define ATC2603C_PMU_SGPIO_CTL0                        0x67
+#define ATC2603C_PMU_SGPIO_CTL1                        0x68
+#define ATC2603C_PMU_SGPIO_CTL2                        0x69
+#define ATC2603C_PMU_SGPIO_CTL3                        0x6A
+#define ATC2603C_PMU_SGPIO_CTL4                        0x6B
+#define ATC2603C_PWMCLK_CTL                    0x6C
+#define ATC2603C_PWM0_CTL                      0x6D
+#define ATC2603C_PWM1_CTL                      0x6E
+#define ATC2603C_PMU_ADC_DBG0                  0x70
+#define ATC2603C_PMU_ADC_DBG1                  0x71
+#define ATC2603C_PMU_ADC_DBG2                  0x72
+#define ATC2603C_PMU_ADC_DBG3                  0x73
+#define ATC2603C_PMU_ADC_DBG4                  0x74
+#define ATC2603C_IRC_CTL                       0x80
+#define ATC2603C_IRC_STAT                      0x81
+#define ATC2603C_IRC_CC                                0x82
+#define ATC2603C_IRC_KDC                       0x83
+#define ATC2603C_IRC_WK                                0x84
+#define ATC2603C_IRC_RCC                       0x85
+#define ATC2603C_IRC_FILTER                    0x86
+
+/* AUDIO_OUT Registers */
+#define ATC2603C_AUDIOINOUT_CTL                        0xA0
+#define ATC2603C_AUDIO_DEBUGOUTCTL             0xA1
+#define ATC2603C_DAC_DIGITALCTL                        0xA2
+#define ATC2603C_DAC_VOLUMECTL0                        0xA3
+#define ATC2603C_DAC_ANALOG0                   0xA4
+#define ATC2603C_DAC_ANALOG1                   0xA5
+#define ATC2603C_DAC_ANALOG2                   0xA6
+#define ATC2603C_DAC_ANALOG3                   0xA7
+
+/* AUDIO_IN Registers */
+#define ATC2603C_ADC_DIGITALCTL                        0xA8
+#define ATC2603C_ADC_HPFCTL                    0xA9
+#define ATC2603C_ADC_CTL                       0xAA
+#define ATC2603C_AGC_CTL0                      0xAB
+#define ATC2603C_AGC_CTL1                      0xAC // Undocumented
+#define ATC2603C_AGC_CTL2                      0xAD
+#define ATC2603C_ADC_ANALOG0                   0xAE
+#define ATC2603C_ADC_ANALOG1                   0xAF
+
+/* PCM_IF Registers */
+#define ATC2603C_PCM0_CTL                      0xB0 // Undocumented
+#define ATC2603C_PCM1_CTL                      0xB1 // Undocumented
+#define ATC2603C_PCM2_CTL                      0xB2 // Undocumented
+#define ATC2603C_PCMIF_CTL                     0xB3 // Undocumented
+
+/* CMU_CONTROL Registers */
+#define ATC2603C_CMU_DEVRST                    0xC1 // Undocumented
+
+/* INTS Registers */
+#define ATC2603C_INTS_PD                       0xC8
+#define ATC2603C_INTS_MSK                      0xC9
+
+/* MFP Registers */
+#define ATC2603C_MFP_CTL                       0xD0
+#define ATC2603C_PAD_VSEL                      0xD1 // Undocumented
+#define ATC2603C_GPIO_OUTEN                    0xD2
+#define ATC2603C_GPIO_INEN                     0xD3
+#define ATC2603C_GPIO_DAT                      0xD4
+#define ATC2603C_PAD_DRV                       0xD5
+#define ATC2603C_PAD_EN                                0xD6
+#define ATC2603C_DEBUG_SEL                     0xD7 // Undocumented
+#define ATC2603C_DEBUG_IE                      0xD8 // Undocumented
+#define ATC2603C_DEBUG_OE                      0xD9 // Undocumented
+#define ATC2603C_BIST_START                    0x0A // Undocumented
+#define ATC2603C_BIST_RESULT                   0x0B // Undocumented
+#define ATC2603C_CHIP_VER                      0xDC
+
+/* TWSI Registers */
+#define ATC2603C_SADDR                         0xFF
+
+/* PMU_SYS_CTL0 Register Mask Bits */
+#define ATC2603C_PMU_SYS_CTL0_IR_WK_EN                 BIT(5)
+#define ATC2603C_PMU_SYS_CTL0_RESET_WK_EN              BIT(6)
+#define ATC2603C_PMU_SYS_CTL0_HDSW_WK_EN               BIT(7)
+#define ATC2603C_PMU_SYS_CTL0_ALARM_WK_EN              BIT(8)
+#define ATC2603C_PMU_SYS_CTL0_REM_CON_WK_EN            BIT(9)
+#define ATC2603C_PMU_SYS_CTL0_RESTART_EN               BIT(10)
+#define ATC2603C_PMU_SYS_CTL0_SGPIOIRQ_WK_EN           BIT(11)
+#define ATC2603C_PMU_SYS_CTL0_ONOFF_SHORT_WK_EN                BIT(12)
+#define ATC2603C_PMU_SYS_CTL0_ONOFF_LONG_WK_EN         BIT(13)
+#define ATC2603C_PMU_SYS_CTL0_WALL_WK_EN               BIT(14)
+#define ATC2603C_PMU_SYS_CTL0_USB_WK_EN                        BIT(15)
+#define ATC2603C_PMU_SYS_CTL0_WK_ALL                   (GENMASK(15, 5) & (~BIT(10)))
+
+/* PMU_SYS_CTL1 Register Mask Bits */
+#define ATC2603C_PMU_SYS_CTL1_EN_S1                    BIT(0)
+#define ATC2603C_PMU_SYS_CTL1_LB_S4_EN                 BIT(2)
+#define ATC2603C_PMU_SYS_CTL1_LB_S4                    GENMASK(4, 3)
+#define ATC2603C_PMU_SYS_CTL1_LB_S4_3_1V               BIT(4)
+#define ATC2603C_PMU_SYS_CTL1_IR_WK_FLAG               BIT(5)
+#define ATC2603C_PMU_SYS_CTL1_RESET_WK_FLAG            BIT(6)
+#define ATC2603C_PMU_SYS_CTL1_HDSW_WK_FLAG             BIT(7)
+#define ATC2603C_PMU_SYS_CTL1_ALARM_WK_FLAG            BIT(8)
+#define ATC2603C_PMU_SYS_CTL1_REM_CON_WK_FLAG          BIT(9)
+#define ATC2603C_PMU_SYS_CTL1_ONOFF_PRESS_RESET_IRQ_PD BIT(10)
+#define ATC2603C_PMU_SYS_CTL1_SGPIOIRQ_WK_FLAG         BIT(11)
+#define ATC2603C_PMU_SYS_CTL1_ONOFF_SHORT_WK_FLAG      BIT(12)
+#define ATC2603C_PMU_SYS_CTL1_ONOFF_LONG_WK_FLAG       BIT(13)
+#define ATC2603C_PMU_SYS_CTL1_WALL_WK_FLAG             BIT(14)
+#define ATC2603C_PMU_SYS_CTL1_USB_WK_FLAG              BIT(15)
+
+/* PMU_SYS_CTL2 Register Mask Bits */
+#define ATC2603C_PMU_SYS_CTL2_PMU_A_EN                 BIT(0)
+#define ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_INT_EN       BIT(1)
+#define ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_PD           BIT(2)
+#define ATC2603C_PMU_SYS_CTL2_S2TIMER                  GENMASK(5, 3)
+#define ATC2603C_PMU_SYS_CTL2_S2_TIMER_EN              BIT(6)
+#define ATC2603C_PMU_SYS_CTL2_ONOFF_RESET_TIME_SEL     GENMASK(8, 7)
+#define ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_RESET_EN     BIT(9)
+#define ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_TIME         GENMASK(11, 10)
+#define ATC2603C_PMU_SYS_CTL2_ONOFF_INT_EN             BIT(12)
+#define ATC2603C_PMU_SYS_CTL2_ONOFF_LONG_PRESS         BIT(13)
+#define ATC2603C_PMU_SYS_CTL2_ONOFF_SHORT_PRESS                BIT(14)
+#define ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS              BIT(15)
+
+/* PMU_SYS_CTL3 Register Mask Bits */
+#define ATC2603C_PMU_SYS_CTL3_S2S3TOS1_TIMER           GENMASK(8, 7)
+#define ATC2603C_PMU_SYS_CTL3_S2S3TOS1_TIMER_EN                BIT(9)
+#define ATC2603C_PMU_SYS_CTL3_S3_TIMER                 GENMASK(12, 10)
+#define ATC2603C_PMU_SYS_CTL3_S3_TIMER_EN              BIT(13)
+#define ATC2603C_PMU_SYS_CTL3_EN_S3                    BIT(14)
+#define ATC2603C_PMU_SYS_CTL3_EN_S2                    BIT(15)
+
+/* PMU_SYS_CTL5 Register Mask Bits */
+#define ATC2603C_PMU_SYS_CTL5_WALLWKDTEN               BIT(7)
+#define ATC2603C_PMU_SYS_CTL5_VBUSWKDTEN               BIT(8)
+#define ATC2603C_PMU_SYS_CTL5_REMCON_DECT_EN           BIT(9)
+#define ATC2603C_PMU_SYS_CTL5_ONOFF_8S_SEL             BIT(10)
+
+/* INTS_MSK Register Mask Bits */
+#define ATC2603C_INTS_MSK_AUDIO                                BIT(0)
+#define ATC2603C_INTS_MSK_OV                           BIT(1)
+#define ATC2603C_INTS_MSK_OC                           BIT(2)
+#define ATC2603C_INTS_MSK_OT                           BIT(3)
+#define ATC2603C_INTS_MSK_UV                           BIT(4)
+#define ATC2603C_INTS_MSK_ALARM                                BIT(5)
+#define ATC2603C_INTS_MSK_ONOFF                                BIT(6)
+#define ATC2603C_INTS_MSK_SGPIO                                BIT(7)
+#define ATC2603C_INTS_MSK_IR                           BIT(8)
+#define ATC2603C_INTS_MSK_REMCON                       BIT(9)
+#define ATC2603C_INTS_MSK_POWERIN                      BIT(10)
+
+/* CMU_DEVRST Register Mask Bits */
+#define ATC2603C_CMU_DEVRST_MFP                                BIT(1)
+#define ATC2603C_CMU_DEVRST_INTS                       BIT(2)
+#define ATC2603C_CMU_DEVRST_AUDIO                      BIT(4)
+
+/* PAD_EN Register Mask Bits */
+#define ATC2603C_PAD_EN_EXTIRQ                         BIT(0)
+
+#endif /* __LINUX_MFD_ATC260X_ATC2603C_H */
diff --git a/include/linux/mfd/atc260x/atc2609a.h b/include/linux/mfd/atc260x/atc2609a.h
new file mode 100644 (file)
index 0000000..b957d7b
--- /dev/null
@@ -0,0 +1,308 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * ATC2609A PMIC register definitions
+ *
+ * Copyright (C) 2019 Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ */
+
+#ifndef __LINUX_MFD_ATC260X_ATC2609A_H
+#define __LINUX_MFD_ATC260X_ATC2609A_H
+
+enum atc2609a_irq_def {
+       ATC2609A_IRQ_AUDIO = 0,
+       ATC2609A_IRQ_OV,
+       ATC2609A_IRQ_OC,
+       ATC2609A_IRQ_OT,
+       ATC2609A_IRQ_UV,
+       ATC2609A_IRQ_ALARM,
+       ATC2609A_IRQ_ONOFF,
+       ATC2609A_IRQ_WKUP,
+       ATC2609A_IRQ_IR,
+       ATC2609A_IRQ_REMCON,
+       ATC2609A_IRQ_POWER_IN,
+};
+
+/* PMU Registers */
+#define ATC2609A_PMU_SYS_CTL0                  0x00
+#define ATC2609A_PMU_SYS_CTL1                  0x01
+#define ATC2609A_PMU_SYS_CTL2                  0x02
+#define ATC2609A_PMU_SYS_CTL3                  0x03
+#define ATC2609A_PMU_SYS_CTL4                  0x04
+#define ATC2609A_PMU_SYS_CTL5                  0x05
+#define ATC2609A_PMU_SYS_CTL6                  0x06
+#define ATC2609A_PMU_SYS_CTL7                  0x07
+#define ATC2609A_PMU_SYS_CTL8                  0x08
+#define ATC2609A_PMU_SYS_CTL9                  0x09
+#define ATC2609A_PMU_BAT_CTL0                  0x0A
+#define ATC2609A_PMU_BAT_CTL1                  0x0B
+#define ATC2609A_PMU_VBUS_CTL0                 0x0C
+#define ATC2609A_PMU_VBUS_CTL1                 0x0D
+#define ATC2609A_PMU_WALL_CTL0                 0x0E
+#define ATC2609A_PMU_WALL_CTL1                 0x0F
+#define ATC2609A_PMU_SYS_PENDING               0x10
+#define ATC2609A_PMU_APDS_CTL0                 0x11
+#define ATC2609A_PMU_APDS_CTL1                 0x12
+#define ATC2609A_PMU_APDS_CTL2                 0x13
+#define ATC2609A_PMU_CHARGER_CTL               0x14
+#define ATC2609A_PMU_BAKCHARGER_CTL            0x15
+#define ATC2609A_PMU_SWCHG_CTL0                        0x16
+#define ATC2609A_PMU_SWCHG_CTL1                        0x17
+#define ATC2609A_PMU_SWCHG_CTL2                        0x18
+#define ATC2609A_PMU_SWCHG_CTL3                        0x19
+#define ATC2609A_PMU_SWCHG_CTL4                        0x1A
+#define ATC2609A_PMU_DC_OSC                    0x1B
+#define ATC2609A_PMU_DC0_CTL0                  0x1C
+#define ATC2609A_PMU_DC0_CTL1                  0x1D
+#define ATC2609A_PMU_DC0_CTL2                  0x1E
+#define ATC2609A_PMU_DC0_CTL3                  0x1F
+#define ATC2609A_PMU_DC0_CTL4                  0x20
+#define ATC2609A_PMU_DC0_CTL5                  0x21
+#define ATC2609A_PMU_DC0_CTL6                  0x22
+#define ATC2609A_PMU_DC1_CTL0                  0x23
+#define ATC2609A_PMU_DC1_CTL1                  0x24
+#define ATC2609A_PMU_DC1_CTL2                  0x25
+#define ATC2609A_PMU_DC1_CTL3                  0x26
+#define ATC2609A_PMU_DC1_CTL4                  0x27
+#define ATC2609A_PMU_DC1_CTL5                  0x28
+#define ATC2609A_PMU_DC1_CTL6                  0x29
+#define ATC2609A_PMU_DC2_CTL0                  0x2A
+#define ATC2609A_PMU_DC2_CTL1                  0x2B
+#define ATC2609A_PMU_DC2_CTL2                  0x2C
+#define ATC2609A_PMU_DC2_CTL3                  0x2D
+#define ATC2609A_PMU_DC2_CTL4                  0x2E
+#define ATC2609A_PMU_DC2_CTL5                  0x2F
+#define ATC2609A_PMU_DC2_CTL6                  0x30
+#define ATC2609A_PMU_DC3_CTL0                  0x31
+#define ATC2609A_PMU_DC3_CTL1                  0x32
+#define ATC2609A_PMU_DC3_CTL2                  0x33
+#define ATC2609A_PMU_DC3_CTL3                  0x34
+#define ATC2609A_PMU_DC3_CTL4                  0x35
+#define ATC2609A_PMU_DC3_CTL5                  0x36
+#define ATC2609A_PMU_DC3_CTL6                  0x37
+#define ATC2609A_PMU_DC_ZR                     0x38
+#define ATC2609A_PMU_LDO0_CTL0                 0x39
+#define ATC2609A_PMU_LDO0_CTL1                 0x3A
+#define ATC2609A_PMU_LDO1_CTL0                 0x3B
+#define ATC2609A_PMU_LDO1_CTL1                 0x3C
+#define ATC2609A_PMU_LDO2_CTL0                 0x3D
+#define ATC2609A_PMU_LDO2_CTL1                 0x3E
+#define ATC2609A_PMU_LDO3_CTL0                 0x3F
+#define ATC2609A_PMU_LDO3_CTL1                 0x40
+#define ATC2609A_PMU_LDO4_CTL0                 0x41
+#define ATC2609A_PMU_LDO4_CTL1                 0x42
+#define ATC2609A_PMU_LDO5_CTL0                 0x43
+#define ATC2609A_PMU_LDO5_CTL1                 0x44
+#define ATC2609A_PMU_LDO6_CTL0                 0x45
+#define ATC2609A_PMU_LDO6_CTL1                 0x46
+#define ATC2609A_PMU_LDO7_CTL0                 0x47
+#define ATC2609A_PMU_LDO7_CTL1                 0x48
+#define ATC2609A_PMU_LDO8_CTL0                 0x49
+#define ATC2609A_PMU_LDO8_CTL1                 0x4A
+#define ATC2609A_PMU_LDO9_CTL                  0x4B
+#define ATC2609A_PMU_OV_INT_EN                 0x4C
+#define ATC2609A_PMU_OV_STATUS                 0x4D
+#define ATC2609A_PMU_UV_INT_EN                 0x4E
+#define ATC2609A_PMU_UV_STATUS                 0x4F
+#define ATC2609A_PMU_OC_INT_EN                 0x50
+#define ATC2609A_PMU_OC_STATUS                 0x51
+#define ATC2609A_PMU_OT_CTL                    0x52
+#define ATC2609A_PMU_CM_CTL0                   0x53
+#define ATC2609A_PMU_FW_USE0                   0x54
+#define ATC2609A_PMU_FW_USE1                   0x55
+#define ATC2609A_PMU_ADC12B_I                  0x56
+#define ATC2609A_PMU_ADC12B_V                  0x57
+#define ATC2609A_PMU_ADC12B_DUMMY              0x58
+#define ATC2609A_PMU_AUXADC_CTL0               0x59
+#define ATC2609A_PMU_AUXADC_CTL1               0x5A
+#define ATC2609A_PMU_BATVADC                   0x5B
+#define ATC2609A_PMU_BATIADC                   0x5C
+#define ATC2609A_PMU_WALLVADC                  0x5D
+#define ATC2609A_PMU_WALLIADC                  0x5E
+#define ATC2609A_PMU_VBUSVADC                  0x5F
+#define ATC2609A_PMU_VBUSIADC                  0x60
+#define ATC2609A_PMU_SYSPWRADC                 0x61
+#define ATC2609A_PMU_REMCONADC                 0x62
+#define ATC2609A_PMU_SVCCADC                   0x63
+#define ATC2609A_PMU_CHGIADC                   0x64
+#define ATC2609A_PMU_IREFADC                   0x65
+#define ATC2609A_PMU_BAKBATADC                 0x66
+#define ATC2609A_PMU_ICTEMPADC                 0x67
+#define ATC2609A_PMU_AUXADC0                   0x68
+#define ATC2609A_PMU_AUXADC1                   0x69
+#define ATC2609A_PMU_AUXADC2                   0x6A
+#define ATC2609A_PMU_AUXADC3                   0x6B
+#define ATC2609A_PMU_ICTEMPADC_ADJ             0x6C
+#define ATC2609A_PMU_BDG_CTL                   0x6D
+#define ATC2609A_RTC_CTL                       0x6E
+#define ATC2609A_RTC_MSALM                     0x6F
+#define ATC2609A_RTC_HALM                      0x70
+#define ATC2609A_RTC_YMDALM                    0x71
+#define ATC2609A_RTC_MS                                0x72
+#define ATC2609A_RTC_H                         0x73
+#define ATC2609A_RTC_DC                                0x74
+#define ATC2609A_RTC_YMD                       0x75
+#define ATC2609A_EFUSE_DAT                     0x76
+#define ATC2609A_EFUSECRTL1                    0x77
+#define ATC2609A_EFUSECRTL2                    0x78
+#define ATC2609A_PMU_DC4_CTL0                  0x79
+#define ATC2609A_PMU_DC4_CTL1                  0x7A
+#define ATC2609A_PMU_DC4_CTL2                  0x7B
+#define ATC2609A_PMU_DC4_CTL3                  0x7C
+#define ATC2609A_PMU_DC4_CTL4                  0x7D
+#define ATC2609A_PMU_DC4_CTL5                  0x7E
+#define ATC2609A_PMU_DC4_CTL6                  0x7F
+#define ATC2609A_PMU_PWR_STATUS                        0x80
+#define ATC2609A_PMU_S2_PWR                    0x81
+#define ATC2609A_CLMT_CTL0                     0x82
+#define ATC2609A_CLMT_DATA0                    0x83
+#define ATC2609A_CLMT_DATA1                    0x84
+#define ATC2609A_CLMT_DATA2                    0x85
+#define ATC2609A_CLMT_DATA3                    0x86
+#define ATC2609A_CLMT_ADD0                     0x87
+#define ATC2609A_CLMT_ADD1                     0x88
+#define ATC2609A_CLMT_OCV_TABLE                        0x89
+#define ATC2609A_CLMT_R_TABLE                  0x8A
+#define ATC2609A_PMU_PWRON_CTL0                        0x8D
+#define ATC2609A_PMU_PWRON_CTL1                        0x8E
+#define ATC2609A_PMU_PWRON_CTL2                        0x8F
+#define ATC2609A_IRC_CTL                       0x90
+#define ATC2609A_IRC_STAT                      0x91
+#define ATC2609A_IRC_CC                                0x92
+#define ATC2609A_IRC_KDC                       0x93
+#define ATC2609A_IRC_WK                                0x94
+#define ATC2609A_IRC_RCC                       0x95
+
+/* AUDIO_OUT Registers */
+#define ATC2609A_AUDIOINOUT_CTL                        0xA0
+#define ATC2609A_AUDIO_DEBUGOUTCTL             0xA1
+#define ATC2609A_DAC_DIGITALCTL                        0xA2
+#define ATC2609A_DAC_VOLUMECTL0                        0xA3
+#define ATC2609A_DAC_ANALOG0                   0xA4
+#define ATC2609A_DAC_ANALOG1                   0xA5
+#define ATC2609A_DAC_ANALOG2                   0xA6
+#define ATC2609A_DAC_ANALOG3                   0xA7
+
+/* AUDIO_IN Registers */
+#define ATC2609A_ADC_DIGITALCTL                        0xA8
+#define ATC2609A_ADC_HPFCTL                    0xA9
+#define ATC2609A_ADC_CTL                       0xAA
+#define ATC2609A_AGC_CTL0                      0xAB
+#define ATC2609A_AGC_CTL1                      0xAC
+#define ATC2609A_AGC_CTL2                      0xAD
+#define ATC2609A_ADC_ANALOG0                   0xAE
+#define ATC2609A_ADC_ANALOG1                   0xAF
+
+/* PCM_IF Registers */
+#define ATC2609A_PCM0_CTL                      0xB0
+#define ATC2609A_PCM1_CTL                      0xB1
+#define ATC2609A_PCM2_CTL                      0xB2
+#define ATC2609A_PCMIF_CTL                     0xB3
+
+/* CMU_CONTROL Registers */
+#define ATC2609A_CMU_DEVRST                    0xC1
+
+/* INTS Registers */
+#define ATC2609A_INTS_PD                       0xC8
+#define ATC2609A_INTS_MSK                      0xC9
+
+/* MFP Registers */
+#define ATC2609A_MFP_CTL                       0xD0
+#define ATC2609A_PAD_VSEL                      0xD1
+#define ATC2609A_GPIO_OUTEN                    0xD2
+#define ATC2609A_GPIO_INEN                     0xD3
+#define ATC2609A_GPIO_DAT                      0xD4
+#define ATC2609A_PAD_DRV                       0xD5
+#define ATC2609A_PAD_EN                                0xD6
+#define ATC2609A_DEBUG_SEL                     0xD7
+#define ATC2609A_DEBUG_IE                      0xD8
+#define ATC2609A_DEBUG_OE                      0xD9
+#define ATC2609A_CHIP_VER                      0xDC
+
+/* PWSI Registers */
+#define ATC2609A_PWSI_CTL                      0xF0
+#define ATC2609A_PWSI_STATUS                   0xF1
+
+/* TWSI Registers */
+#define ATC2609A_SADDR                         0xFF
+
+/* PMU_SYS_CTL0 Register Mask Bits */
+#define ATC2609A_PMU_SYS_CTL0_IR_WK_EN                 BIT(5)
+#define ATC2609A_PMU_SYS_CTL0_RESET_WK_EN              BIT(6)
+#define ATC2609A_PMU_SYS_CTL0_HDSW_WK_EN               BIT(7)
+#define ATC2609A_PMU_SYS_CTL0_ALARM_WK_EN              BIT(8)
+#define ATC2609A_PMU_SYS_CTL0_REM_CON_WK_EN            BIT(9)
+#define ATC2609A_PMU_SYS_CTL0_RESTART_EN               BIT(10)
+#define ATC2609A_PMU_SYS_CTL0_WKIRQ_WK_EN              BIT(11)
+#define ATC2609A_PMU_SYS_CTL0_ONOFF_SHORT_WK_EN                BIT(12)
+#define ATC2609A_PMU_SYS_CTL0_ONOFF_LONG_WK_EN         BIT(13)
+#define ATC2609A_PMU_SYS_CTL0_WALL_WK_EN               BIT(14)
+#define ATC2609A_PMU_SYS_CTL0_USB_WK_EN                        BIT(15)
+#define ATC2609A_PMU_SYS_CTL0_WK_ALL                   (GENMASK(15, 5) & (~BIT(10)))
+
+/* PMU_SYS_CTL1 Register Mask Bits */
+#define ATC2609A_PMU_SYS_CTL1_EN_S1                    BIT(0)
+#define ATC2609A_PMU_SYS_CTL1_LB_S4_EN                 BIT(2)
+#define ATC2609A_PMU_SYS_CTL1_LB_S4                    GENMASK(4, 3)
+#define ATC2609A_PMU_SYS_CTL1_LB_S4_3_1V               BIT(4)
+#define ATC2609A_PMU_SYS_CTL1_IR_WK_FLAG               BIT(5)
+#define ATC2609A_PMU_SYS_CTL1_RESET_WK_FLAG            BIT(6)
+#define ATC2609A_PMU_SYS_CTL1_HDSW_WK_FLAG             BIT(7)
+#define ATC2609A_PMU_SYS_CTL1_ALARM_WK_FLAG            BIT(8)
+#define ATC2609A_PMU_SYS_CTL1_REM_CON_WK_FLAG          BIT(9)
+#define ATC2609A_PMU_SYS_CTL1_RESTART_WK_FLAG          BIT(10)
+#define ATC2609A_PMU_SYS_CTL1_WKIRQ_WK_FLAG            BIT(11)
+#define ATC2609A_PMU_SYS_CTL1_ONOFF_SHORT_WK_FLAG      BIT(12)
+#define ATC2609A_PMU_SYS_CTL1_ONOFF_LONG_WK_FLAG       BIT(13)
+#define ATC2609A_PMU_SYS_CTL1_WALL_WK_FLAG             BIT(14)
+#define ATC2609A_PMU_SYS_CTL1_USB_WK_FLAG              BIT(15)
+
+/* PMU_SYS_CTL2 Register Mask Bits */
+#define ATC2609A_PMU_SYS_CTL2_PMU_A_EN                 BIT(0)
+#define ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS_INT_EN       BIT(1)
+#define ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS_PD           BIT(2)
+#define ATC2609A_PMU_SYS_CTL2_S2TIMER                  GENMASK(5, 3)
+#define ATC2609A_PMU_SYS_CTL2_S2_TIMER_EN              BIT(6)
+#define ATC2609A_PMU_SYS_CTL2_ONOFF_RESET_TIME_SEL     GENMASK(8, 7)
+#define ATC2609A_PMU_SYS_CTL2_ONOFF_RESET_EN           BIT(9)
+#define ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS_TIME         GENMASK(11, 10)
+#define ATC2609A_PMU_SYS_CTL2_ONOFF_LSP_INT_EN         BIT(12)
+#define ATC2609A_PMU_SYS_CTL2_ONOFF_LONG_PRESS         BIT(13)
+#define ATC2609A_PMU_SYS_CTL2_ONOFF_SHORT_PRESS                BIT(14)
+#define ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS              BIT(15)
+
+/* PMU_SYS_CTL3 Register Mask Bits */
+#define ATC2609A_PMU_SYS_CTL3_S2S3TOS1_TIMER           GENMASK(8, 7)
+#define ATC2609A_PMU_SYS_CTL3_S2S3TOS1_TIMER_EN                BIT(9)
+#define ATC2609A_PMU_SYS_CTL3_S3_TIMER                 GENMASK(12, 10)
+#define ATC2609A_PMU_SYS_CTL3_S3_TIMER_EN              BIT(13)
+#define ATC2609A_PMU_SYS_CTL3_EN_S3                    BIT(14)
+#define ATC2609A_PMU_SYS_CTL3_EN_S2                    BIT(15)
+
+/* PMU_SYS_CTL5 Register Mask Bits */
+#define ATC2609A_PMU_SYS_CTL5_WALLWKDTEN               BIT(7)
+#define ATC2609A_PMU_SYS_CTL5_VBUSWKDTEN               BIT(8)
+#define ATC2609A_PMU_SYS_CTL5_REMCON_DECT_EN           BIT(9)
+#define ATC2609A_PMU_SYS_CTL5_ONOFF_8S_SEL             BIT(10)
+
+/* INTS_MSK Register Mask Bits */
+#define ATC2609A_INTS_MSK_AUDIO                                BIT(0)
+#define ATC2609A_INTS_MSK_OV                           BIT(1)
+#define ATC2609A_INTS_MSK_OC                           BIT(2)
+#define ATC2609A_INTS_MSK_OT                           BIT(3)
+#define ATC2609A_INTS_MSK_UV                           BIT(4)
+#define ATC2609A_INTS_MSK_ALARM                                BIT(5)
+#define ATC2609A_INTS_MSK_ONOFF                                BIT(6)
+#define ATC2609A_INTS_MSK_WKUP                         BIT(7)
+#define ATC2609A_INTS_MSK_IR                           BIT(8)
+#define ATC2609A_INTS_MSK_REMCON                       BIT(9)
+#define ATC2609A_INTS_MSK_POWERIN                      BIT(10)
+
+/* CMU_DEVRST Register Mask Bits */
+#define ATC2609A_CMU_DEVRST_AUDIO                      BIT(0)
+#define ATC2609A_CMU_DEVRST_MFP                                BIT(1)
+#define ATC2609A_CMU_DEVRST_INTS                       BIT(2)
+
+/* PAD_EN Register Mask Bits */
+#define ATC2609A_PAD_EN_EXTIRQ                         BIT(0)
+
+#endif /* __LINUX_MFD_ATC260X_ATC2609A_H */
diff --git a/include/linux/mfd/atc260x/core.h b/include/linux/mfd/atc260x/core.h
new file mode 100644 (file)
index 0000000..777b6c3
--- /dev/null
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Core MFD defines for ATC260x PMICs
+ *
+ * Copyright (C) 2019 Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ * Copyright (C) 2020 Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
+ */
+
+#ifndef __LINUX_MFD_ATC260X_CORE_H
+#define __LINUX_MFD_ATC260X_CORE_H
+
+#include <linux/mfd/atc260x/atc2603c.h>
+#include <linux/mfd/atc260x/atc2609a.h>
+
+enum atc260x_type {
+       ATC2603A = 0,
+       ATC2603C,
+       ATC2609A,
+};
+
+enum atc260x_ver {
+       ATC260X_A = 0,
+       ATC260X_B,
+       ATC260X_C,
+       ATC260X_D,
+       ATC260X_E,
+       ATC260X_F,
+       ATC260X_G,
+       ATC260X_H,
+};
+
+struct atc260x {
+       struct device *dev;
+
+       struct regmap *regmap;
+       const struct regmap_irq_chip *regmap_irq_chip;
+       struct regmap_irq_chip_data *irq_data;
+
+       struct mutex *regmap_mutex;     /* mutex for custom regmap locking */
+
+       const struct mfd_cell *cells;
+       int nr_cells;
+       int irq;
+
+       enum atc260x_type ic_type;
+       enum atc260x_ver ic_ver;
+       const char *type_name;
+       unsigned int rev_reg;
+
+       const struct atc260x_init_regs *init_regs; /* regs for device init */
+};
+
+struct regmap_config;
+
+int atc260x_match_device(struct atc260x *atc260x, struct regmap_config *regmap_cfg);
+int atc260x_device_probe(struct atc260x *atc260x);
+
+#endif /* __LINUX_MFD_ATC260X_CORE_H */
diff --git a/include/linux/mfd/rohm-bd71815.h b/include/linux/mfd/rohm-bd71815.h
new file mode 100644 (file)
index 0000000..ec6d961
--- /dev/null
@@ -0,0 +1,562 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright 2021 ROHM Semiconductors.
+ *
+ * Author: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
+ *
+ * Copyright 2014 Embest Technology Co. Ltd. Inc.
+ *
+ * Author: yanglsh@embest-tech.com
+ */
+
+#ifndef _MFD_BD71815_H
+#define _MFD_BD71815_H
+
+#include <linux/regmap.h>
+
+enum {
+       BD71815_BUCK1   =       0,
+       BD71815_BUCK2,
+       BD71815_BUCK3,
+       BD71815_BUCK4,
+       BD71815_BUCK5,
+       /* General Purpose */
+       BD71815_LDO1,
+       BD71815_LDO2,
+       BD71815_LDO3,
+       /* LDOs for SD Card and SD Card Interface */
+       BD71815_LDO4,
+       BD71815_LDO5,
+       /* LDO for DDR Reference Voltage */
+       BD71815_LDODVREF,
+       /* LDO for Low-Power State Retention */
+       BD71815_LDOLPSR,
+       BD71815_WLED,
+       BD71815_REGULATOR_CNT,
+};
+
+#define BD71815_SUPPLY_STATE_ENABLED    0x1
+
+enum {
+       BD71815_REG_DEVICE              = 0,
+       BD71815_REG_PWRCTRL,
+       BD71815_REG_BUCK1_MODE,
+       BD71815_REG_BUCK2_MODE,
+       BD71815_REG_BUCK3_MODE,
+       BD71815_REG_BUCK4_MODE,
+       BD71815_REG_BUCK5_MODE,
+       BD71815_REG_BUCK1_VOLT_H,
+       BD71815_REG_BUCK1_VOLT_L,
+       BD71815_REG_BUCK2_VOLT_H,
+       BD71815_REG_BUCK2_VOLT_L,
+       BD71815_REG_BUCK3_VOLT,
+       BD71815_REG_BUCK4_VOLT,
+       BD71815_REG_BUCK5_VOLT,
+       BD71815_REG_LED_CTRL,
+       BD71815_REG_LED_DIMM,
+       BD71815_REG_LDO_MODE1,
+       BD71815_REG_LDO_MODE2,
+       BD71815_REG_LDO_MODE3,
+       BD71815_REG_LDO_MODE4,
+       BD71815_REG_LDO1_VOLT,
+       BD71815_REG_LDO2_VOLT,
+       BD71815_REG_LDO3_VOLT,
+       BD71815_REG_LDO4_VOLT,
+       BD71815_REG_LDO5_VOLT_H,
+       BD71815_REG_LDO5_VOLT_L,
+       BD71815_REG_BUCK_PD_DIS,
+       BD71815_REG_LDO_PD_DIS,
+       BD71815_REG_GPO,
+       BD71815_REG_OUT32K,
+       BD71815_REG_SEC,
+       BD71815_REG_MIN,
+       BD71815_REG_HOUR,
+       BD71815_REG_WEEK,
+       BD71815_REG_DAY,
+       BD71815_REG_MONTH,
+       BD71815_REG_YEAR,
+       BD71815_REG_ALM0_SEC,
+
+       BD71815_REG_ALM1_SEC            = 0x2C,
+
+       BD71815_REG_ALM0_MASK           = 0x33,
+       BD71815_REG_ALM1_MASK,
+       BD71815_REG_ALM2,
+       BD71815_REG_TRIM,
+       BD71815_REG_CONF,
+       BD71815_REG_SYS_INIT,
+       BD71815_REG_CHG_STATE,
+       BD71815_REG_CHG_LAST_STATE,
+       BD71815_REG_BAT_STAT,
+       BD71815_REG_DCIN_STAT,
+       BD71815_REG_VSYS_STAT,
+       BD71815_REG_CHG_STAT,
+       BD71815_REG_CHG_WDT_STAT,
+       BD71815_REG_BAT_TEMP,
+       BD71815_REG_IGNORE_0,
+       BD71815_REG_INHIBIT_0,
+       BD71815_REG_DCIN_CLPS,
+       BD71815_REG_VSYS_REG,
+       BD71815_REG_VSYS_MAX,
+       BD71815_REG_VSYS_MIN,
+       BD71815_REG_CHG_SET1,
+       BD71815_REG_CHG_SET2,
+       BD71815_REG_CHG_WDT_PRE,
+       BD71815_REG_CHG_WDT_FST,
+       BD71815_REG_CHG_IPRE,
+       BD71815_REG_CHG_IFST,
+       BD71815_REG_CHG_IFST_TERM,
+       BD71815_REG_CHG_VPRE,
+       BD71815_REG_CHG_VBAT_1,
+       BD71815_REG_CHG_VBAT_2,
+       BD71815_REG_CHG_VBAT_3,
+       BD71815_REG_CHG_LED_1,
+       BD71815_REG_VF_TH,
+       BD71815_REG_BAT_SET_1,
+       BD71815_REG_BAT_SET_2,
+       BD71815_REG_BAT_SET_3,
+       BD71815_REG_ALM_VBAT_TH_U,
+       BD71815_REG_ALM_VBAT_TH_L,
+       BD71815_REG_ALM_DCIN_TH,
+       BD71815_REG_ALM_VSYS_TH,
+       BD71815_REG_VM_IBAT_U,
+       BD71815_REG_VM_IBAT_L,
+       BD71815_REG_VM_VBAT_U,
+       BD71815_REG_VM_VBAT_L,
+       BD71815_REG_VM_BTMP,
+       BD71815_REG_VM_VTH,
+       BD71815_REG_VM_DCIN_U,
+       BD71815_REG_VM_DCIN_L,
+       BD71815_REG_VM_VSYS,
+       BD71815_REG_VM_VF,
+       BD71815_REG_VM_OCI_PRE_U,
+       BD71815_REG_VM_OCI_PRE_L,
+       BD71815_REG_VM_OCV_PRE_U,
+       BD71815_REG_VM_OCV_PRE_L,
+       BD71815_REG_VM_OCI_PST_U,
+       BD71815_REG_VM_OCI_PST_L,
+       BD71815_REG_VM_OCV_PST_U,
+       BD71815_REG_VM_OCV_PST_L,
+       BD71815_REG_VM_SA_VBAT_U,
+       BD71815_REG_VM_SA_VBAT_L,
+       BD71815_REG_VM_SA_IBAT_U,
+       BD71815_REG_VM_SA_IBAT_L,
+       BD71815_REG_CC_CTRL,
+       BD71815_REG_CC_BATCAP1_TH_U,
+       BD71815_REG_CC_BATCAP1_TH_L,
+       BD71815_REG_CC_BATCAP2_TH_U,
+       BD71815_REG_CC_BATCAP2_TH_L,
+       BD71815_REG_CC_BATCAP3_TH_U,
+       BD71815_REG_CC_BATCAP3_TH_L,
+       BD71815_REG_CC_STAT,
+       BD71815_REG_CC_CCNTD_3,
+       BD71815_REG_CC_CCNTD_2,
+       BD71815_REG_CC_CCNTD_1,
+       BD71815_REG_CC_CCNTD_0,
+       BD71815_REG_CC_CURCD_U,
+       BD71815_REG_CC_CURCD_L,
+       BD71815_REG_VM_OCUR_THR_1,
+       BD71815_REG_VM_OCUR_DUR_1,
+       BD71815_REG_VM_OCUR_THR_2,
+       BD71815_REG_VM_OCUR_DUR_2,
+       BD71815_REG_VM_OCUR_THR_3,
+       BD71815_REG_VM_OCUR_DUR_3,
+       BD71815_REG_VM_OCUR_MON,
+       BD71815_REG_VM_BTMP_OV_THR,
+       BD71815_REG_VM_BTMP_OV_DUR,
+       BD71815_REG_VM_BTMP_LO_THR,
+       BD71815_REG_VM_BTMP_LO_DUR,
+       BD71815_REG_VM_BTMP_MON,
+       BD71815_REG_INT_EN_01,
+
+       BD71815_REG_INT_EN_11           = 0x95,
+       BD71815_REG_INT_EN_12,
+       BD71815_REG_INT_STAT,
+       BD71815_REG_INT_STAT_01,
+       BD71815_REG_INT_STAT_02,
+       BD71815_REG_INT_STAT_03,
+       BD71815_REG_INT_STAT_04,
+       BD71815_REG_INT_STAT_05,
+       BD71815_REG_INT_STAT_06,
+       BD71815_REG_INT_STAT_07,
+       BD71815_REG_INT_STAT_08,
+       BD71815_REG_INT_STAT_09,
+       BD71815_REG_INT_STAT_10,
+       BD71815_REG_INT_STAT_11,
+       BD71815_REG_INT_STAT_12,
+       BD71815_REG_INT_UPDATE,
+
+       BD71815_REG_VM_VSYS_U           = 0xC0,
+       BD71815_REG_VM_VSYS_L,
+       BD71815_REG_VM_SA_VSYS_U,
+       BD71815_REG_VM_SA_VSYS_L,
+
+       BD71815_REG_VM_SA_IBAT_MIN_U    = 0xD0,
+       BD71815_REG_VM_SA_IBAT_MIN_L,
+       BD71815_REG_VM_SA_IBAT_MAX_U,
+       BD71815_REG_VM_SA_IBAT_MAX_L,
+       BD71815_REG_VM_SA_VBAT_MIN_U,
+       BD71815_REG_VM_SA_VBAT_MIN_L,
+       BD71815_REG_VM_SA_VBAT_MAX_U,
+       BD71815_REG_VM_SA_VBAT_MAX_L,
+       BD71815_REG_VM_SA_VSYS_MIN_U,
+       BD71815_REG_VM_SA_VSYS_MIN_L,
+       BD71815_REG_VM_SA_VSYS_MAX_U,
+       BD71815_REG_VM_SA_VSYS_MAX_L,
+       BD71815_REG_VM_SA_MINMAX_CLR,
+
+       BD71815_REG_REX_CCNTD_3         = 0xE0,
+       BD71815_REG_REX_CCNTD_2,
+       BD71815_REG_REX_CCNTD_1,
+       BD71815_REG_REX_CCNTD_0,
+       BD71815_REG_REX_SA_VBAT_U,
+       BD71815_REG_REX_SA_VBAT_L,
+       BD71815_REG_REX_CTRL_1,
+       BD71815_REG_REX_CTRL_2,
+       BD71815_REG_FULL_CCNTD_3,
+       BD71815_REG_FULL_CCNTD_2,
+       BD71815_REG_FULL_CCNTD_1,
+       BD71815_REG_FULL_CCNTD_0,
+       BD71815_REG_FULL_CTRL,
+
+       BD71815_REG_CCNTD_CHG_3         = 0xF0,
+       BD71815_REG_CCNTD_CHG_2,
+
+       BD71815_REG_TEST_MODE           = 0xFE,
+       BD71815_MAX_REGISTER,
+};
+
+/* BD71815_REG_BUCK1_MODE bits */
+#define BD71815_BUCK_RAMPRATE_MASK             0xC0
+#define BD71815_BUCK_RAMPRATE_10P00MV          0x0
+#define BD71815_BUCK_RAMPRATE_5P00MV           0x01
+#define BD71815_BUCK_RAMPRATE_2P50MV           0x02
+#define BD71815_BUCK_RAMPRATE_1P25MV           0x03
+
+#define BD71815_BUCK_PWM_FIXED                 BIT(4)
+#define BD71815_BUCK_SNVS_ON                   BIT(3)
+#define BD71815_BUCK_RUN_ON                    BIT(2)
+#define BD71815_BUCK_LPSR_ON                   BIT(1)
+#define BD71815_BUCK_SUSP_ON                   BIT(0)
+
+/* BD71815_REG_BUCK1_VOLT_H bits */
+#define BD71815_BUCK_DVSSEL                    BIT(7)
+#define BD71815_BUCK_STBY_DVS                  BIT(6)
+#define BD71815_VOLT_MASK                      0x3F
+#define BD71815_BUCK1_H_DEFAULT                        0x14
+#define BD71815_BUCK1_L_DEFAULT                        0x14
+
+/* BD71815_REG_BUCK2_VOLT_H bits */
+#define BD71815_BUCK2_H_DEFAULT                        0x14
+#define BD71815_BUCK2_L_DEFAULT                        0x14
+
+/* WLED output */
+/* current register mask */
+#define LED_DIMM_MASK                          0x3f
+/* LED enable bits at LED_CTRL reg */
+#define LED_CHGDONE_EN                         BIT(4)
+#define LED_RUN_ON                             BIT(2)
+#define LED_LPSR_ON                            BIT(1)
+#define LED_SUSP_ON                            BIT(0)
+
+/* BD71815_REG_LDO1_CTRL bits */
+#define LDO1_EN                                        BIT(0)
+#define LDO2_EN                                        BIT(1)
+#define LDO3_EN                                        BIT(2)
+#define DVREF_EN                               BIT(3)
+#define VOSNVS_SW_EN                           BIT(4)
+
+/* LDO_MODE1_register */
+#define LDO1_SNVS_ON                           BIT(7)
+#define LDO1_RUN_ON                            BIT(6)
+#define LDO1_LPSR_ON                           BIT(5)
+#define LDO1_SUSP_ON                           BIT(4)
+/* set => register control, unset => GPIO control */
+#define LDO4_MODE_MASK                         BIT(3)
+#define LDO4_MODE_I2C                          BIT(3)
+#define LDO4_MODE_GPIO                         0
+/* set => register control, unset => start when DCIN connected */
+#define LDO3_MODE_MASK                         BIT(2)
+#define LDO3_MODE_I2C                          BIT(2)
+#define LDO3_MODE_DCIN                         0
+
+/* LDO_MODE2 register */
+#define LDO3_SNVS_ON                           BIT(7)
+#define LDO3_RUN_ON                            BIT(6)
+#define LDO3_LPSR_ON                           BIT(5)
+#define LDO3_SUSP_ON                           BIT(4)
+#define LDO2_SNVS_ON                           BIT(3)
+#define LDO2_RUN_ON                            BIT(2)
+#define LDO2_LPSR_ON                           BIT(1)
+#define LDO2_SUSP_ON                           BIT(0)
+
+
+/* LDO_MODE3 register */
+#define LDO5_SNVS_ON                           BIT(7)
+#define LDO5_RUN_ON                            BIT(6)
+#define LDO5_LPSR_ON                           BIT(5)
+#define LDO5_SUSP_ON                           BIT(4)
+#define LDO4_SNVS_ON                           BIT(3)
+#define LDO4_RUN_ON                            BIT(2)
+#define LDO4_LPSR_ON                           BIT(1)
+#define LDO4_SUSP_ON                           BIT(0)
+
+/* LDO_MODE4 register */
+#define DVREF_SNVS_ON                          BIT(7)
+#define DVREF_RUN_ON                           BIT(6)
+#define DVREF_LPSR_ON                          BIT(5)
+#define DVREF_SUSP_ON                          BIT(4)
+#define LDO_LPSR_SNVS_ON                       BIT(3)
+#define LDO_LPSR_RUN_ON                                BIT(2)
+#define LDO_LPSR_LPSR_ON                       BIT(1)
+#define LDO_LPSR_SUSP_ON                       BIT(0)
+
+/* BD71815_REG_OUT32K bits */
+#define OUT32K_EN                              BIT(0)
+#define OUT32K_MODE                            BIT(1)
+#define OUT32K_MODE_CMOS                       BIT(1)
+#define OUT32K_MODE_OPEN_DRAIN                 0
+
+/* BD71815_REG_BAT_STAT bits */
+#define BAT_DET                                        BIT(5)
+#define BAT_DET_OFFSET                         5
+#define BAT_DET_DONE                           BIT(4)
+#define VBAT_OV                                        BIT(3)
+#define DBAT_DET                               BIT(0)
+
+/* BD71815_REG_VBUS_STAT bits */
+#define VBUS_DET                               BIT(0)
+
+#define BD71815_REG_RTC_START                  BD71815_REG_SEC
+#define BD71815_REG_RTC_ALM_START              BD71815_REG_ALM0_SEC
+
+/* BD71815_REG_ALM0_MASK bits */
+#define A0_ONESEC                              BIT(7)
+
+/* BD71815_REG_INT_EN_00 bits */
+#define ALMALE                                 BIT(0)
+
+/* BD71815_REG_INT_STAT_03 bits */
+#define DCIN_MON_DET                           BIT(1)
+#define DCIN_MON_RES                           BIT(0)
+#define POWERON_LONG                           BIT(2)
+#define POWERON_MID                            BIT(3)
+#define POWERON_SHORT                          BIT(4)
+#define POWERON_PRESS                          BIT(5)
+
+/* BD71805_REG_INT_STAT_08 bits */
+#define VBAT_MON_DET                           BIT(1)
+#define VBAT_MON_RES                           BIT(0)
+
+/* BD71805_REG_INT_STAT_11 bits */
+#define        INT_STAT_11_VF_DET                      BIT(7)
+#define        INT_STAT_11_VF_RES                      BIT(6)
+#define        INT_STAT_11_VF125_DET                   BIT(5)
+#define        INT_STAT_11_VF125_RES                   BIT(4)
+#define        INT_STAT_11_OVTMP_DET                   BIT(3)
+#define        INT_STAT_11_OVTMP_RES                   BIT(2)
+#define        INT_STAT_11_LOTMP_DET                   BIT(1)
+#define        INT_STAT_11_LOTMP_RES                   BIT(0)
+
+#define VBAT_MON_DET                           BIT(1)
+#define VBAT_MON_RES                           BIT(0)
+
+/* BD71815_REG_PWRCTRL bits */
+#define RESTARTEN                              BIT(0)
+
+/* BD71815_REG_GPO bits */
+#define READY_FORCE_LOW                                BIT(2)
+#define BD71815_GPIO_DRIVE_MASK                        BIT(4)
+#define BD71815_GPIO_OPEN_DRAIN                        0
+#define BD71815_GPIO_CMOS                      BIT(4)
+
+/* BD71815 interrupt masks */
+enum {
+       BD71815_INT_EN_01_BUCKAST_MASK  =       0x0F,
+       BD71815_INT_EN_02_DCINAST_MASK  =       0x3E,
+       BD71815_INT_EN_03_DCINAST_MASK  =       0x3F,
+       BD71815_INT_EN_04_VSYSAST_MASK  =       0xCF,
+       BD71815_INT_EN_05_CHGAST_MASK   =       0xFC,
+       BD71815_INT_EN_06_BATAST_MASK   =       0xF3,
+       BD71815_INT_EN_07_BMONAST_MASK  =       0xFE,
+       BD71815_INT_EN_08_BMONAST_MASK  =       0x03,
+       BD71815_INT_EN_09_BMONAST_MASK  =       0x07,
+       BD71815_INT_EN_10_BMONAST_MASK  =       0x3F,
+       BD71815_INT_EN_11_TMPAST_MASK   =       0xFF,
+       BD71815_INT_EN_12_ALMAST_MASK   =       0x07,
+};
+/* BD71815 interrupt irqs */
+enum {
+       /* BUCK reg interrupts */
+       BD71815_INT_BUCK1_OCP,
+       BD71815_INT_BUCK2_OCP,
+       BD71815_INT_BUCK3_OCP,
+       BD71815_INT_BUCK4_OCP,
+       BD71815_INT_BUCK5_OCP,
+       BD71815_INT_LED_OVP,
+       BD71815_INT_LED_OCP,
+       BD71815_INT_LED_SCP,
+       /* DCIN1 interrupts */
+       BD71815_INT_DCIN_RMV,
+       BD71815_INT_CLPS_OUT,
+       BD71815_INT_CLPS_IN,
+       BD71815_INT_DCIN_OVP_RES,
+       BD71815_INT_DCIN_OVP_DET,
+       /* DCIN2 interrupts */
+       BD71815_INT_DCIN_MON_RES,
+       BD71815_INT_DCIN_MON_DET,
+       BD71815_INT_WDOG,
+       /* Vsys INT_STAT_04 */
+       BD71815_INT_VSYS_UV_RES,
+       BD71815_INT_VSYS_UV_DET,
+       BD71815_INT_VSYS_LOW_RES,
+       BD71815_INT_VSYS_LOW_DET,
+       BD71815_INT_VSYS_MON_RES,
+       BD71815_INT_VSYS_MON_DET,
+       /* Charger INT_STAT_05 */
+       BD71815_INT_CHG_WDG_TEMP,
+       BD71815_INT_CHG_WDG_TIME,
+       BD71815_INT_CHG_RECHARGE_RES,
+       BD71815_INT_CHG_RECHARGE_DET,
+       BD71815_INT_CHG_RANGED_TEMP_TRANSITION,
+       BD71815_INT_CHG_STATE_TRANSITION,
+       /* Battery  INT_STAT_06 */
+       BD71815_INT_BAT_TEMP_NORMAL,
+       BD71815_INT_BAT_TEMP_ERANGE,
+       BD71815_INT_BAT_REMOVED,
+       BD71815_INT_BAT_DETECTED,
+       BD71815_INT_THERM_REMOVED,
+       BD71815_INT_THERM_DETECTED,
+       /* Battery Mon 1 INT_STAT_07 */
+       BD71815_INT_BAT_DEAD,
+       BD71815_INT_BAT_SHORTC_RES,
+       BD71815_INT_BAT_SHORTC_DET,
+       BD71815_INT_BAT_LOW_VOLT_RES,
+       BD71815_INT_BAT_LOW_VOLT_DET,
+       BD71815_INT_BAT_OVER_VOLT_RES,
+       BD71815_INT_BAT_OVER_VOLT_DET,
+       /* Battery Mon 2 INT_STAT_08 */
+       BD71815_INT_BAT_MON_RES,
+       BD71815_INT_BAT_MON_DET,
+       /* Battery Mon 3 (Coulomb counter) INT_STAT_09 */
+       BD71815_INT_BAT_CC_MON1,
+       BD71815_INT_BAT_CC_MON2,
+       BD71815_INT_BAT_CC_MON3,
+       /* Battery Mon 4 INT_STAT_10 */
+       BD71815_INT_BAT_OVER_CURR_1_RES,
+       BD71815_INT_BAT_OVER_CURR_1_DET,
+       BD71815_INT_BAT_OVER_CURR_2_RES,
+       BD71815_INT_BAT_OVER_CURR_2_DET,
+       BD71815_INT_BAT_OVER_CURR_3_RES,
+       BD71815_INT_BAT_OVER_CURR_3_DET,
+       /* Temperature INT_STAT_11 */
+       BD71815_INT_TEMP_BAT_LOW_RES,
+       BD71815_INT_TEMP_BAT_LOW_DET,
+       BD71815_INT_TEMP_BAT_HI_RES,
+       BD71815_INT_TEMP_BAT_HI_DET,
+       BD71815_INT_TEMP_CHIP_OVER_125_RES,
+       BD71815_INT_TEMP_CHIP_OVER_125_DET,
+       BD71815_INT_TEMP_CHIP_OVER_VF_RES,
+       BD71815_INT_TEMP_CHIP_OVER_VF_DET,
+       /* RTC Alarm INT_STAT_12 */
+       BD71815_INT_RTC0,
+       BD71815_INT_RTC1,
+       BD71815_INT_RTC2,
+};
+
+#define BD71815_INT_BUCK1_OCP_MASK                     BIT(0)
+#define BD71815_INT_BUCK2_OCP_MASK                     BIT(1)
+#define BD71815_INT_BUCK3_OCP_MASK                     BIT(2)
+#define BD71815_INT_BUCK4_OCP_MASK                     BIT(3)
+#define BD71815_INT_BUCK5_OCP_MASK                     BIT(4)
+#define BD71815_INT_LED_OVP_MASK                       BIT(5)
+#define BD71815_INT_LED_OCP_MASK                       BIT(6)
+#define BD71815_INT_LED_SCP_MASK                       BIT(7)
+
+#define BD71815_INT_DCIN_RMV_MASK                      BIT(1)
+#define BD71815_INT_CLPS_OUT_MASK                      BIT(2)
+#define BD71815_INT_CLPS_IN_MASK                       BIT(3)
+#define BD71815_INT_DCIN_OVP_RES_MASK                  BIT(4)
+#define BD71815_INT_DCIN_OVP_DET_MASK                  BIT(5)
+
+#define BD71815_INT_DCIN_MON_RES_MASK                  BIT(0)
+#define BD71815_INT_DCIN_MON_DET_MASK                  BIT(1)
+#define BD71815_INT_WDOG_MASK                          BIT(6)
+
+#define BD71815_INT_VSYS_UV_RES_MASK                   BIT(0)
+#define BD71815_INT_VSYS_UV_DET_MASK                   BIT(1)
+#define BD71815_INT_VSYS_LOW_RES_MASK                  BIT(2)
+#define BD71815_INT_VSYS_LOW_DET_MASK                  BIT(3)
+#define BD71815_INT_VSYS_MON_RES_MASK                  BIT(6)
+#define BD71815_INT_VSYS_MON_DET_MASK                  BIT(7)
+
+#define BD71815_INT_CHG_WDG_TEMP_MASK                  BIT(2)
+#define BD71815_INT_CHG_WDG_TIME_MASK                  BIT(3)
+#define BD71815_INT_CHG_RECHARGE_RES_MASK              BIT(4)
+#define BD71815_INT_CHG_RECHARGE_DET_MASK              BIT(5)
+#define BD71815_INT_CHG_RANGED_TEMP_TRANSITION_MASK    BIT(6)
+#define BD71815_INT_CHG_STATE_TRANSITION_MASK          BIT(7)
+
+#define BD71815_INT_BAT_TEMP_NORMAL_MASK               BIT(0)
+#define BD71815_INT_BAT_TEMP_ERANGE_MASK               BIT(1)
+#define BD71815_INT_BAT_REMOVED_MASK                   BIT(4)
+#define BD71815_INT_BAT_DETECTED_MASK                  BIT(5)
+#define BD71815_INT_THERM_REMOVED_MASK                 BIT(6)
+#define BD71815_INT_THERM_DETECTED_MASK                        BIT(7)
+
+#define BD71815_INT_BAT_DEAD_MASK                      BIT(1)
+#define BD71815_INT_BAT_SHORTC_RES_MASK                        BIT(2)
+#define BD71815_INT_BAT_SHORTC_DET_MASK                        BIT(3)
+#define BD71815_INT_BAT_LOW_VOLT_RES_MASK              BIT(4)
+#define BD71815_INT_BAT_LOW_VOLT_DET_MASK              BIT(5)
+#define BD71815_INT_BAT_OVER_VOLT_RES_MASK             BIT(6)
+#define BD71815_INT_BAT_OVER_VOLT_DET_MASK             BIT(7)
+
+#define BD71815_INT_BAT_MON_RES_MASK                   BIT(0)
+#define BD71815_INT_BAT_MON_DET_MASK                   BIT(1)
+
+#define BD71815_INT_BAT_CC_MON1_MASK                   BIT(0)
+#define BD71815_INT_BAT_CC_MON2_MASK                   BIT(1)
+#define BD71815_INT_BAT_CC_MON3_MASK                   BIT(2)
+
+#define BD71815_INT_BAT_OVER_CURR_1_RES_MASK           BIT(0)
+#define BD71815_INT_BAT_OVER_CURR_1_DET_MASK           BIT(1)
+#define BD71815_INT_BAT_OVER_CURR_2_RES_MASK           BIT(2)
+#define BD71815_INT_BAT_OVER_CURR_2_DET_MASK           BIT(3)
+#define BD71815_INT_BAT_OVER_CURR_3_RES_MASK           BIT(4)
+#define BD71815_INT_BAT_OVER_CURR_3_DET_MASK           BIT(5)
+
+#define BD71815_INT_TEMP_BAT_LOW_RES_MASK              BIT(0)
+#define BD71815_INT_TEMP_BAT_LOW_DET_MASK              BIT(1)
+#define BD71815_INT_TEMP_BAT_HI_RES_MASK               BIT(2)
+#define BD71815_INT_TEMP_BAT_HI_DET_MASK               BIT(3)
+#define BD71815_INT_TEMP_CHIP_OVER_125_RES_MASK                BIT(4)
+#define BD71815_INT_TEMP_CHIP_OVER_125_DET_MASK                BIT(5)
+#define BD71815_INT_TEMP_CHIP_OVER_VF_RES_MASK         BIT(6)
+#define BD71815_INT_TEMP_CHIP_OVER_VF_DET_MASK         BIT(7)
+
+#define BD71815_INT_RTC0_MASK                          BIT(0)
+#define BD71815_INT_RTC1_MASK                          BIT(1)
+#define BD71815_INT_RTC2_MASK                          BIT(2)
+
+/* BD71815_REG_CC_CTRL bits */
+#define CCNTRST                                                0x80
+#define CCNTENB                                                0x40
+#define CCCALIB                                                0x20
+
+/* BD71815_REG_CC_CURCD */
+#define CURDIR_Discharging                             0x8000
+
+/* BD71815_REG_VM_SA_IBAT */
+#define IBAT_SA_DIR_Discharging                                0x8000
+
+/* BD71815_REG_REX_CTRL_1 bits */
+#define REX_CLR                                                BIT(4)
+
+/* BD71815_REG_REX_CTRL_1 bits */
+#define REX_PMU_STATE_MASK                             BIT(2)
+
+/* BD71815_REG_LED_CTRL bits */
+#define CHGDONE_LED_EN                                 BIT(4)
+
+#endif /* __LINUX_MFD_BD71815_H */
index 017a4c0..c7ab69c 100644 (file)
@@ -151,6 +151,9 @@ enum {
 #define BD71828_REG_GPIO_CTRL3         0x49
 #define BD71828_REG_IO_STAT            0xed
 
+/* clk */
+#define BD71828_REG_OUT32K             0x4b
+
 /* RTC */
 #define BD71828_REG_RTC_SEC            0x4c
 #define BD71828_REG_RTC_MINUTE         0x4d
index bee2474..df29181 100644 (file)
@@ -310,17 +310,4 @@ enum {
        BD718XX_PWRBTN_LONG_PRESS_15S
 };
 
-struct bd718xx {
-       /*
-        * Please keep this as the first member here as some
-        * drivers (clk) supporting more than one chip may only know this
-        * generic struct 'struct rohm_regmap_dev' and assume it is
-        * the first chunk of parent device's private data.
-        */
-       struct rohm_regmap_dev chip;
-
-       int chip_irq;
-       struct regmap_irq_chip_data *irq_data;
-};
-
 #endif /* __LINUX_MFD_BD718XX_H__ */
index 66f673c..a914428 100644 (file)
@@ -8,12 +8,13 @@
 #include <linux/regulator/driver.h>
 
 enum rohm_chip_type {
-       ROHM_CHIP_TYPE_BD71837 = 0,
-       ROHM_CHIP_TYPE_BD71847,
-       ROHM_CHIP_TYPE_BD70528,
-       ROHM_CHIP_TYPE_BD71828,
        ROHM_CHIP_TYPE_BD9571,
        ROHM_CHIP_TYPE_BD9574,
+       ROHM_CHIP_TYPE_BD70528,
+       ROHM_CHIP_TYPE_BD71815,
+       ROHM_CHIP_TYPE_BD71828,
+       ROHM_CHIP_TYPE_BD71837,
+       ROHM_CHIP_TYPE_BD71847,
        ROHM_CHIP_TYPE_AMOUNT
 };
 
@@ -26,7 +27,8 @@ struct rohm_regmap_dev {
 #define ROHM_DVS_LEVEL_IDLE            BIT(1)
 #define ROHM_DVS_LEVEL_SUSPEND         BIT(2)
 #define ROHM_DVS_LEVEL_LPSR            BIT(3)
-#define ROHM_DVS_LEVEL_VALID_AMOUNT    4
+#define ROHM_DVS_LEVEL_SNVS            BIT(4)
+#define ROHM_DVS_LEVEL_VALID_AMOUNT    5
 #define ROHM_DVS_LEVEL_UNKNOWN         0
 
 /**
@@ -65,6 +67,9 @@ struct rohm_dvs_config {
        unsigned int lpsr_reg;
        unsigned int lpsr_mask;
        unsigned int lpsr_on_mask;
+       unsigned int snvs_reg;
+       unsigned int snvs_mask;
+       unsigned int snvs_on_mask;
 };
 
 #if IS_ENABLED(CONFIG_REGULATOR_ROHM)
index 77e64e3..64a71bf 100644 (file)
@@ -1300,6 +1300,27 @@ static inline bool page_maybe_dma_pinned(struct page *page)
                GUP_PIN_COUNTING_BIAS;
 }
 
+static inline bool is_cow_mapping(vm_flags_t flags)
+{
+       return (flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE;
+}
+
+/*
+ * This should most likely only be called during fork() to see whether we
+ * should break the cow immediately for a page on the src mm.
+ */
+static inline bool page_needs_cow_for_dma(struct vm_area_struct *vma,
+                                         struct page *page)
+{
+       if (!is_cow_mapping(vma->vm_flags))
+               return false;
+
+       if (!atomic_read(&vma->vm_mm->has_pinned))
+               return false;
+
+       return page_maybe_dma_pinned(page);
+}
+
 #if defined(CONFIG_SPARSEMEM) && !defined(CONFIG_SPARSEMEM_VMEMMAP)
 #define SECTION_IN_PAGE_FLAGS
 #endif
index 0974ad5..6613b26 100644 (file)
@@ -23,6 +23,7 @@
 #endif
 #define AT_VECTOR_SIZE (2*(AT_VECTOR_SIZE_ARCH + AT_VECTOR_SIZE_BASE + 1))
 
+#define INIT_PASID     0
 
 struct address_space;
 struct mem_cgroup;
index 59f094f..da4b6fb 100644 (file)
@@ -30,9 +30,6 @@
 #include <linux/percpu.h>
 #include <asm/module.h>
 
-/* Not Yet Implemented */
-#define MODULE_SUPPORTED_DEVICE(name)
-
 #define MODULE_NAME_LEN MAX_PARAM_PREFIX_LEN
 
 struct modversion_info {
index f06fbee..5b67ea8 100644 (file)
@@ -3959,8 +3959,6 @@ int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,
 int bpf_xdp_link_attach(const union bpf_attr *attr, struct bpf_prog *prog);
 u32 dev_xdp_prog_id(struct net_device *dev, enum bpf_xdp_mode mode);
 
-int xdp_umem_query(struct net_device *dev, u16 queue_id);
-
 int __dev_forward_skb(struct net_device *dev, struct sk_buff *skb);
 int dev_forward_skb(struct net_device *dev, struct sk_buff *skb);
 int dev_forward_skb_nomtu(struct net_device *dev, struct sk_buff *skb);
index fab42cf..3f7f89e 100644 (file)
@@ -606,6 +606,7 @@ struct swevent_hlist {
 #define PERF_ATTACH_TASK       0x04
 #define PERF_ATTACH_TASK_DATA  0x08
 #define PERF_ATTACH_ITRACE     0x10
+#define PERF_ATTACH_SCHED_CB   0x20
 
 struct perf_cgroup;
 struct perf_buffer;
@@ -872,6 +873,7 @@ struct perf_cpu_context {
        struct list_head                cgrp_cpuctx_entry;
 #endif
 
+       struct list_head                sched_cb_entry;
        int                             sched_cb_usage;
 
        int                             online;
index cdfc4e9..5e77239 100644 (file)
@@ -904,6 +904,10 @@ static inline void ptep_modify_prot_commit(struct vm_area_struct *vma,
 #define pgprot_device pgprot_noncached
 #endif
 
+#ifndef pgprot_mhp
+#define pgprot_mhp(prot)       (prot)
+#endif
+
 #ifdef CONFIG_MMU
 #ifndef pgprot_modify
 #define pgprot_modify pgprot_modify
index dafccfc..dd4687b 100644 (file)
@@ -488,7 +488,7 @@ fwnode_create_software_node(const struct property_entry *properties,
                            const struct fwnode_handle *parent);
 void fwnode_remove_software_node(struct fwnode_handle *fwnode);
 
-int device_add_software_node(struct device *dev, const struct software_node *swnode);
+int device_add_software_node(struct device *dev, const struct software_node *node);
 void device_remove_software_node(struct device *dev);
 
 int device_create_managed_software_node(struct device *dev,
index d7c77ee..597ed11 100644 (file)
@@ -373,6 +373,10 @@ struct regulator_desc {
        unsigned int pull_down_reg;
        unsigned int pull_down_mask;
        unsigned int pull_down_val_on;
+       unsigned int ramp_reg;
+       unsigned int ramp_mask;
+       const unsigned int *ramp_delay_table;
+       unsigned int n_ramp_values;
 
        unsigned int enable_time;
 
@@ -535,6 +539,7 @@ int regulator_set_current_limit_regmap(struct regulator_dev *rdev,
                                       int min_uA, int max_uA);
 int regulator_get_current_limit_regmap(struct regulator_dev *rdev);
 void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data);
+int regulator_set_ramp_delay_regmap(struct regulator_dev *rdev, int ramp_delay);
 
 /*
  * Helper functions intended to be used by regulator drivers prior registering
@@ -543,4 +548,6 @@ void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data);
 int regulator_desc_list_voltage_linear_range(const struct regulator_desc *desc,
                                             unsigned int selector);
 
+int regulator_desc_list_voltage_linear(const struct regulator_desc *desc,
+                                      unsigned int selector);
 #endif
index ccdb532..71902f4 100644 (file)
@@ -147,6 +147,9 @@ enum {
 #define BUCK6_FPWM                     0x04
 #define BUCK6_ENMODE_MASK              0x03
 
+/* PCA9450_REG_BUCK123_PRESET_EN bit */
+#define BUCK123_PRESET_EN              0x80
+
 /* PCA9450_BUCK1OUT_DVS0 bits */
 #define BUCK1OUT_DVS0_MASK             0x7F
 #define BUCK1OUT_DVS0_DEFAULT          0x14
index bba2920..980a655 100644 (file)
@@ -23,6 +23,7 @@ enum timespec_type {
  * System call restart block.
  */
 struct restart_block {
+       unsigned long arch_data;
        long (*fn)(struct restart_block *);
        union {
                /* For futex_wait and futex_wait_requeue_pi */
index 1ae08b8..90b2a0b 100644 (file)
@@ -140,7 +140,8 @@ static inline bool in_vfork(struct task_struct *tsk)
         * another oom-unkillable task does this it should blame itself.
         */
        rcu_read_lock();
-       ret = tsk->vfork_done && tsk->real_parent->mm == tsk->mm;
+       ret = tsk->vfork_done &&
+                       rcu_dereference(tsk->real_parent)->mm == tsk->mm;
        rcu_read_unlock();
 
        return ret;
index 2f7bb92..f61e34f 100644 (file)
@@ -664,10 +664,7 @@ typedef struct {
  * seqcount_latch_init() - runtime initializer for seqcount_latch_t
  * @s: Pointer to the seqcount_latch_t instance
  */
-static inline void seqcount_latch_init(seqcount_latch_t *s)
-{
-       seqcount_init(&s->seqcount);
-}
+#define seqcount_latch_init(s) seqcount_init(&(s)->seqcount)
 
 /**
  * raw_read_seqcount_latch() - pick even/odd latch data copy
index 30577c3..46fb3eb 100644 (file)
@@ -128,7 +128,7 @@ int stop_machine_from_inactive_cpu(cpu_stop_fn_t fn, void *data,
                                   const struct cpumask *cpus);
 #else  /* CONFIG_SMP || CONFIG_HOTPLUG_CPU */
 
-static inline int stop_machine_cpuslocked(cpu_stop_fn_t fn, void *data,
+static __always_inline int stop_machine_cpuslocked(cpu_stop_fn_t fn, void *data,
                                          const struct cpumask *cpus)
 {
        unsigned long flags;
@@ -139,14 +139,15 @@ static inline int stop_machine_cpuslocked(cpu_stop_fn_t fn, void *data,
        return ret;
 }
 
-static inline int stop_machine(cpu_stop_fn_t fn, void *data,
-                              const struct cpumask *cpus)
+static __always_inline int
+stop_machine(cpu_stop_fn_t fn, void *data, const struct cpumask *cpus)
 {
        return stop_machine_cpuslocked(fn, data, cpus);
 }
 
-static inline int stop_machine_from_inactive_cpu(cpu_stop_fn_t fn, void *data,
-                                                const struct cpumask *cpus)
+static __always_inline int
+stop_machine_from_inactive_cpu(cpu_stop_fn_t fn, void *data,
+                              const struct cpumask *cpus)
 {
        return stop_machine(fn, data, cpus);
 }
index 7c693b3..1e76ed6 100644 (file)
@@ -104,7 +104,6 @@ struct svcxprt_rdma {
 
        wait_queue_head_t    sc_send_wait;      /* SQ exhaustion waitlist */
        unsigned long        sc_flags;
-       u32                  sc_pending_recvs;
        struct list_head     sc_read_complete_q;
        struct work_struct   sc_work;
 
index 13770cf..6673e4d 100644 (file)
@@ -23,7 +23,7 @@ struct ts_config;
 struct ts_state
 {
        unsigned int            offset;
-       char                    cb[40];
+       char                    cb[48];
 };
 
 /**
index 9b2158c..157762d 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/types.h>
 #include <linux/bug.h>
 #include <linux/restart_block.h>
+#include <linux/errno.h>
 
 #ifdef CONFIG_THREAD_INFO_IN_TASK
 /*
@@ -59,6 +60,18 @@ enum syscall_work_bit {
 
 #ifdef __KERNEL__
 
+#ifndef arch_set_restart_data
+#define arch_set_restart_data(restart) do { } while (0)
+#endif
+
+static inline long set_restart_fn(struct restart_block *restart,
+                                       long (*fn)(struct restart_block *))
+{
+       restart->fn = fn;
+       arch_set_restart_data(restart);
+       return -ERESTART_RESTARTBLOCK;
+}
+
 #ifndef THREAD_ALIGN
 #define THREAD_ALIGN   THREAD_SIZE
 #endif
index c6abb79..e81856c 100644 (file)
@@ -115,12 +115,13 @@ static inline void u64_stats_inc(u64_stats_t *p)
 }
 #endif
 
+#if BITS_PER_LONG == 32 && defined(CONFIG_SMP)
+#define u64_stats_init(syncp)  seqcount_init(&(syncp)->seq)
+#else
 static inline void u64_stats_init(struct u64_stats_sync *syncp)
 {
-#if BITS_PER_LONG == 32 && defined(CONFIG_SMP)
-       seqcount_init(&syncp->seq);
-#endif
 }
+#endif
 
 static inline void u64_stats_update_begin(struct u64_stats_sync *syncp)
 {
index 7d72c4e..d6a4184 100644 (file)
@@ -746,6 +746,8 @@ extern int usb_lock_device_for_reset(struct usb_device *udev,
 extern int usb_reset_device(struct usb_device *dev);
 extern void usb_queue_reset_device(struct usb_interface *dev);
 
+extern struct device *usb_intf_get_dma_device(struct usb_interface *intf);
+
 #ifdef CONFIG_ACPI
 extern int usb_acpi_set_power_state(struct usb_device *hdev, int index,
        bool enable);
index 6b03fdd..712363c 100644 (file)
@@ -86,6 +86,8 @@
                /* lies about caching, so always sync */        \
        US_FLAG(NO_SAME, 0x40000000)                            \
                /* Cannot handle WRITE_SAME */                  \
+       US_FLAG(SENSE_AFTER_SYNC, 0x80000000)                   \
+               /* Do REQUEST_SENSE after SYNCHRONIZE_CACHE */  \
 
 #define US_FLAG(name, value)   US_FL_##name = value ,
 enum { US_DO_ALL_FLAGS };
index 4ab5494..15fa085 100644 (file)
@@ -250,20 +250,20 @@ struct vdpa_config_ops {
 
 struct vdpa_device *__vdpa_alloc_device(struct device *parent,
                                        const struct vdpa_config_ops *config,
-                                       int nvqs, size_t size, const char *name);
+                                       size_t size, const char *name);
 
-#define vdpa_alloc_device(dev_struct, member, parent, config, nvqs, name)   \
+#define vdpa_alloc_device(dev_struct, member, parent, config, name)   \
                          container_of(__vdpa_alloc_device( \
-                                      parent, config, nvqs, \
+                                      parent, config, \
                                       sizeof(dev_struct) + \
                                       BUILD_BUG_ON_ZERO(offsetof( \
                                       dev_struct, member)), name), \
                                       dev_struct, member)
 
-int vdpa_register_device(struct vdpa_device *vdev);
+int vdpa_register_device(struct vdpa_device *vdev, int nvqs);
 void vdpa_unregister_device(struct vdpa_device *vdev);
 
-int _vdpa_register_device(struct vdpa_device *vdev);
+int _vdpa_register_device(struct vdpa_device *vdev, int nvqs);
 void _vdpa_unregister_device(struct vdpa_device *vdev);
 
 /**
index 55ea329..b1894e0 100644 (file)
@@ -132,8 +132,6 @@ bool is_virtio_device(struct device *dev);
 void virtio_break_device(struct virtio_device *dev);
 
 void virtio_config_changed(struct virtio_device *dev);
-void virtio_config_disable(struct virtio_device *dev);
-void virtio_config_enable(struct virtio_device *dev);
 int virtio_finalize_features(struct virtio_device *dev);
 #ifdef CONFIG_PM_SLEEP
 int virtio_device_freeze(struct virtio_device *dev);
index e8a924e..6b5fcfa 100644 (file)
@@ -79,8 +79,13 @@ static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
                if (gso_type && skb->network_header) {
                        struct flow_keys_basic keys;
 
-                       if (!skb->protocol)
+                       if (!skb->protocol) {
+                               __be16 protocol = dev_parse_header_protocol(skb);
+
                                virtio_net_hdr_set_proto(skb, hdr);
+                               if (protocol && protocol != skb->protocol)
+                                       return -EINVAL;
+                       }
 retry:
                        if (!skb_flow_dissect_flow_keys_basic(NULL, skb, &keys,
                                                              NULL, 0, 0, 0,
index 850424e..6ecf2a0 100644 (file)
@@ -173,9 +173,10 @@ static inline void ww_acquire_done(struct ww_acquire_ctx *ctx)
  */
 static inline void ww_acquire_fini(struct ww_acquire_ctx *ctx)
 {
-#ifdef CONFIG_DEBUG_MUTEXES
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
        mutex_release(&ctx->dep_map, _THIS_IP_);
-
+#endif
+#ifdef CONFIG_DEBUG_MUTEXES
        DEBUG_LOCKS_WARN_ON(ctx->acquired);
        if (!IS_ENABLED(CONFIG_PROVE_LOCKING))
                /*
index 999b750..30f138e 100644 (file)
@@ -175,6 +175,13 @@ struct rc_map_list {
        struct rc_map map;
 };
 
+#ifdef CONFIG_MEDIA_CEC_RC
+/*
+ * rc_map_list from rc-cec.c
+ */
+extern struct rc_map_list cec_map;
+#endif
+
 /* Routines from rc-map.c */
 
 /**
index 970cc2e..6154a2e 100644 (file)
@@ -30,7 +30,7 @@ TRACE_EVENT(workqueue_queue_work,
        TP_STRUCT__entry(
                __field( void *,        work    )
                __field( void *,        function)
-               __field( const char *,  workqueue)
+               __string( workqueue,    pwq->wq->name)
                __field( unsigned int,  req_cpu )
                __field( unsigned int,  cpu     )
        ),
@@ -38,13 +38,13 @@ TRACE_EVENT(workqueue_queue_work,
        TP_fast_assign(
                __entry->work           = work;
                __entry->function       = work->func;
-               __entry->workqueue      = pwq->wq->name;
+               __assign_str(workqueue, pwq->wq->name);
                __entry->req_cpu        = req_cpu;
                __entry->cpu            = pwq->pool->cpu;
        ),
 
        TP_printk("work struct=%p function=%ps workqueue=%s req_cpu=%u cpu=%u",
-                 __entry->work, __entry->function, __entry->workqueue,
+                 __entry->work, __entry->function, __get_str(workqueue),
                  __entry->req_cpu, __entry->cpu)
 );
 
index 4c24daa..79c8933 100644 (file)
@@ -3850,7 +3850,6 @@ union bpf_attr {
  *
  * long bpf_check_mtu(void *ctx, u32 ifindex, u32 *mtu_len, s32 len_diff, u64 flags)
  *     Description
-
  *             Check ctx packet size against exceeding MTU of net device (based
  *             on *ifindex*).  This helper will likely be used in combination
  *             with helpers that adjust/change the packet size.
index 98ca64d..5444261 100644 (file)
@@ -903,7 +903,8 @@ struct fuse_notify_retrieve_in {
 };
 
 /* Device ioctls: */
-#define FUSE_DEV_IOC_CLONE     _IOR(229, 0, uint32_t)
+#define FUSE_DEV_IOC_MAGIC             229
+#define FUSE_DEV_IOC_CLONE             _IOR(FUSE_DEV_IOC_MAGIC, 0, uint32_t)
 
 struct fuse_lseek_in {
        uint64_t        fh;
index 30c80d5..bab8c97 100644 (file)
@@ -145,6 +145,7 @@ enum {
        L2TP_ATTR_RX_ERRORS,            /* u64 */
        L2TP_ATTR_STATS_PAD,
        L2TP_ATTR_RX_COOKIE_DISCARDS,   /* u64 */
+       L2TP_ATTR_RX_INVALID,           /* u64 */
        __L2TP_ATTR_STATS_MAX,
 };
 
index a13137a..70af020 100644 (file)
@@ -5,7 +5,7 @@
 #define NFCT_HELPER_STATUS_DISABLED    0
 #define NFCT_HELPER_STATUS_ENABLED     1
 
-enum nfnl_acct_msg_types {
+enum nfnl_cthelper_msg_types {
        NFNL_MSG_CTHELPER_NEW,
        NFNL_MSG_CTHELPER_GET,
        NFNL_MSG_CTHELPER_DEL,
index 0b1182a..cb854df 100644 (file)
 #include <linux/page-flags.h>
 #include <linux/kernel.h>
 
+/*
+ * Technically there's no reliably invalid grant reference or grant handle,
+ * so pick the value that is the most unlikely one to be observed valid.
+ */
+#define INVALID_GRANT_REF          ((grant_ref_t)-1)
+#define INVALID_GRANT_HANDLE       ((grant_handle_t)-1)
+
 #define GNTTAB_RESERVED_XENSTORE 1
 
 /* NR_GRANT_FRAMES must be less than or equal to that configured in Xen */
index 0b13860..b94074c 100644 (file)
@@ -51,7 +51,6 @@
 
 #define XENBUS_MAX_RING_GRANT_ORDER 4
 #define XENBUS_MAX_RING_GRANTS      (1U << XENBUS_MAX_RING_GRANT_ORDER)
-#define INVALID_GRANT_HANDLE       (~0U)
 
 /* Register callback to watch this node. */
 struct xenbus_watch
index 22946fe..5f5c776 100644 (file)
@@ -20,10 +20,10 @@ config CC_VERSION_TEXT
            When the compiler is updated, Kconfig will be invoked.
 
          - Ensure full rebuild when the compiler is updated
-           include/linux/kconfig.h contains this option in the comment line so
-           fixdep adds include/config/cc/version/text.h into the auto-generated
-           dependency. When the compiler is updated, syncconfig will touch it
-           and then every file will be rebuilt.
+           include/linux/compiler-version.h contains this option in the comment
+           line so fixdep adds include/config/cc/version/text.h into the
+           auto-generated dependency. When the compiler is updated, syncconfig
+           will touch it and then every file will be rebuilt.
 
 config CC_IS_GCC
        def_bool $(success,test "$(cc-name)" = GCC)
@@ -119,8 +119,7 @@ config INIT_ENV_ARG_LIMIT
 
 config COMPILE_TEST
        bool "Compile also drivers which will not load"
-       depends on !UML && !S390
-       default n
+       depends on HAS_IOMEM
        help
          Some drivers can be compiled on a different platform than they are
          intended to be run on. Despite they cannot be loaded there (or even
index 2efeb5f..b1a76fe 100644 (file)
@@ -4321,8 +4321,6 @@ btf_get_prog_ctx_type(struct bpf_verifier_log *log, struct btf *btf,
                 * is not supported yet.
                 * BPF_PROG_TYPE_RAW_TRACEPOINT is fine.
                 */
-               if (log->level & BPF_LOG_LEVEL)
-                       bpf_log(log, "arg#%d type is not a struct\n", arg);
                return NULL;
        }
        tname = btf_name_by_offset(btf, t->name_off);
index 0ae015a..3a283bf 100644 (file)
@@ -1118,6 +1118,8 @@ static void bpf_prog_clone_free(struct bpf_prog *fp)
         * clone is guaranteed to not be locked.
         */
        fp->aux = NULL;
+       fp->stats = NULL;
+       fp->active = NULL;
        __bpf_prog_free(fp);
 }
 
@@ -2342,6 +2344,10 @@ bool __weak bpf_helper_changes_pkt_data(void *func)
 /* Return TRUE if the JIT backend wants verifier to enable sub-register usage
  * analysis code and wants explicit zero extension inserted by verifier.
  * Otherwise, return FALSE.
+ *
+ * The verifier inserts an explicit zero extension after BPF_CMPXCHGs even if
+ * you don't override this. JITs that don't want these extra insns can detect
+ * them using insn_is_zext.
  */
 bool __weak bpf_jit_needs_zext(void)
 {
index 1dda9d8..c56e3fc 100644 (file)
@@ -504,6 +504,13 @@ static bool is_ptr_cast_function(enum bpf_func_id func_id)
                func_id == BPF_FUNC_skc_to_tcp_request_sock;
 }
 
+static bool is_cmpxchg_insn(const struct bpf_insn *insn)
+{
+       return BPF_CLASS(insn->code) == BPF_STX &&
+              BPF_MODE(insn->code) == BPF_ATOMIC &&
+              insn->imm == BPF_CMPXCHG;
+}
+
 /* string representation of 'enum bpf_reg_type' */
 static const char * const reg_type_str[] = {
        [NOT_INIT]              = "?",
@@ -1120,7 +1127,7 @@ static void mark_ptr_not_null_reg(struct bpf_reg_state *reg)
                reg->type = PTR_TO_RDWR_BUF;
                break;
        default:
-               WARN_ON("unknown nullable register type");
+               WARN_ONCE(1, "unknown nullable register type");
        }
 }
 
@@ -1703,7 +1710,11 @@ static bool is_reg64(struct bpf_verifier_env *env, struct bpf_insn *insn,
        }
 
        if (class == BPF_STX) {
-               if (reg->type != SCALAR_VALUE)
+               /* BPF_STX (including atomic variants) has multiple source
+                * operands, one of which is a ptr. Check whether the caller is
+                * asking about it.
+                */
+               if (t == SRC_OP && reg->type != SCALAR_VALUE)
                        return true;
                return BPF_SIZE(code) == BPF_DW;
        }
@@ -1735,22 +1746,38 @@ static bool is_reg64(struct bpf_verifier_env *env, struct bpf_insn *insn,
        return true;
 }
 
-/* Return TRUE if INSN doesn't have explicit value define. */
-static bool insn_no_def(struct bpf_insn *insn)
+/* Return the regno defined by the insn, or -1. */
+static int insn_def_regno(const struct bpf_insn *insn)
 {
-       u8 class = BPF_CLASS(insn->code);
-
-       return (class == BPF_JMP || class == BPF_JMP32 ||
-               class == BPF_STX || class == BPF_ST);
+       switch (BPF_CLASS(insn->code)) {
+       case BPF_JMP:
+       case BPF_JMP32:
+       case BPF_ST:
+               return -1;
+       case BPF_STX:
+               if (BPF_MODE(insn->code) == BPF_ATOMIC &&
+                   (insn->imm & BPF_FETCH)) {
+                       if (insn->imm == BPF_CMPXCHG)
+                               return BPF_REG_0;
+                       else
+                               return insn->src_reg;
+               } else {
+                       return -1;
+               }
+       default:
+               return insn->dst_reg;
+       }
 }
 
 /* Return TRUE if INSN has defined any 32-bit value explicitly. */
 static bool insn_has_def32(struct bpf_verifier_env *env, struct bpf_insn *insn)
 {
-       if (insn_no_def(insn))
+       int dst_reg = insn_def_regno(insn);
+
+       if (dst_reg == -1)
                return false;
 
-       return !is_reg64(env, insn, insn->dst_reg, NULL, DST_OP);
+       return !is_reg64(env, insn, dst_reg, NULL, DST_OP);
 }
 
 static void mark_insn_zext(struct bpf_verifier_env *env,
@@ -11006,9 +11033,10 @@ static int opt_subreg_zext_lo32_rnd_hi32(struct bpf_verifier_env *env,
        for (i = 0; i < len; i++) {
                int adj_idx = i + delta;
                struct bpf_insn insn;
-               u8 load_reg;
+               int load_reg;
 
                insn = insns[adj_idx];
+               load_reg = insn_def_regno(&insn);
                if (!aux[adj_idx].zext_dst) {
                        u8 code, class;
                        u32 imm_rnd;
@@ -11018,14 +11046,14 @@ static int opt_subreg_zext_lo32_rnd_hi32(struct bpf_verifier_env *env,
 
                        code = insn.code;
                        class = BPF_CLASS(code);
-                       if (insn_no_def(&insn))
+                       if (load_reg == -1)
                                continue;
 
                        /* NOTE: arg "reg" (the fourth one) is only used for
-                        *       BPF_STX which has been ruled out in above
-                        *       check, it is safe to pass NULL here.
+                        *       BPF_STX + SRC_OP, so it is safe to pass NULL
+                        *       here.
                         */
-                       if (is_reg64(env, &insn, insn.dst_reg, NULL, DST_OP)) {
+                       if (is_reg64(env, &insn, load_reg, NULL, DST_OP)) {
                                if (class == BPF_LD &&
                                    BPF_MODE(code) == BPF_IMM)
                                        i++;
@@ -11040,31 +11068,28 @@ static int opt_subreg_zext_lo32_rnd_hi32(struct bpf_verifier_env *env,
                        imm_rnd = get_random_int();
                        rnd_hi32_patch[0] = insn;
                        rnd_hi32_patch[1].imm = imm_rnd;
-                       rnd_hi32_patch[3].dst_reg = insn.dst_reg;
+                       rnd_hi32_patch[3].dst_reg = load_reg;
                        patch = rnd_hi32_patch;
                        patch_len = 4;
                        goto apply_patch_buffer;
                }
 
-               if (!bpf_jit_needs_zext())
+               /* Add in an zero-extend instruction if a) the JIT has requested
+                * it or b) it's a CMPXCHG.
+                *
+                * The latter is because: BPF_CMPXCHG always loads a value into
+                * R0, therefore always zero-extends. However some archs'
+                * equivalent instruction only does this load when the
+                * comparison is successful. This detail of CMPXCHG is
+                * orthogonal to the general zero-extension behaviour of the
+                * CPU, so it's treated independently of bpf_jit_needs_zext.
+                */
+               if (!bpf_jit_needs_zext() && !is_cmpxchg_insn(&insn))
                        continue;
 
-               /* zext_dst means that we want to zero-extend whatever register
-                * the insn defines, which is dst_reg most of the time, with
-                * the notable exception of BPF_STX + BPF_ATOMIC + BPF_FETCH.
-                */
-               if (BPF_CLASS(insn.code) == BPF_STX &&
-                   BPF_MODE(insn.code) == BPF_ATOMIC) {
-                       /* BPF_STX + BPF_ATOMIC insns without BPF_FETCH do not
-                        * define any registers, therefore zext_dst cannot be
-                        * set.
-                        */
-                       if (WARN_ON(!(insn.imm & BPF_FETCH)))
-                               return -EINVAL;
-                       load_reg = insn.imm == BPF_CMPXCHG ? BPF_REG_0
-                                                          : insn.src_reg;
-               } else {
-                       load_reg = insn.dst_reg;
+               if (WARN_ON(load_reg == -1)) {
+                       verbose(env, "verifier bug. zext_dst is set, but no reg is defined\n");
+                       return -EFAULT;
                }
 
                zext_patch[0] = insn;
index 0aeca5f..03db40f 100644 (file)
@@ -386,6 +386,7 @@ static DEFINE_MUTEX(perf_sched_mutex);
 static atomic_t perf_sched_count;
 
 static DEFINE_PER_CPU(atomic_t, perf_cgroup_events);
+static DEFINE_PER_CPU(int, perf_sched_cb_usages);
 static DEFINE_PER_CPU(struct pmu_event_list, pmu_sb_events);
 
 static atomic_t nr_mmap_events __read_mostly;
@@ -3461,11 +3462,16 @@ unlock:
        }
 }
 
+static DEFINE_PER_CPU(struct list_head, sched_cb_list);
+
 void perf_sched_cb_dec(struct pmu *pmu)
 {
        struct perf_cpu_context *cpuctx = this_cpu_ptr(pmu->pmu_cpu_context);
 
-       --cpuctx->sched_cb_usage;
+       this_cpu_dec(perf_sched_cb_usages);
+
+       if (!--cpuctx->sched_cb_usage)
+               list_del(&cpuctx->sched_cb_entry);
 }
 
 
@@ -3473,7 +3479,10 @@ void perf_sched_cb_inc(struct pmu *pmu)
 {
        struct perf_cpu_context *cpuctx = this_cpu_ptr(pmu->pmu_cpu_context);
 
-       cpuctx->sched_cb_usage++;
+       if (!cpuctx->sched_cb_usage++)
+               list_add(&cpuctx->sched_cb_entry, this_cpu_ptr(&sched_cb_list));
+
+       this_cpu_inc(perf_sched_cb_usages);
 }
 
 /*
@@ -3502,6 +3511,24 @@ static void __perf_pmu_sched_task(struct perf_cpu_context *cpuctx, bool sched_in
        perf_ctx_unlock(cpuctx, cpuctx->task_ctx);
 }
 
+static void perf_pmu_sched_task(struct task_struct *prev,
+                               struct task_struct *next,
+                               bool sched_in)
+{
+       struct perf_cpu_context *cpuctx;
+
+       if (prev == next)
+               return;
+
+       list_for_each_entry(cpuctx, this_cpu_ptr(&sched_cb_list), sched_cb_entry) {
+               /* will be handled in perf_event_context_sched_in/out */
+               if (cpuctx->task_ctx)
+                       continue;
+
+               __perf_pmu_sched_task(cpuctx, sched_in);
+       }
+}
+
 static void perf_event_switch(struct task_struct *task,
                              struct task_struct *next_prev, bool sched_in);
 
@@ -3524,6 +3551,9 @@ void __perf_event_task_sched_out(struct task_struct *task,
 {
        int ctxn;
 
+       if (__this_cpu_read(perf_sched_cb_usages))
+               perf_pmu_sched_task(task, next, false);
+
        if (atomic_read(&nr_switch_events))
                perf_event_switch(task, next, false);
 
@@ -3832,6 +3862,9 @@ void __perf_event_task_sched_in(struct task_struct *prev,
 
        if (atomic_read(&nr_switch_events))
                perf_event_switch(task, prev, true);
+
+       if (__this_cpu_read(perf_sched_cb_usages))
+               perf_pmu_sched_task(prev, task, true);
 }
 
 static u64 perf_calculate_period(struct perf_event *event, u64 nsec, u64 count)
@@ -4656,7 +4689,7 @@ static void unaccount_event(struct perf_event *event)
        if (event->parent)
                return;
 
-       if (event->attach_state & PERF_ATTACH_TASK)
+       if (event->attach_state & (PERF_ATTACH_TASK | PERF_ATTACH_SCHED_CB))
                dec = true;
        if (event->attr.mmap || event->attr.mmap_data)
                atomic_dec(&nr_mmap_events);
@@ -11175,7 +11208,7 @@ static void account_event(struct perf_event *event)
        if (event->parent)
                return;
 
-       if (event->attach_state & PERF_ATTACH_TASK)
+       if (event->attach_state & (PERF_ATTACH_TASK | PERF_ATTACH_SCHED_CB))
                inc = true;
        if (event->attr.mmap || event->attr.mmap_data)
                atomic_inc(&nr_mmap_events);
@@ -12972,6 +13005,7 @@ static void __init perf_event_init_all_cpus(void)
 #ifdef CONFIG_CGROUP_PERF
                INIT_LIST_HEAD(&per_cpu(cgrp_cpuctx_list, cpu));
 #endif
+               INIT_LIST_HEAD(&per_cpu(sched_cb_list, cpu));
        }
 }
 
index d3171e8..54cc905 100644 (file)
@@ -994,6 +994,13 @@ static void mm_init_owner(struct mm_struct *mm, struct task_struct *p)
 #endif
 }
 
+static void mm_init_pasid(struct mm_struct *mm)
+{
+#ifdef CONFIG_IOMMU_SUPPORT
+       mm->pasid = INIT_PASID;
+#endif
+}
+
 static void mm_init_uprobes_state(struct mm_struct *mm)
 {
 #ifdef CONFIG_UPROBES
@@ -1024,6 +1031,7 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p,
        mm_init_cpumask(mm);
        mm_init_aio(mm);
        mm_init_owner(mm, p);
+       mm_init_pasid(mm);
        RCU_INIT_POINTER(mm->exe_file, NULL);
        mmu_notifier_subscriptions_init(mm);
        init_tlb_flush_pending(mm);
index dc520f0..1a2d57d 100644 (file)
@@ -134,7 +134,7 @@ bool freeze_task(struct task_struct *p)
                return false;
        }
 
-       if (!(p->flags & PF_KTHREAD))
+       if (!(p->flags & (PF_KTHREAD | PF_IO_WORKER)))
                fake_signal_wake_up(p);
        else
                wake_up_state(p, TASK_INTERRUPTIBLE);
index e68db77..00febd6 100644 (file)
@@ -2728,14 +2728,13 @@ retry:
                goto out;
 
        restart = &current->restart_block;
-       restart->fn = futex_wait_restart;
        restart->futex.uaddr = uaddr;
        restart->futex.val = val;
        restart->futex.time = *abs_time;
        restart->futex.bitset = bitset;
        restart->futex.flags = flags | FLAGS_HAS_TIMEOUT;
 
-       ret = -ERESTART_RESTARTBLOCK;
+       ret = set_restart_fn(restart, futex_wait_restart);
 
 out:
        if (to) {
index 4800660..40880c3 100644 (file)
@@ -159,7 +159,7 @@ static const struct irq_domain_ops irq_sim_domain_ops = {
  * irq_domain_create_sim - Create a new interrupt simulator irq_domain and
  *                         allocate a range of dummy interrupts.
  *
- * @fnode:      struct fwnode_handle to be associated with this domain.
+ * @fwnode:     struct fwnode_handle to be associated with this domain.
  * @num_irqs:   Number of interrupts to allocate.
  *
  * On success: return a new irq_domain object.
@@ -228,7 +228,7 @@ static void devm_irq_domain_release_sim(struct device *dev, void *res)
  *                              a managed device.
  *
  * @dev:        Device to initialize the simulator object for.
- * @fnode:      struct fwnode_handle to be associated with this domain.
+ * @fwnode:     struct fwnode_handle to be associated with this domain.
  * @num_irqs:   Number of interrupts to allocate
  *
  * On success: return a new irq_domain object.
index 2881513..d10ab1d 100644 (file)
@@ -1898,16 +1898,15 @@ DEFINE_SHOW_ATTRIBUTE(irq_domain_debug);
 
 static void debugfs_add_domain_dir(struct irq_domain *d)
 {
-       if (!d->name || !domain_dir || d->debugfs_file)
+       if (!d->name || !domain_dir)
                return;
-       d->debugfs_file = debugfs_create_file(d->name, 0444, domain_dir, d,
-                                             &irq_domain_debug_fops);
+       debugfs_create_file(d->name, 0444, domain_dir, d,
+                           &irq_domain_debug_fops);
 }
 
 static void debugfs_remove_domain_dir(struct irq_domain *d)
 {
-       debugfs_remove(d->debugfs_file);
-       d->debugfs_file = NULL;
+       debugfs_remove(debugfs_lookup(d->name, domain_dir));
 }
 
 void __init irq_domain_debugfs_init(struct dentry *root)
index dec3f73..21ea370 100644 (file)
@@ -1142,11 +1142,15 @@ irq_forced_thread_fn(struct irq_desc *desc, struct irqaction *action)
        irqreturn_t ret;
 
        local_bh_disable();
+       if (!IS_ENABLED(CONFIG_PREEMPT_RT))
+               local_irq_disable();
        ret = action->thread_fn(action->irq, action->dev_id);
        if (ret == IRQ_HANDLED)
                atomic_inc(&desc->threads_handled);
 
        irq_finalize_oneshot(desc, action);
+       if (!IS_ENABLED(CONFIG_PREEMPT_RT))
+               local_irq_enable();
        local_bh_enable();
        return ret;
 }
index c6a39d6..ba39fbb 100644 (file)
@@ -407,6 +407,14 @@ static bool jump_label_can_update(struct jump_entry *entry, bool init)
                return false;
 
        if (!kernel_text_address(jump_entry_code(entry))) {
+               /*
+                * This skips patching built-in __exit, which
+                * is part of init_section_contains() but is
+                * not part of kernel_text_address().
+                *
+                * Skipping built-in __exit is fine since it
+                * will never be executed.
+                */
                WARN_ONCE(!jump_entry_is_init(entry),
                          "can't patch jump_label at %pS",
                          (void *)jump_entry_code(entry));
index adb9350..622ebdf 100644 (file)
@@ -626,7 +626,7 @@ static inline int mutex_can_spin_on_owner(struct mutex *lock)
  */
 static __always_inline bool
 mutex_optimistic_spin(struct mutex *lock, struct ww_acquire_ctx *ww_ctx,
-                     const bool use_ww_ctx, struct mutex_waiter *waiter)
+                     struct mutex_waiter *waiter)
 {
        if (!waiter) {
                /*
@@ -702,7 +702,7 @@ fail:
 #else
 static __always_inline bool
 mutex_optimistic_spin(struct mutex *lock, struct ww_acquire_ctx *ww_ctx,
-                     const bool use_ww_ctx, struct mutex_waiter *waiter)
+                     struct mutex_waiter *waiter)
 {
        return false;
 }
@@ -922,6 +922,9 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
        struct ww_mutex *ww;
        int ret;
 
+       if (!use_ww_ctx)
+               ww_ctx = NULL;
+
        might_sleep();
 
 #ifdef CONFIG_DEBUG_MUTEXES
@@ -929,7 +932,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
 #endif
 
        ww = container_of(lock, struct ww_mutex, base);
-       if (use_ww_ctx && ww_ctx) {
+       if (ww_ctx) {
                if (unlikely(ww_ctx == READ_ONCE(ww->ctx)))
                        return -EALREADY;
 
@@ -946,10 +949,10 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
        mutex_acquire_nest(&lock->dep_map, subclass, 0, nest_lock, ip);
 
        if (__mutex_trylock(lock) ||
-           mutex_optimistic_spin(lock, ww_ctx, use_ww_ctx, NULL)) {
+           mutex_optimistic_spin(lock, ww_ctx, NULL)) {
                /* got the lock, yay! */
                lock_acquired(&lock->dep_map, ip);
-               if (use_ww_ctx && ww_ctx)
+               if (ww_ctx)
                        ww_mutex_set_context_fastpath(ww, ww_ctx);
                preempt_enable();
                return 0;
@@ -960,7 +963,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
         * After waiting to acquire the wait_lock, try again.
         */
        if (__mutex_trylock(lock)) {
-               if (use_ww_ctx && ww_ctx)
+               if (ww_ctx)
                        __ww_mutex_check_waiters(lock, ww_ctx);
 
                goto skip_wait;
@@ -1013,7 +1016,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
                        goto err;
                }
 
-               if (use_ww_ctx && ww_ctx) {
+               if (ww_ctx) {
                        ret = __ww_mutex_check_kill(lock, &waiter, ww_ctx);
                        if (ret)
                                goto err;
@@ -1026,7 +1029,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
                 * ww_mutex needs to always recheck its position since its waiter
                 * list is not FIFO ordered.
                 */
-               if ((use_ww_ctx && ww_ctx) || !first) {
+               if (ww_ctx || !first) {
                        first = __mutex_waiter_is_first(lock, &waiter);
                        if (first)
                                __mutex_set_flag(lock, MUTEX_FLAG_HANDOFF);
@@ -1039,7 +1042,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
                 * or we must see its unlock and acquire.
                 */
                if (__mutex_trylock(lock) ||
-                   (first && mutex_optimistic_spin(lock, ww_ctx, use_ww_ctx, &waiter)))
+                   (first && mutex_optimistic_spin(lock, ww_ctx, &waiter)))
                        break;
 
                spin_lock(&lock->wait_lock);
@@ -1048,7 +1051,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
 acquired:
        __set_current_state(TASK_RUNNING);
 
-       if (use_ww_ctx && ww_ctx) {
+       if (ww_ctx) {
                /*
                 * Wound-Wait; we stole the lock (!first_waiter), check the
                 * waiters as anyone might want to wound us.
@@ -1068,7 +1071,7 @@ skip_wait:
        /* got the lock - cleanup and rejoice! */
        lock_acquired(&lock->dep_map, ip);
 
-       if (use_ww_ctx && ww_ctx)
+       if (ww_ctx)
                ww_mutex_lock_acquired(ww, ww_ctx);
 
        spin_unlock(&lock->wait_lock);
index eb1b158..a6ad5eb 100644 (file)
@@ -244,8 +244,6 @@ void migrate_to_reboot_cpu(void)
 void kernel_restart(char *cmd)
 {
        kernel_restart_prepare(cmd);
-       if (pm_power_off_prepare)
-               pm_power_off_prepare();
        migrate_to_reboot_cpu();
        syscore_shutdown();
        if (!cmd)
index ca2bb62..9819121 100644 (file)
@@ -1862,8 +1862,13 @@ struct migration_arg {
        struct set_affinity_pending     *pending;
 };
 
+/*
+ * @refs: number of wait_for_completion()
+ * @stop_pending: is @stop_work in use
+ */
 struct set_affinity_pending {
        refcount_t              refs;
+       unsigned int            stop_pending;
        struct completion       done;
        struct cpu_stop_work    stop_work;
        struct migration_arg    arg;
@@ -1898,8 +1903,8 @@ static struct rq *__migrate_task(struct rq *rq, struct rq_flags *rf,
  */
 static int migration_cpu_stop(void *data)
 {
-       struct set_affinity_pending *pending;
        struct migration_arg *arg = data;
+       struct set_affinity_pending *pending = arg->pending;
        struct task_struct *p = arg->task;
        int dest_cpu = arg->dest_cpu;
        struct rq *rq = this_rq();
@@ -1921,7 +1926,6 @@ static int migration_cpu_stop(void *data)
        raw_spin_lock(&p->pi_lock);
        rq_lock(rq, &rf);
 
-       pending = p->migration_pending;
        /*
         * If task_rq(p) != rq, it cannot be migrated here, because we're
         * holding rq->lock, if p->on_rq == 0 it cannot get enqueued because
@@ -1932,21 +1936,14 @@ static int migration_cpu_stop(void *data)
                        goto out;
 
                if (pending) {
-                       p->migration_pending = NULL;
+                       if (p->migration_pending == pending)
+                               p->migration_pending = NULL;
                        complete = true;
                }
 
-               /* migrate_enable() --  we must not race against SCA */
                if (dest_cpu < 0) {
-                       /*
-                        * When this was migrate_enable() but we no longer
-                        * have a @pending, a concurrent SCA 'fixed' things
-                        * and we should be valid again. Nothing to do.
-                        */
-                       if (!pending) {
-                               WARN_ON_ONCE(!cpumask_test_cpu(task_cpu(p), &p->cpus_mask));
+                       if (cpumask_test_cpu(task_cpu(p), &p->cpus_mask))
                                goto out;
-                       }
 
                        dest_cpu = cpumask_any_distribute(&p->cpus_mask);
                }
@@ -1956,7 +1953,14 @@ static int migration_cpu_stop(void *data)
                else
                        p->wake_cpu = dest_cpu;
 
-       } else if (dest_cpu < 0 || pending) {
+               /*
+                * XXX __migrate_task() can fail, at which point we might end
+                * up running on a dodgy CPU, AFAICT this can only happen
+                * during CPU hotplug, at which point we'll get pushed out
+                * anyway, so it's probably not a big deal.
+                */
+
+       } else if (pending) {
                /*
                 * This happens when we get migrated between migrate_enable()'s
                 * preempt_enable() and scheduling the stopper task. At that
@@ -1971,43 +1975,32 @@ static int migration_cpu_stop(void *data)
                 * ->pi_lock, so the allowed mask is stable - if it got
                 * somewhere allowed, we're done.
                 */
-               if (pending && cpumask_test_cpu(task_cpu(p), p->cpus_ptr)) {
-                       p->migration_pending = NULL;
+               if (cpumask_test_cpu(task_cpu(p), p->cpus_ptr)) {
+                       if (p->migration_pending == pending)
+                               p->migration_pending = NULL;
                        complete = true;
                        goto out;
                }
 
-               /*
-                * When this was migrate_enable() but we no longer have an
-                * @pending, a concurrent SCA 'fixed' things and we should be
-                * valid again. Nothing to do.
-                */
-               if (!pending) {
-                       WARN_ON_ONCE(!cpumask_test_cpu(task_cpu(p), &p->cpus_mask));
-                       goto out;
-               }
-
                /*
                 * When migrate_enable() hits a rq mis-match we can't reliably
                 * determine is_migration_disabled() and so have to chase after
                 * it.
                 */
+               WARN_ON_ONCE(!pending->stop_pending);
                task_rq_unlock(rq, p, &rf);
                stop_one_cpu_nowait(task_cpu(p), migration_cpu_stop,
                                    &pending->arg, &pending->stop_work);
                return 0;
        }
 out:
+       if (pending)
+               pending->stop_pending = false;
        task_rq_unlock(rq, p, &rf);
 
        if (complete)
                complete_all(&pending->done);
 
-       /* For pending->{arg,stop_work} */
-       pending = arg->pending;
-       if (pending && refcount_dec_and_test(&pending->refs))
-               wake_up_var(&pending->refs);
-
        return 0;
 }
 
@@ -2194,11 +2187,7 @@ static int affine_move_task(struct rq *rq, struct task_struct *p, struct rq_flag
                            int dest_cpu, unsigned int flags)
 {
        struct set_affinity_pending my_pending = { }, *pending = NULL;
-       struct migration_arg arg = {
-               .task = p,
-               .dest_cpu = dest_cpu,
-       };
-       bool complete = false;
+       bool stop_pending, complete = false;
 
        /* Can the task run on the task's current CPU? If so, we're done */
        if (cpumask_test_cpu(task_cpu(p), &p->cpus_mask)) {
@@ -2210,12 +2199,16 @@ static int affine_move_task(struct rq *rq, struct task_struct *p, struct rq_flag
                        push_task = get_task_struct(p);
                }
 
+               /*
+                * If there are pending waiters, but no pending stop_work,
+                * then complete now.
+                */
                pending = p->migration_pending;
-               if (pending) {
-                       refcount_inc(&pending->refs);
+               if (pending && !pending->stop_pending) {
                        p->migration_pending = NULL;
                        complete = true;
                }
+
                task_rq_unlock(rq, p, rf);
 
                if (push_task) {
@@ -2224,7 +2217,7 @@ static int affine_move_task(struct rq *rq, struct task_struct *p, struct rq_flag
                }
 
                if (complete)
-                       goto do_complete;
+                       complete_all(&pending->done);
 
                return 0;
        }
@@ -2235,6 +2228,12 @@ static int affine_move_task(struct rq *rq, struct task_struct *p, struct rq_flag
                        /* Install the request */
                        refcount_set(&my_pending.refs, 1);
                        init_completion(&my_pending.done);
+                       my_pending.arg = (struct migration_arg) {
+                               .task = p,
+                               .dest_cpu = -1,         /* any */
+                               .pending = &my_pending,
+                       };
+
                        p->migration_pending = &my_pending;
                } else {
                        pending = p->migration_pending;
@@ -2259,45 +2258,41 @@ static int affine_move_task(struct rq *rq, struct task_struct *p, struct rq_flag
                return -EINVAL;
        }
 
-       if (flags & SCA_MIGRATE_ENABLE) {
-
-               refcount_inc(&pending->refs); /* pending->{arg,stop_work} */
-               p->migration_flags &= ~MDF_PUSH;
-               task_rq_unlock(rq, p, rf);
-
-               pending->arg = (struct migration_arg) {
-                       .task = p,
-                       .dest_cpu = -1,
-                       .pending = pending,
-               };
-
-               stop_one_cpu_nowait(cpu_of(rq), migration_cpu_stop,
-                                   &pending->arg, &pending->stop_work);
-
-               return 0;
-       }
-
        if (task_running(rq, p) || p->state == TASK_WAKING) {
                /*
-                * Lessen races (and headaches) by delegating
-                * is_migration_disabled(p) checks to the stopper, which will
-                * run on the same CPU as said p.
+                * MIGRATE_ENABLE gets here because 'p == current', but for
+                * anything else we cannot do is_migration_disabled(), punt
+                * and have the stopper function handle it all race-free.
                 */
+               stop_pending = pending->stop_pending;
+               if (!stop_pending)
+                       pending->stop_pending = true;
+
+               if (flags & SCA_MIGRATE_ENABLE)
+                       p->migration_flags &= ~MDF_PUSH;
+
                task_rq_unlock(rq, p, rf);
-               stop_one_cpu(cpu_of(rq), migration_cpu_stop, &arg);
 
+               if (!stop_pending) {
+                       stop_one_cpu_nowait(cpu_of(rq), migration_cpu_stop,
+                                           &pending->arg, &pending->stop_work);
+               }
+
+               if (flags & SCA_MIGRATE_ENABLE)
+                       return 0;
        } else {
 
                if (!is_migration_disabled(p)) {
                        if (task_on_rq_queued(p))
                                rq = move_queued_task(rq, rf, p, dest_cpu);
 
-                       p->migration_pending = NULL;
-                       complete = true;
+                       if (!pending->stop_pending) {
+                               p->migration_pending = NULL;
+                               complete = true;
+                       }
                }
                task_rq_unlock(rq, p, rf);
 
-do_complete:
                if (complete)
                        complete_all(&pending->done);
        }
@@ -2305,7 +2300,7 @@ do_complete:
        wait_for_completion(&pending->done);
 
        if (refcount_dec_and_test(&pending->refs))
-               wake_up_var(&pending->refs);
+               wake_up_var(&pending->refs); /* No UaF, just an address */
 
        /*
         * Block the original owner of &pending until all subsequent callers
@@ -2313,6 +2308,9 @@ do_complete:
         */
        wait_var_event(&my_pending.refs, !refcount_read(&my_pending.refs));
 
+       /* ARGH */
+       WARN_ON_ONCE(my_pending.stop_pending);
+
        return 0;
 }
 
index acdae62..b5add64 100644 (file)
@@ -471,9 +471,7 @@ static int sync_runqueues_membarrier_state(struct mm_struct *mm)
        }
        rcu_read_unlock();
 
-       preempt_disable();
-       smp_call_function_many(tmpmask, ipi_sync_rq_state, mm, 1);
-       preempt_enable();
+       on_each_cpu_mask(tmpmask, ipi_sync_rq_state, mm, true);
 
        free_cpumask_var(tmpmask);
        cpus_read_unlock();
index ba4d1ef..f2a1b89 100644 (file)
@@ -288,7 +288,8 @@ bool task_set_jobctl_pending(struct task_struct *task, unsigned long mask)
                        JOBCTL_STOP_SIGMASK | JOBCTL_TRAPPING));
        BUG_ON((mask & JOBCTL_TRAPPING) && !(mask & JOBCTL_PENDING_MASK));
 
-       if (unlikely(fatal_signal_pending(task) || (task->flags & PF_EXITING)))
+       if (unlikely(fatal_signal_pending(task) ||
+                    (task->flags & (PF_EXITING | PF_IO_WORKER))))
                return false;
 
        if (mask & JOBCTL_STOP_SIGMASK)
@@ -833,6 +834,9 @@ static int check_kill_permission(int sig, struct kernel_siginfo *info,
 
        if (!valid_signal(sig))
                return -EINVAL;
+       /* PF_IO_WORKER threads don't take any signals */
+       if (t->flags & PF_IO_WORKER)
+               return -ESRCH;
 
        if (!si_fromuser(info))
                return 0;
index 6906c6e..2c5950b 100644 (file)
@@ -35,27 +35,30 @@ static inline void *static_call_addr(struct static_call_site *site)
        return (void *)((long)site->addr + (long)&site->addr);
 }
 
+static inline unsigned long __static_call_key(const struct static_call_site *site)
+{
+       return (long)site->key + (long)&site->key;
+}
 
 static inline struct static_call_key *static_call_key(const struct static_call_site *site)
 {
-       return (struct static_call_key *)
-               (((long)site->key + (long)&site->key) & ~STATIC_CALL_SITE_FLAGS);
+       return (void *)(__static_call_key(site) & ~STATIC_CALL_SITE_FLAGS);
 }
 
 /* These assume the key is word-aligned. */
 static inline bool static_call_is_init(struct static_call_site *site)
 {
-       return ((long)site->key + (long)&site->key) & STATIC_CALL_SITE_INIT;
+       return __static_call_key(site) & STATIC_CALL_SITE_INIT;
 }
 
 static inline bool static_call_is_tail(struct static_call_site *site)
 {
-       return ((long)site->key + (long)&site->key) & STATIC_CALL_SITE_TAIL;
+       return __static_call_key(site) & STATIC_CALL_SITE_TAIL;
 }
 
 static inline void static_call_set_init(struct static_call_site *site)
 {
-       site->key = ((long)static_call_key(site) | STATIC_CALL_SITE_INIT) -
+       site->key = (__static_call_key(site) | STATIC_CALL_SITE_INIT) -
                    (long)&site->key;
 }
 
@@ -146,6 +149,7 @@ void __static_call_update(struct static_call_key *key, void *tramp, void *func)
        };
 
        for (site_mod = &first; site_mod; site_mod = site_mod->next) {
+               bool init = system_state < SYSTEM_RUNNING;
                struct module *mod = site_mod->mod;
 
                if (!site_mod->sites) {
@@ -165,6 +169,7 @@ void __static_call_update(struct static_call_key *key, void *tramp, void *func)
                if (mod) {
                        stop = mod->static_call_sites +
                               mod->num_static_call_sites;
+                       init = mod->state == MODULE_STATE_COMING;
                }
 #endif
 
@@ -172,25 +177,26 @@ void __static_call_update(struct static_call_key *key, void *tramp, void *func)
                     site < stop && static_call_key(site) == key; site++) {
                        void *site_addr = static_call_addr(site);
 
-                       if (static_call_is_init(site)) {
-                               /*
-                                * Don't write to call sites which were in
-                                * initmem and have since been freed.
-                                */
-                               if (!mod && system_state >= SYSTEM_RUNNING)
-                                       continue;
-                               if (mod && !within_module_init((unsigned long)site_addr, mod))
-                                       continue;
-                       }
+                       if (!init && static_call_is_init(site))
+                               continue;
 
                        if (!kernel_text_address((unsigned long)site_addr)) {
-                               WARN_ONCE(1, "can't patch static call site at %pS",
+                               /*
+                                * This skips patching built-in __exit, which
+                                * is part of init_section_contains() but is
+                                * not part of kernel_text_address().
+                                *
+                                * Skipping built-in __exit is fine since it
+                                * will never be executed.
+                                */
+                               WARN_ONCE(!static_call_is_init(site),
+                                         "can't patch static call site at %pS",
                                          site_addr);
                                continue;
                        }
 
                        arch_static_call_transform(site_addr, NULL, func,
-                               static_call_is_tail(site));
+                                                  static_call_is_tail(site));
                }
        }
 
@@ -349,7 +355,8 @@ static int static_call_add_module(struct module *mod)
        struct static_call_site *site;
 
        for (site = start; site != stop; site++) {
-               unsigned long addr = (unsigned long)static_call_key(site);
+               unsigned long s_key = __static_call_key(site);
+               unsigned long addr = s_key & ~STATIC_CALL_SITE_FLAGS;
                unsigned long key;
 
                /*
@@ -373,8 +380,8 @@ static int static_call_add_module(struct module *mod)
                        return -EINVAL;
                }
 
-               site->key = (key - (long)&site->key) |
-                           (site->key & STATIC_CALL_SITE_FLAGS);
+               key |= s_key & STATIC_CALL_SITE_FLAGS;
+               site->key = key - (long)&site->key;
        }
 
        return __static_call_init(mod, start, stop);
index b09fe21..2e2e3f3 100644 (file)
@@ -2079,7 +2079,7 @@ static int prctl_set_auxv(struct mm_struct *mm, unsigned long addr,
         * up to the caller to provide sane values here, otherwise userspace
         * tools which use this vector might be unhappy.
         */
-       unsigned long user_auxv[AT_VECTOR_SIZE];
+       unsigned long user_auxv[AT_VECTOR_SIZE] = {};
 
        if (len > sizeof(user_auxv))
                return -EINVAL;
index 98d7a15..4d94e2b 100644 (file)
@@ -854,9 +854,9 @@ static int alarm_timer_nsleep(const clockid_t which_clock, int flags,
        if (flags == TIMER_ABSTIME)
                return -ERESTARTNOHAND;
 
-       restart->fn = alarm_timer_nsleep_restart;
        restart->nanosleep.clockid = type;
        restart->nanosleep.expires = exp;
+       set_restart_fn(restart, alarm_timer_nsleep_restart);
        return ret;
 }
 
index 743c852..5c9d968 100644 (file)
@@ -546,8 +546,11 @@ static ktime_t __hrtimer_next_event_base(struct hrtimer_cpu_base *cpu_base,
 }
 
 /*
- * Recomputes cpu_base::*next_timer and returns the earliest expires_next but
- * does not set cpu_base::*expires_next, that is done by hrtimer_reprogram.
+ * Recomputes cpu_base::*next_timer and returns the earliest expires_next
+ * but does not set cpu_base::*expires_next, that is done by
+ * hrtimer[_force]_reprogram and hrtimer_interrupt only. When updating
+ * cpu_base::*expires_next right away, reprogramming logic would no longer
+ * work.
  *
  * When a softirq is pending, we can ignore the HRTIMER_ACTIVE_SOFT bases,
  * those timers will get run whenever the softirq gets handled, at the end of
@@ -588,6 +591,37 @@ __hrtimer_get_next_event(struct hrtimer_cpu_base *cpu_base, unsigned int active_
        return expires_next;
 }
 
+static ktime_t hrtimer_update_next_event(struct hrtimer_cpu_base *cpu_base)
+{
+       ktime_t expires_next, soft = KTIME_MAX;
+
+       /*
+        * If the soft interrupt has already been activated, ignore the
+        * soft bases. They will be handled in the already raised soft
+        * interrupt.
+        */
+       if (!cpu_base->softirq_activated) {
+               soft = __hrtimer_get_next_event(cpu_base, HRTIMER_ACTIVE_SOFT);
+               /*
+                * Update the soft expiry time. clock_settime() might have
+                * affected it.
+                */
+               cpu_base->softirq_expires_next = soft;
+       }
+
+       expires_next = __hrtimer_get_next_event(cpu_base, HRTIMER_ACTIVE_HARD);
+       /*
+        * If a softirq timer is expiring first, update cpu_base->next_timer
+        * and program the hardware with the soft expiry time.
+        */
+       if (expires_next > soft) {
+               cpu_base->next_timer = cpu_base->softirq_next_timer;
+               expires_next = soft;
+       }
+
+       return expires_next;
+}
+
 static inline ktime_t hrtimer_update_base(struct hrtimer_cpu_base *base)
 {
        ktime_t *offs_real = &base->clock_base[HRTIMER_BASE_REALTIME].offset;
@@ -628,23 +662,7 @@ hrtimer_force_reprogram(struct hrtimer_cpu_base *cpu_base, int skip_equal)
 {
        ktime_t expires_next;
 
-       /*
-        * Find the current next expiration time.
-        */
-       expires_next = __hrtimer_get_next_event(cpu_base, HRTIMER_ACTIVE_ALL);
-
-       if (cpu_base->next_timer && cpu_base->next_timer->is_soft) {
-               /*
-                * When the softirq is activated, hrtimer has to be
-                * programmed with the first hard hrtimer because soft
-                * timer interrupt could occur too late.
-                */
-               if (cpu_base->softirq_activated)
-                       expires_next = __hrtimer_get_next_event(cpu_base,
-                                                               HRTIMER_ACTIVE_HARD);
-               else
-                       cpu_base->softirq_expires_next = expires_next;
-       }
+       expires_next = hrtimer_update_next_event(cpu_base);
 
        if (skip_equal && expires_next == cpu_base->expires_next)
                return;
@@ -1644,8 +1662,8 @@ retry:
 
        __hrtimer_run_queues(cpu_base, now, flags, HRTIMER_ACTIVE_HARD);
 
-       /* Reevaluate the clock bases for the next expiry */
-       expires_next = __hrtimer_get_next_event(cpu_base, HRTIMER_ACTIVE_ALL);
+       /* Reevaluate the clock bases for the [soft] next expiry */
+       expires_next = hrtimer_update_next_event(cpu_base);
        /*
         * Store the new expiry value so the migration code can verify
         * against it.
@@ -1939,9 +1957,9 @@ long hrtimer_nanosleep(ktime_t rqtp, const enum hrtimer_mode mode,
        }
 
        restart = &current->restart_block;
-       restart->fn = hrtimer_nanosleep_restart;
        restart->nanosleep.clockid = t.timer.base->clockid;
        restart->nanosleep.expires = hrtimer_get_expires_tv64(&t.timer);
+       set_restart_fn(restart, hrtimer_nanosleep_restart);
 out:
        destroy_hrtimer_on_stack(&t.timer);
        return ret;
index a71758e..9abe152 100644 (file)
@@ -1480,8 +1480,8 @@ static int posix_cpu_nsleep(const clockid_t which_clock, int flags,
                if (flags & TIMER_ABSTIME)
                        return -ERESTARTNOHAND;
 
-               restart_block->fn = posix_cpu_nsleep_restart;
                restart_block->nanosleep.clockid = which_clock;
+               set_restart_fn(restart_block, posix_cpu_nsleep_restart);
        }
        return error;
 }
index 624ae1d..fba9909 100644 (file)
@@ -156,6 +156,7 @@ config KASAN_STACK_ENABLE
 
 config KASAN_STACK
        int
+       depends on KASAN_GENERIC || KASAN_SW_TAGS
        default 1 if KASAN_STACK_ENABLE || CC_IS_GCC
        default 0
 
index c3e59ca..9c9f40b 100644 (file)
@@ -21,7 +21,6 @@ static inline unsigned long ex_to_insn(const struct exception_table_entry *x)
 }
 #endif
 
-#ifndef ARCH_HAS_SORT_EXTABLE
 #ifndef ARCH_HAS_RELATIVE_EXTABLE
 #define swap_ex                NULL
 #else
@@ -88,9 +87,6 @@ void trim_init_extable(struct module *m)
                m->num_exentries--;
 }
 #endif /* CONFIG_MODULES */
-#endif /* !ARCH_HAS_SORT_EXTABLE */
-
-#ifndef ARCH_HAS_SEARCH_EXTABLE
 
 static int cmp_ex_search(const void *key, const void *elt)
 {
@@ -120,4 +116,3 @@ search_extable(const struct exception_table_entry *base,
        return bsearch(&value, base, num,
                       sizeof(struct exception_table_entry), cmp_ex_search);
 }
-#endif
index 874b732..86f2b94 100644 (file)
@@ -368,20 +368,24 @@ void zero_user_segments(struct page *page, unsigned start1, unsigned end1,
 
        BUG_ON(end1 > page_size(page) || end2 > page_size(page));
 
+       if (start1 >= end1)
+               start1 = end1 = 0;
+       if (start2 >= end2)
+               start2 = end2 = 0;
+
        for (i = 0; i < compound_nr(page); i++) {
                void *kaddr = NULL;
 
-               if (start1 < PAGE_SIZE || start2 < PAGE_SIZE)
-                       kaddr = kmap_atomic(page + i);
-
                if (start1 >= PAGE_SIZE) {
                        start1 -= PAGE_SIZE;
                        end1 -= PAGE_SIZE;
                } else {
                        unsigned this_end = min_t(unsigned, end1, PAGE_SIZE);
 
-                       if (end1 > start1)
+                       if (end1 > start1) {
+                               kaddr = kmap_atomic(page + i);
                                memset(kaddr + start1, 0, this_end - start1);
+                       }
                        end1 -= this_end;
                        start1 = 0;
                }
@@ -392,8 +396,11 @@ void zero_user_segments(struct page *page, unsigned start1, unsigned end1,
                } else {
                        unsigned this_end = min_t(unsigned, end2, PAGE_SIZE);
 
-                       if (end2 > start2)
+                       if (end2 > start2) {
+                               if (!kaddr)
+                                       kaddr = kmap_atomic(page + i);
                                memset(kaddr + start2, 0, this_end - start2);
+                       }
                        end2 -= this_end;
                        start2 = 0;
                }
index 395c751..ae907a9 100644 (file)
@@ -1100,9 +1100,7 @@ int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm,
         * best effort that the pinned pages won't be replaced by another
         * random page during the coming copy-on-write.
         */
-       if (unlikely(is_cow_mapping(vma->vm_flags) &&
-                    atomic_read(&src_mm->has_pinned) &&
-                    page_maybe_dma_pinned(src_page))) {
+       if (unlikely(page_needs_cow_for_dma(vma, src_page))) {
                pte_free(dst_mm, pgtable);
                spin_unlock(src_ptl);
                spin_unlock(dst_ptl);
@@ -1214,9 +1212,7 @@ int copy_huge_pud(struct mm_struct *dst_mm, struct mm_struct *src_mm,
        }
 
        /* Please refer to comments in copy_huge_pmd() */
-       if (unlikely(is_cow_mapping(vma->vm_flags) &&
-                    atomic_read(&src_mm->has_pinned) &&
-                    page_maybe_dma_pinned(pud_page(pud)))) {
+       if (unlikely(page_needs_cow_for_dma(vma, pud_page(pud)))) {
                spin_unlock(src_ptl);
                spin_unlock(dst_ptl);
                __split_huge_pud(vma, src_pud, addr);
@@ -2471,7 +2467,7 @@ static void __split_huge_page(struct page *page, struct list_head *list,
        int i;
 
        /* complete memcg works before add pages to LRU */
-       mem_cgroup_split_huge_fixup(head);
+       split_page_memcg(head, nr);
 
        if (PageAnon(head) && PageSwapCache(head)) {
                swp_entry_t entry = { .val = page_private(head) };
index 8fb42c6..5b1ab1f 100644 (file)
@@ -331,6 +331,24 @@ static void coalesce_file_region(struct resv_map *resv, struct file_region *rg)
        }
 }
 
+static inline long
+hugetlb_resv_map_add(struct resv_map *map, struct file_region *rg, long from,
+                    long to, struct hstate *h, struct hugetlb_cgroup *cg,
+                    long *regions_needed)
+{
+       struct file_region *nrg;
+
+       if (!regions_needed) {
+               nrg = get_file_region_entry_from_cache(map, from, to);
+               record_hugetlb_cgroup_uncharge_info(cg, h, map, nrg);
+               list_add(&nrg->link, rg->link.prev);
+               coalesce_file_region(map, nrg);
+       } else
+               *regions_needed += 1;
+
+       return to - from;
+}
+
 /*
  * Must be called with resv->lock held.
  *
@@ -346,7 +364,7 @@ static long add_reservation_in_range(struct resv_map *resv, long f, long t,
        long add = 0;
        struct list_head *head = &resv->regions;
        long last_accounted_offset = f;
-       struct file_region *rg = NULL, *trg = NULL, *nrg = NULL;
+       struct file_region *rg = NULL, *trg = NULL;
 
        if (regions_needed)
                *regions_needed = 0;
@@ -369,24 +387,17 @@ static long add_reservation_in_range(struct resv_map *resv, long f, long t,
                /* When we find a region that starts beyond our range, we've
                 * finished.
                 */
-               if (rg->from > t)
+               if (rg->from >= t)
                        break;
 
                /* Add an entry for last_accounted_offset -> rg->from, and
                 * update last_accounted_offset.
                 */
-               if (rg->from > last_accounted_offset) {
-                       add += rg->from - last_accounted_offset;
-                       if (!regions_needed) {
-                               nrg = get_file_region_entry_from_cache(
-                                       resv, last_accounted_offset, rg->from);
-                               record_hugetlb_cgroup_uncharge_info(h_cg, h,
-                                                                   resv, nrg);
-                               list_add(&nrg->link, rg->link.prev);
-                               coalesce_file_region(resv, nrg);
-                       } else
-                               *regions_needed += 1;
-               }
+               if (rg->from > last_accounted_offset)
+                       add += hugetlb_resv_map_add(resv, rg,
+                                                   last_accounted_offset,
+                                                   rg->from, h, h_cg,
+                                                   regions_needed);
 
                last_accounted_offset = rg->to;
        }
@@ -394,17 +405,9 @@ static long add_reservation_in_range(struct resv_map *resv, long f, long t,
        /* Handle the case where our range extends beyond
         * last_accounted_offset.
         */
-       if (last_accounted_offset < t) {
-               add += t - last_accounted_offset;
-               if (!regions_needed) {
-                       nrg = get_file_region_entry_from_cache(
-                               resv, last_accounted_offset, t);
-                       record_hugetlb_cgroup_uncharge_info(h_cg, h, resv, nrg);
-                       list_add(&nrg->link, rg->link.prev);
-                       coalesce_file_region(resv, nrg);
-               } else
-                       *regions_needed += 1;
-       }
+       if (last_accounted_offset < t)
+               add += hugetlb_resv_map_add(resv, rg, last_accounted_offset,
+                                           t, h, h_cg, regions_needed);
 
        VM_BUG_ON(add < 0);
        return add;
@@ -3725,21 +3728,32 @@ static bool is_hugetlb_entry_hwpoisoned(pte_t pte)
                return false;
 }
 
+static void
+hugetlb_install_page(struct vm_area_struct *vma, pte_t *ptep, unsigned long addr,
+                    struct page *new_page)
+{
+       __SetPageUptodate(new_page);
+       set_huge_pte_at(vma->vm_mm, addr, ptep, make_huge_pte(vma, new_page, 1));
+       hugepage_add_new_anon_rmap(new_page, vma, addr);
+       hugetlb_count_add(pages_per_huge_page(hstate_vma(vma)), vma->vm_mm);
+       ClearHPageRestoreReserve(new_page);
+       SetHPageMigratable(new_page);
+}
+
 int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
                            struct vm_area_struct *vma)
 {
        pte_t *src_pte, *dst_pte, entry, dst_entry;
        struct page *ptepage;
        unsigned long addr;
-       int cow;
+       bool cow = is_cow_mapping(vma->vm_flags);
        struct hstate *h = hstate_vma(vma);
        unsigned long sz = huge_page_size(h);
+       unsigned long npages = pages_per_huge_page(h);
        struct address_space *mapping = vma->vm_file->f_mapping;
        struct mmu_notifier_range range;
        int ret = 0;
 
-       cow = (vma->vm_flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE;
-
        if (cow) {
                mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, vma, src,
                                        vma->vm_start,
@@ -3784,6 +3798,7 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
                spin_lock_nested(src_ptl, SINGLE_DEPTH_NESTING);
                entry = huge_ptep_get(src_pte);
                dst_entry = huge_ptep_get(dst_pte);
+again:
                if (huge_pte_none(entry) || !huge_pte_none(dst_entry)) {
                        /*
                         * Skip if src entry none.  Also, skip in the
@@ -3807,6 +3822,52 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
                        }
                        set_huge_swap_pte_at(dst, addr, dst_pte, entry, sz);
                } else {
+                       entry = huge_ptep_get(src_pte);
+                       ptepage = pte_page(entry);
+                       get_page(ptepage);
+
+                       /*
+                        * This is a rare case where we see pinned hugetlb
+                        * pages while they're prone to COW.  We need to do the
+                        * COW earlier during fork.
+                        *
+                        * When pre-allocating the page or copying data, we
+                        * need to be without the pgtable locks since we could
+                        * sleep during the process.
+                        */
+                       if (unlikely(page_needs_cow_for_dma(vma, ptepage))) {
+                               pte_t src_pte_old = entry;
+                               struct page *new;
+
+                               spin_unlock(src_ptl);
+                               spin_unlock(dst_ptl);
+                               /* Do not use reserve as it's private owned */
+                               new = alloc_huge_page(vma, addr, 1);
+                               if (IS_ERR(new)) {
+                                       put_page(ptepage);
+                                       ret = PTR_ERR(new);
+                                       break;
+                               }
+                               copy_user_huge_page(new, ptepage, addr, vma,
+                                                   npages);
+                               put_page(ptepage);
+
+                               /* Install the new huge page if src pte stable */
+                               dst_ptl = huge_pte_lock(h, dst, dst_pte);
+                               src_ptl = huge_pte_lockptr(h, src, src_pte);
+                               spin_lock_nested(src_ptl, SINGLE_DEPTH_NESTING);
+                               entry = huge_ptep_get(src_pte);
+                               if (!pte_same(src_pte_old, entry)) {
+                                       put_page(new);
+                                       /* dst_entry won't change as in child */
+                                       goto again;
+                               }
+                               hugetlb_install_page(vma, dst_pte, addr, new);
+                               spin_unlock(src_ptl);
+                               spin_unlock(dst_ptl);
+                               continue;
+                       }
+
                        if (cow) {
                                /*
                                 * No need to notify as we are downgrading page
@@ -3817,12 +3878,10 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
                                 */
                                huge_ptep_set_wrprotect(src, addr, src_pte);
                        }
-                       entry = huge_ptep_get(src_pte);
-                       ptepage = pte_page(entry);
-                       get_page(ptepage);
+
                        page_dup_rmap(ptepage, true);
                        set_huge_pte_at(dst, addr, dst_pte, entry);
-                       hugetlb_count_add(pages_per_huge_page(h), dst);
+                       hugetlb_count_add(npages, dst);
                }
                spin_unlock(src_ptl);
                spin_unlock(dst_ptl);
index 9902648..1432fee 100644 (file)
@@ -296,11 +296,6 @@ static inline unsigned int buddy_order(struct page *page)
  */
 #define buddy_order_unsafe(page)       READ_ONCE(page_private(page))
 
-static inline bool is_cow_mapping(vm_flags_t flags)
-{
-       return (flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE;
-}
-
 /*
  * These three helpers classifies VMAs for virtual memory accounting.
  */
index ab83d5a..e3f7145 100644 (file)
 
 #include "kfence.h"
 
+/* May be overridden by <asm/kfence.h>. */
+#ifndef ARCH_FUNC_PREFIX
+#define ARCH_FUNC_PREFIX ""
+#endif
+
 extern bool no_hash_pointers;
 
 /* Helper function to either print to a seq_file or to console. */
@@ -67,8 +72,9 @@ static int get_stack_skipnr(const unsigned long stack_entries[], int num_entries
        for (skipnr = 0; skipnr < num_entries; skipnr++) {
                int len = scnprintf(buf, sizeof(buf), "%ps", (void *)stack_entries[skipnr]);
 
-               if (str_has_prefix(buf, "kfence_") || str_has_prefix(buf, "__kfence_") ||
-                   !strncmp(buf, "__slab_free", len)) {
+               if (str_has_prefix(buf, ARCH_FUNC_PREFIX "kfence_") ||
+                   str_has_prefix(buf, ARCH_FUNC_PREFIX "__kfence_") ||
+                   !strncmp(buf, ARCH_FUNC_PREFIX "__slab_free", len)) {
                        /*
                         * In case of tail calls from any of the below
                         * to any of the above.
@@ -77,10 +83,10 @@ static int get_stack_skipnr(const unsigned long stack_entries[], int num_entries
                }
 
                /* Also the *_bulk() variants by only checking prefixes. */
-               if (str_has_prefix(buf, "kfree") ||
-                   str_has_prefix(buf, "kmem_cache_free") ||
-                   str_has_prefix(buf, "__kmalloc") ||
-                   str_has_prefix(buf, "kmem_cache_alloc"))
+               if (str_has_prefix(buf, ARCH_FUNC_PREFIX "kfree") ||
+                   str_has_prefix(buf, ARCH_FUNC_PREFIX "kmem_cache_free") ||
+                   str_has_prefix(buf, ARCH_FUNC_PREFIX "__kmalloc") ||
+                   str_has_prefix(buf, ARCH_FUNC_PREFIX "kmem_cache_alloc"))
                        goto found;
        }
        if (fallback < num_entries)
@@ -116,12 +122,12 @@ void kfence_print_object(struct seq_file *seq, const struct kfence_metadata *met
        lockdep_assert_held(&meta->lock);
 
        if (meta->state == KFENCE_OBJECT_UNUSED) {
-               seq_con_printf(seq, "kfence-#%zd unused\n", meta - kfence_metadata);
+               seq_con_printf(seq, "kfence-#%td unused\n", meta - kfence_metadata);
                return;
        }
 
        seq_con_printf(seq,
-                      "kfence-#%zd [0x%p-0x%p"
+                      "kfence-#%td [0x%p-0x%p"
                       ", size=%d, cache=%s] allocated by task %d:\n",
                       meta - kfence_metadata, (void *)start, (void *)(start + size - 1), size,
                       (cache && cache->name) ? cache->name : "<destroyed>", meta->alloc_track.pid);
@@ -204,7 +210,7 @@ void kfence_report_error(unsigned long address, bool is_write, struct pt_regs *r
 
                pr_err("BUG: KFENCE: out-of-bounds %s in %pS\n\n", get_access_type(is_write),
                       (void *)stack_entries[skipnr]);
-               pr_err("Out-of-bounds %s at 0x%p (%luB %s of kfence-#%zd):\n",
+               pr_err("Out-of-bounds %s at 0x%p (%luB %s of kfence-#%td):\n",
                       get_access_type(is_write), (void *)address,
                       left_of_object ? meta->addr - address : address - meta->addr,
                       left_of_object ? "left" : "right", object_index);
@@ -213,14 +219,14 @@ void kfence_report_error(unsigned long address, bool is_write, struct pt_regs *r
        case KFENCE_ERROR_UAF:
                pr_err("BUG: KFENCE: use-after-free %s in %pS\n\n", get_access_type(is_write),
                       (void *)stack_entries[skipnr]);
-               pr_err("Use-after-free %s at 0x%p (in kfence-#%zd):\n",
+               pr_err("Use-after-free %s at 0x%p (in kfence-#%td):\n",
                       get_access_type(is_write), (void *)address, object_index);
                break;
        case KFENCE_ERROR_CORRUPTION:
                pr_err("BUG: KFENCE: memory corruption in %pS\n\n", (void *)stack_entries[skipnr]);
                pr_err("Corrupted memory at 0x%p ", (void *)address);
                print_diff_canary(address, 16, meta);
-               pr_cont(" (in kfence-#%zd):\n", object_index);
+               pr_cont(" (in kfence-#%td):\n", object_index);
                break;
        case KFENCE_ERROR_INVALID:
                pr_err("BUG: KFENCE: invalid %s in %pS\n\n", get_access_type(is_write),
@@ -230,7 +236,7 @@ void kfence_report_error(unsigned long address, bool is_write, struct pt_regs *r
                break;
        case KFENCE_ERROR_INVALID_FREE:
                pr_err("BUG: KFENCE: invalid free in %pS\n\n", (void *)stack_entries[skipnr]);
-               pr_err("Invalid free of 0x%p (in kfence-#%zd):\n", (void *)address,
+               pr_err("Invalid free of 0x%p (in kfence-#%td):\n", (void *)address,
                       object_index);
                break;
        }
index df692d2..01fef79 100644 (file)
@@ -1198,12 +1198,22 @@ SYSCALL_DEFINE5(process_madvise, int, pidfd, const struct iovec __user *, vec,
                goto release_task;
        }
 
-       mm = mm_access(task, PTRACE_MODE_ATTACH_FSCREDS);
+       /* Require PTRACE_MODE_READ to avoid leaking ASLR metadata. */
+       mm = mm_access(task, PTRACE_MODE_READ_FSCREDS);
        if (IS_ERR_OR_NULL(mm)) {
                ret = IS_ERR(mm) ? PTR_ERR(mm) : -ESRCH;
                goto release_task;
        }
 
+       /*
+        * Require CAP_SYS_NICE for influencing process performance. Note that
+        * only non-destructive hints are currently supported.
+        */
+       if (!capable(CAP_SYS_NICE)) {
+               ret = -EPERM;
+               goto release_mm;
+       }
+
        total_len = iov_iter_count(&iter);
 
        while (iov_iter_count(&iter)) {
@@ -1218,6 +1228,7 @@ SYSCALL_DEFINE5(process_madvise, int, pidfd, const struct iovec __user *, vec,
        if (ret == 0)
                ret = total_len - iov_iter_count(&iter);
 
+release_mm:
        mmput(mm);
 release_task:
        put_task_struct(task);
index 845eec0..e064ac0 100644 (file)
@@ -3287,24 +3287,21 @@ void obj_cgroup_uncharge(struct obj_cgroup *objcg, size_t size)
 
 #endif /* CONFIG_MEMCG_KMEM */
 
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
 /*
- * Because page_memcg(head) is not set on compound tails, set it now.
+ * Because page_memcg(head) is not set on tails, set it now.
  */
-void mem_cgroup_split_huge_fixup(struct page *head)
+void split_page_memcg(struct page *head, unsigned int nr)
 {
        struct mem_cgroup *memcg = page_memcg(head);
        int i;
 
-       if (mem_cgroup_disabled())
+       if (mem_cgroup_disabled() || !memcg)
                return;
 
-       for (i = 1; i < HPAGE_PMD_NR; i++) {
-               css_get(&memcg->css);
-               head[i].memcg_data = (unsigned long)memcg;
-       }
+       for (i = 1; i < nr; i++)
+               head[i].memcg_data = head->memcg_data;
+       css_get_many(&memcg->css, nr - 1);
 }
-#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
 #ifdef CONFIG_MEMCG_SWAP
 /**
index c8e3576..5efa07f 100644 (file)
@@ -809,12 +809,8 @@ copy_present_page(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma
                  pte_t *dst_pte, pte_t *src_pte, unsigned long addr, int *rss,
                  struct page **prealloc, pte_t pte, struct page *page)
 {
-       struct mm_struct *src_mm = src_vma->vm_mm;
        struct page *new_page;
 
-       if (!is_cow_mapping(src_vma->vm_flags))
-               return 1;
-
        /*
         * What we want to do is to check whether this page may
         * have been pinned by the parent process.  If so,
@@ -828,9 +824,7 @@ copy_present_page(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma
         * the page count. That might give false positives for
         * for pinning, but it will work correctly.
         */
-       if (likely(!atomic_read(&src_mm->has_pinned)))
-               return 1;
-       if (likely(!page_maybe_dma_pinned(page)))
+       if (likely(!page_needs_cow_for_dma(src_vma, page)))
                return 1;
 
        new_page = *prealloc;
@@ -3103,6 +3097,14 @@ static vm_fault_t do_wp_page(struct vm_fault *vmf)
                return handle_userfault(vmf, VM_UFFD_WP);
        }
 
+       /*
+        * Userfaultfd write-protect can defer flushes. Ensure the TLB
+        * is flushed in this case before copying.
+        */
+       if (unlikely(userfaultfd_wp(vmf->vma) &&
+                    mm_tlb_flush_pending(vmf->vma->vm_mm)))
+               flush_tlb_page(vmf->vma, vmf->address);
+
        vmf->page = vm_normal_page(vma, vmf->address, vmf->orig_pte);
        if (!vmf->page) {
                /*
index 5ba51a8..0cdbbfb 100644 (file)
@@ -1072,7 +1072,7 @@ static int online_memory_block(struct memory_block *mem, void *arg)
  */
 int __ref add_memory_resource(int nid, struct resource *res, mhp_t mhp_flags)
 {
-       struct mhp_params params = { .pgprot = PAGE_KERNEL };
+       struct mhp_params params = { .pgprot = pgprot_mhp(PAGE_KERNEL) };
        u64 start, size;
        bool new_node = false;
        int ret;
index 3e4b29e..cfc7287 100644 (file)
@@ -1281,6 +1281,12 @@ static __always_inline bool free_pages_prepare(struct page *page,
 
        kernel_poison_pages(page, 1 << order);
 
+       /*
+        * With hardware tag-based KASAN, memory tags must be set before the
+        * page becomes unavailable via debug_pagealloc or arch_free_page.
+        */
+       kasan_free_nondeferred_pages(page, order);
+
        /*
         * arch_free_page() can make the page's contents inaccessible.  s390
         * does this.  So nothing which can access the page's contents should
@@ -1290,8 +1296,6 @@ static __always_inline bool free_pages_prepare(struct page *page,
 
        debug_pagealloc_unmap_pages(page, 1 << order);
 
-       kasan_free_nondeferred_pages(page, order);
-
        return true;
 }
 
@@ -3310,6 +3314,7 @@ void split_page(struct page *page, unsigned int order)
        for (i = 1; i < (1 << order); i++)
                set_page_refcounted(page + i);
        split_page_owner(page, 1 << order);
+       split_page_memcg(page, 1 << order);
 }
 EXPORT_SYMBOL_GPL(split_page);
 
@@ -6259,12 +6264,65 @@ static void __meminit zone_init_free_lists(struct zone *zone)
        }
 }
 
+#if !defined(CONFIG_FLAT_NODE_MEM_MAP)
+/*
+ * Only struct pages that correspond to ranges defined by memblock.memory
+ * are zeroed and initialized by going through __init_single_page() during
+ * memmap_init_zone().
+ *
+ * But, there could be struct pages that correspond to holes in
+ * memblock.memory. This can happen because of the following reasons:
+ * - physical memory bank size is not necessarily the exact multiple of the
+ *   arbitrary section size
+ * - early reserved memory may not be listed in memblock.memory
+ * - memory layouts defined with memmap= kernel parameter may not align
+ *   nicely with memmap sections
+ *
+ * Explicitly initialize those struct pages so that:
+ * - PG_Reserved is set
+ * - zone and node links point to zone and node that span the page if the
+ *   hole is in the middle of a zone
+ * - zone and node links point to adjacent zone/node if the hole falls on
+ *   the zone boundary; the pages in such holes will be prepended to the
+ *   zone/node above the hole except for the trailing pages in the last
+ *   section that will be appended to the zone/node below.
+ */
+static u64 __meminit init_unavailable_range(unsigned long spfn,
+                                           unsigned long epfn,
+                                           int zone, int node)
+{
+       unsigned long pfn;
+       u64 pgcnt = 0;
+
+       for (pfn = spfn; pfn < epfn; pfn++) {
+               if (!pfn_valid(ALIGN_DOWN(pfn, pageblock_nr_pages))) {
+                       pfn = ALIGN_DOWN(pfn, pageblock_nr_pages)
+                               + pageblock_nr_pages - 1;
+                       continue;
+               }
+               __init_single_page(pfn_to_page(pfn), pfn, zone, node);
+               __SetPageReserved(pfn_to_page(pfn));
+               pgcnt++;
+       }
+
+       return pgcnt;
+}
+#else
+static inline u64 init_unavailable_range(unsigned long spfn, unsigned long epfn,
+                                        int zone, int node)
+{
+       return 0;
+}
+#endif
+
 void __meminit __weak memmap_init_zone(struct zone *zone)
 {
        unsigned long zone_start_pfn = zone->zone_start_pfn;
        unsigned long zone_end_pfn = zone_start_pfn + zone->spanned_pages;
        int i, nid = zone_to_nid(zone), zone_id = zone_idx(zone);
+       static unsigned long hole_pfn;
        unsigned long start_pfn, end_pfn;
+       u64 pgcnt = 0;
 
        for_each_mem_pfn_range(i, nid, &start_pfn, &end_pfn, NULL) {
                start_pfn = clamp(start_pfn, zone_start_pfn, zone_end_pfn);
@@ -6274,7 +6332,29 @@ void __meminit __weak memmap_init_zone(struct zone *zone)
                        memmap_init_range(end_pfn - start_pfn, nid,
                                        zone_id, start_pfn, zone_end_pfn,
                                        MEMINIT_EARLY, NULL, MIGRATE_MOVABLE);
+
+               if (hole_pfn < start_pfn)
+                       pgcnt += init_unavailable_range(hole_pfn, start_pfn,
+                                                       zone_id, nid);
+               hole_pfn = end_pfn;
        }
+
+#ifdef CONFIG_SPARSEMEM
+       /*
+        * Initialize the hole in the range [zone_end_pfn, section_end].
+        * If zone boundary falls in the middle of a section, this hole
+        * will be re-initialized during the call to this function for the
+        * higher zone.
+        */
+       end_pfn = round_up(zone_end_pfn, PAGES_PER_SECTION);
+       if (hole_pfn < end_pfn)
+               pgcnt += init_unavailable_range(hole_pfn, end_pfn,
+                                               zone_id, nid);
+#endif
+
+       if (pgcnt)
+               pr_info("  %s zone: %llu pages in unavailable ranges\n",
+                       zone->name, pgcnt);
 }
 
 static int zone_batchsize(struct zone *zone)
@@ -7071,88 +7151,6 @@ void __init free_area_init_memoryless_node(int nid)
        free_area_init_node(nid);
 }
 
-#if !defined(CONFIG_FLAT_NODE_MEM_MAP)
-/*
- * Initialize all valid struct pages in the range [spfn, epfn) and mark them
- * PageReserved(). Return the number of struct pages that were initialized.
- */
-static u64 __init init_unavailable_range(unsigned long spfn, unsigned long epfn)
-{
-       unsigned long pfn;
-       u64 pgcnt = 0;
-
-       for (pfn = spfn; pfn < epfn; pfn++) {
-               if (!pfn_valid(ALIGN_DOWN(pfn, pageblock_nr_pages))) {
-                       pfn = ALIGN_DOWN(pfn, pageblock_nr_pages)
-                               + pageblock_nr_pages - 1;
-                       continue;
-               }
-               /*
-                * Use a fake node/zone (0) for now. Some of these pages
-                * (in memblock.reserved but not in memblock.memory) will
-                * get re-initialized via reserve_bootmem_region() later.
-                */
-               __init_single_page(pfn_to_page(pfn), pfn, 0, 0);
-               __SetPageReserved(pfn_to_page(pfn));
-               pgcnt++;
-       }
-
-       return pgcnt;
-}
-
-/*
- * Only struct pages that are backed by physical memory are zeroed and
- * initialized by going through __init_single_page(). But, there are some
- * struct pages which are reserved in memblock allocator and their fields
- * may be accessed (for example page_to_pfn() on some configuration accesses
- * flags). We must explicitly initialize those struct pages.
- *
- * This function also addresses a similar issue where struct pages are left
- * uninitialized because the physical address range is not covered by
- * memblock.memory or memblock.reserved. That could happen when memblock
- * layout is manually configured via memmap=, or when the highest physical
- * address (max_pfn) does not end on a section boundary.
- */
-static void __init init_unavailable_mem(void)
-{
-       phys_addr_t start, end;
-       u64 i, pgcnt;
-       phys_addr_t next = 0;
-
-       /*
-        * Loop through unavailable ranges not covered by memblock.memory.
-        */
-       pgcnt = 0;
-       for_each_mem_range(i, &start, &end) {
-               if (next < start)
-                       pgcnt += init_unavailable_range(PFN_DOWN(next),
-                                                       PFN_UP(start));
-               next = end;
-       }
-
-       /*
-        * Early sections always have a fully populated memmap for the whole
-        * section - see pfn_valid(). If the last section has holes at the
-        * end and that section is marked "online", the memmap will be
-        * considered initialized. Make sure that memmap has a well defined
-        * state.
-        */
-       pgcnt += init_unavailable_range(PFN_DOWN(next),
-                                       round_up(max_pfn, PAGES_PER_SECTION));
-
-       /*
-        * Struct pages that do not have backing memory. This could be because
-        * firmware is using some of this memory, or for some other reasons.
-        */
-       if (pgcnt)
-               pr_info("Zeroed struct page in unavailable ranges: %lld pages", pgcnt);
-}
-#else
-static inline void __init init_unavailable_mem(void)
-{
-}
-#endif /* !CONFIG_FLAT_NODE_MEM_MAP */
-
 #if MAX_NUMNODES > 1
 /*
  * Figure out the number of possible node ids.
@@ -7576,7 +7574,6 @@ void __init free_area_init(unsigned long *max_zone_pfn)
        /* Initialise every node */
        mminit_verify_pageflags_layout();
        setup_nr_node_ids();
-       init_unavailable_mem();
        for_each_online_node(nid) {
                pg_data_t *pgdat = NODE_DATA(nid);
                free_area_init_node(nid);
index 51fd424..ae651bf 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -2992,7 +2992,7 @@ static void *cache_alloc_debugcheck_after(struct kmem_cache *cachep,
                                gfp_t flags, void *objp, unsigned long caller)
 {
        WARN_ON_ONCE(cachep->ctor && (flags & __GFP_ZERO));
-       if (!objp)
+       if (!objp || is_kfence_address(objp))
                return objp;
        if (cachep->flags & SLAB_POISON) {
                check_poison_obj(cachep, objp);
index e26c274..3021ce9 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1993,7 +1993,7 @@ static void *get_partial_node(struct kmem_cache *s, struct kmem_cache_node *n,
 
                t = acquire_slab(s, n, page, object == NULL, &objects);
                if (!t)
-                       continue; /* cmpxchg raced */
+                       break;
 
                available += objects;
                if (!object) {
index 4f62f29..0a9019d 100644 (file)
@@ -1623,10 +1623,6 @@ p9_client_read_once(struct p9_fid *fid, u64 offset, struct iov_iter *to,
        }
 
        p9_debug(P9_DEBUG_9P, "<<< RREAD count %d\n", count);
-       if (!count) {
-               p9_tag_remove(clnt, req);
-               return 0;
-       }
 
        if (non_zc) {
                int n = copy_to_iter(dataptr, count, to);
index e48f7ac..3ddd66e 100644 (file)
@@ -702,7 +702,6 @@ MODULE_LICENSE("GPL");
 
 MODULE_AUTHOR(BATADV_DRIVER_AUTHOR);
 MODULE_DESCRIPTION(BATADV_DRIVER_DESC);
-MODULE_SUPPORTED_DEVICE(BATADV_DRIVER_DEVICE);
 MODULE_VERSION(BATADV_SOURCE_VERSION);
 MODULE_ALIAS_RTNL_LINK("batadv");
 MODULE_ALIAS_GENL_FAMILY(BATADV_NL_NAME);
index 0edc0b2..1bdcb33 100644 (file)
@@ -2147,7 +2147,7 @@ out:
 out_err:
        cb->args[1] = idx;
        cb->args[0] = h;
-       cb->seq = net->dev_base_seq;
+       cb->seq = tgt_net->dev_base_seq;
        nl_dump_check_consistent(cb, nlmsg_hdr(skb));
        if (netnsid >= 0)
                put_net(tgt_net);
index 545a472..c421c8f 100644 (file)
@@ -3659,6 +3659,8 @@ unsigned int skb_find_text(struct sk_buff *skb, unsigned int from,
        struct ts_state state;
        unsigned int ret;
 
+       BUILD_BUG_ON(sizeof(struct skb_seq_state) > sizeof(state.cb));
+
        config->get_next_block = skb_ts_get_next_block;
        config->finish = skb_ts_finish;
 
index 3589224..58b8fc8 100644 (file)
@@ -118,6 +118,8 @@ config NET_DSA_TAG_OCELOT
 
 config NET_DSA_TAG_OCELOT_8021Q
        tristate "Tag driver for Ocelot family of switches, using VLAN"
+       depends on MSCC_OCELOT_SWITCH_LIB || \
+                 (MSCC_OCELOT_SWITCH_LIB=n && COMPILE_TEST)
        select NET_DSA_TAG_8021Q
        help
          Say Y or M if you want to enable support for tagging frames with a
index 2eeaa42..9d4b0e9 100644 (file)
@@ -230,8 +230,8 @@ int dsa_port_hsr_join(struct dsa_port *dp, struct net_device *hsr);
 void dsa_port_hsr_leave(struct dsa_port *dp, struct net_device *hsr);
 extern const struct phylink_mac_ops dsa_port_phylink_mac_ops;
 
-static inline bool dsa_port_offloads_netdev(struct dsa_port *dp,
-                                           struct net_device *dev)
+static inline bool dsa_port_offloads_bridge_port(struct dsa_port *dp,
+                                                struct net_device *dev)
 {
        /* Switchdev offloading can be configured on: */
 
@@ -241,12 +241,6 @@ static inline bool dsa_port_offloads_netdev(struct dsa_port *dp,
                 */
                return true;
 
-       if (dp->bridge_dev == dev)
-               /* DSA ports connected to a bridge, and event was emitted
-                * for the bridge.
-                */
-               return true;
-
        if (dp->lag_dev == dev)
                /* DSA ports connected to a bridge via a LAG */
                return true;
@@ -254,14 +248,23 @@ static inline bool dsa_port_offloads_netdev(struct dsa_port *dp,
        return false;
 }
 
+static inline bool dsa_port_offloads_bridge(struct dsa_port *dp,
+                                           struct net_device *bridge_dev)
+{
+       /* DSA ports connected to a bridge, and event was emitted
+        * for the bridge.
+        */
+       return dp->bridge_dev == bridge_dev;
+}
+
 /* Returns true if any port of this tree offloads the given net_device */
-static inline bool dsa_tree_offloads_netdev(struct dsa_switch_tree *dst,
-                                           struct net_device *dev)
+static inline bool dsa_tree_offloads_bridge_port(struct dsa_switch_tree *dst,
+                                                struct net_device *dev)
 {
        struct dsa_port *dp;
 
        list_for_each_entry(dp, &dst->ports, list)
-               if (dsa_port_offloads_netdev(dp, dev))
+               if (dsa_port_offloads_bridge_port(dp, dev))
                        return true;
 
        return false;
index 491e376..992fcab 100644 (file)
@@ -278,28 +278,43 @@ static int dsa_slave_port_attr_set(struct net_device *dev,
        struct dsa_port *dp = dsa_slave_to_port(dev);
        int ret;
 
-       if (!dsa_port_offloads_netdev(dp, attr->orig_dev))
-               return -EOPNOTSUPP;
-
        switch (attr->id) {
        case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
+               if (!dsa_port_offloads_bridge_port(dp, attr->orig_dev))
+                       return -EOPNOTSUPP;
+
                ret = dsa_port_set_state(dp, attr->u.stp_state);
                break;
        case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
+               if (!dsa_port_offloads_bridge(dp, attr->orig_dev))
+                       return -EOPNOTSUPP;
+
                ret = dsa_port_vlan_filtering(dp, attr->u.vlan_filtering,
                                              extack);
                break;
        case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:
+               if (!dsa_port_offloads_bridge(dp, attr->orig_dev))
+                       return -EOPNOTSUPP;
+
                ret = dsa_port_ageing_time(dp, attr->u.ageing_time);
                break;
        case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS:
+               if (!dsa_port_offloads_bridge_port(dp, attr->orig_dev))
+                       return -EOPNOTSUPP;
+
                ret = dsa_port_pre_bridge_flags(dp, attr->u.brport_flags,
                                                extack);
                break;
        case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
+               if (!dsa_port_offloads_bridge_port(dp, attr->orig_dev))
+                       return -EOPNOTSUPP;
+
                ret = dsa_port_bridge_flags(dp, attr->u.brport_flags, extack);
                break;
        case SWITCHDEV_ATTR_ID_BRIDGE_MROUTER:
+               if (!dsa_port_offloads_bridge(dp, attr->orig_dev))
+                       return -EOPNOTSUPP;
+
                ret = dsa_port_mrouter(dp->cpu_dp, attr->u.mrouter, extack);
                break;
        default:
@@ -341,9 +356,6 @@ static int dsa_slave_vlan_add(struct net_device *dev,
        struct switchdev_obj_port_vlan vlan;
        int err;
 
-       if (!dsa_port_offloads_netdev(dp, obj->orig_dev))
-               return -EOPNOTSUPP;
-
        if (dsa_port_skip_vlan_configuration(dp)) {
                NL_SET_ERR_MSG_MOD(extack, "skipping configuration of VLAN");
                return 0;
@@ -391,27 +403,36 @@ static int dsa_slave_port_obj_add(struct net_device *dev,
 
        switch (obj->id) {
        case SWITCHDEV_OBJ_ID_PORT_MDB:
-               if (!dsa_port_offloads_netdev(dp, obj->orig_dev))
+               if (!dsa_port_offloads_bridge_port(dp, obj->orig_dev))
                        return -EOPNOTSUPP;
+
                err = dsa_port_mdb_add(dp, SWITCHDEV_OBJ_PORT_MDB(obj));
                break;
        case SWITCHDEV_OBJ_ID_HOST_MDB:
+               if (!dsa_port_offloads_bridge(dp, obj->orig_dev))
+                       return -EOPNOTSUPP;
+
                /* DSA can directly translate this to a normal MDB add,
                 * but on the CPU port.
                 */
                err = dsa_port_mdb_add(dp->cpu_dp, SWITCHDEV_OBJ_PORT_MDB(obj));
                break;
        case SWITCHDEV_OBJ_ID_PORT_VLAN:
+               if (!dsa_port_offloads_bridge_port(dp, obj->orig_dev))
+                       return -EOPNOTSUPP;
+
                err = dsa_slave_vlan_add(dev, obj, extack);
                break;
        case SWITCHDEV_OBJ_ID_MRP:
-               if (!dsa_port_offloads_netdev(dp, obj->orig_dev))
+               if (!dsa_port_offloads_bridge(dp, obj->orig_dev))
                        return -EOPNOTSUPP;
+
                err = dsa_port_mrp_add(dp, SWITCHDEV_OBJ_MRP(obj));
                break;
        case SWITCHDEV_OBJ_ID_RING_ROLE_MRP:
-               if (!dsa_port_offloads_netdev(dp, obj->orig_dev))
+               if (!dsa_port_offloads_bridge(dp, obj->orig_dev))
                        return -EOPNOTSUPP;
+
                err = dsa_port_mrp_add_ring_role(dp,
                                                 SWITCHDEV_OBJ_RING_ROLE_MRP(obj));
                break;
@@ -431,9 +452,6 @@ static int dsa_slave_vlan_del(struct net_device *dev,
        struct switchdev_obj_port_vlan *vlan;
        int err;
 
-       if (!dsa_port_offloads_netdev(dp, obj->orig_dev))
-               return -EOPNOTSUPP;
-
        if (dsa_port_skip_vlan_configuration(dp))
                return 0;
 
@@ -459,27 +477,36 @@ static int dsa_slave_port_obj_del(struct net_device *dev,
 
        switch (obj->id) {
        case SWITCHDEV_OBJ_ID_PORT_MDB:
-               if (!dsa_port_offloads_netdev(dp, obj->orig_dev))
+               if (!dsa_port_offloads_bridge_port(dp, obj->orig_dev))
                        return -EOPNOTSUPP;
+
                err = dsa_port_mdb_del(dp, SWITCHDEV_OBJ_PORT_MDB(obj));
                break;
        case SWITCHDEV_OBJ_ID_HOST_MDB:
+               if (!dsa_port_offloads_bridge(dp, obj->orig_dev))
+                       return -EOPNOTSUPP;
+
                /* DSA can directly translate this to a normal MDB add,
                 * but on the CPU port.
                 */
                err = dsa_port_mdb_del(dp->cpu_dp, SWITCHDEV_OBJ_PORT_MDB(obj));
                break;
        case SWITCHDEV_OBJ_ID_PORT_VLAN:
+               if (!dsa_port_offloads_bridge_port(dp, obj->orig_dev))
+                       return -EOPNOTSUPP;
+
                err = dsa_slave_vlan_del(dev, obj);
                break;
        case SWITCHDEV_OBJ_ID_MRP:
-               if (!dsa_port_offloads_netdev(dp, obj->orig_dev))
+               if (!dsa_port_offloads_bridge(dp, obj->orig_dev))
                        return -EOPNOTSUPP;
+
                err = dsa_port_mrp_del(dp, SWITCHDEV_OBJ_MRP(obj));
                break;
        case SWITCHDEV_OBJ_ID_RING_ROLE_MRP:
-               if (!dsa_port_offloads_netdev(dp, obj->orig_dev))
+               if (!dsa_port_offloads_bridge(dp, obj->orig_dev))
                        return -EOPNOTSUPP;
+
                err = dsa_port_mrp_del_ring_role(dp,
                                                 SWITCHDEV_OBJ_RING_ROLE_MRP(obj));
                break;
@@ -2298,7 +2325,7 @@ static int dsa_slave_switchdev_event(struct notifier_block *unused,
                         * other ports bridged with the LAG should be able to
                         * autonomously forward towards it.
                         */
-                       if (dsa_tree_offloads_netdev(dp->ds->dst, dev))
+                       if (dsa_tree_offloads_bridge_port(dp->ds->dst, dev))
                                return NOTIFY_DONE;
                }
 
index 38dcdde..5974848 100644 (file)
@@ -13,6 +13,7 @@
 #define MTK_HDR_LEN            4
 #define MTK_HDR_XMIT_UNTAGGED          0
 #define MTK_HDR_XMIT_TAGGED_TPID_8100  1
+#define MTK_HDR_XMIT_TAGGED_TPID_88A8  2
 #define MTK_HDR_RECV_SOURCE_PORT_MASK  GENMASK(2, 0)
 #define MTK_HDR_XMIT_DP_BIT_MASK       GENMASK(5, 0)
 #define MTK_HDR_XMIT_SA_DIS            BIT(6)
@@ -21,8 +22,8 @@ static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb,
                                    struct net_device *dev)
 {
        struct dsa_port *dp = dsa_slave_to_port(dev);
+       u8 xmit_tpid;
        u8 *mtk_tag;
-       bool is_vlan_skb = true;
        unsigned char *dest = eth_hdr(skb)->h_dest;
        bool is_multicast_skb = is_multicast_ether_addr(dest) &&
                                !is_broadcast_ether_addr(dest);
@@ -33,10 +34,17 @@ static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb,
         * the both special and VLAN tag at the same time and then look up VLAN
         * table with VID.
         */
-       if (!skb_vlan_tagged(skb)) {
+       switch (skb->protocol) {
+       case htons(ETH_P_8021Q):
+               xmit_tpid = MTK_HDR_XMIT_TAGGED_TPID_8100;
+               break;
+       case htons(ETH_P_8021AD):
+               xmit_tpid = MTK_HDR_XMIT_TAGGED_TPID_88A8;
+               break;
+       default:
+               xmit_tpid = MTK_HDR_XMIT_UNTAGGED;
                skb_push(skb, MTK_HDR_LEN);
                memmove(skb->data, skb->data + MTK_HDR_LEN, 2 * ETH_ALEN);
-               is_vlan_skb = false;
        }
 
        mtk_tag = skb->data + 2 * ETH_ALEN;
@@ -44,8 +52,7 @@ static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb,
        /* Mark tag attribute on special tag insertion to notify hardware
         * whether that's a combined special tag with 802.1Q header.
         */
-       mtk_tag[0] = is_vlan_skb ? MTK_HDR_XMIT_TAGGED_TPID_8100 :
-                    MTK_HDR_XMIT_UNTAGGED;
+       mtk_tag[0] = xmit_tpid;
        mtk_tag[1] = (1 << dp->index) & MTK_HDR_XMIT_DP_BIT_MASK;
 
        /* Disable SA learning for multicast frames */
@@ -53,7 +60,7 @@ static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb,
                mtk_tag[1] |= MTK_HDR_XMIT_SA_DIS;
 
        /* Tag control information is kept for 802.1Q */
-       if (!is_vlan_skb) {
+       if (xmit_tpid == MTK_HDR_XMIT_UNTAGGED) {
                mtk_tag[2] = 0;
                mtk_tag[3] = 0;
        }
index c17d39b..e917647 100644 (file)
@@ -35,14 +35,12 @@ static struct sk_buff *rtl4a_tag_xmit(struct sk_buff *skb,
                                      struct net_device *dev)
 {
        struct dsa_port *dp = dsa_slave_to_port(dev);
+       __be16 *p;
        u8 *tag;
-       u16 *p;
        u16 out;
 
        /* Pad out to at least 60 bytes */
-       if (unlikely(eth_skb_pad(skb)))
-               return NULL;
-       if (skb_cow_head(skb, RTL4_A_HDR_LEN) < 0)
+       if (unlikely(__skb_put_padto(skb, ETH_ZLEN, false)))
                return NULL;
 
        netdev_dbg(dev, "add realtek tag to package to port %d\n",
@@ -53,13 +51,13 @@ static struct sk_buff *rtl4a_tag_xmit(struct sk_buff *skb,
        tag = skb->data + 2 * ETH_ALEN;
 
        /* Set Ethertype */
-       p = (u16 *)tag;
+       p = (__be16 *)tag;
        *p = htons(RTL4_A_ETHERTYPE);
 
        out = (RTL4_A_PROTOCOL_RTL8366RB << 12) | (2 << 8);
-       /* The lower bits is the port numer */
+       /* The lower bits is the port number */
        out |= (u8)dp->index;
-       p = (u16 *)(tag + 2);
+       p = (__be16 *)(tag + 2);
        *p = htons(out);
 
        return skb;
index 25a9e56..6a070dc 100644 (file)
@@ -116,10 +116,9 @@ int ethnl_set_channels(struct sk_buff *skb, struct genl_info *info)
        struct ethtool_channels channels = {};
        struct ethnl_req_info req_info = {};
        struct nlattr **tb = info->attrs;
-       const struct nlattr *err_attr;
+       u32 err_attr, max_rx_in_use = 0;
        const struct ethtool_ops *ops;
        struct net_device *dev;
-       u32 max_rx_in_use = 0;
        int ret;
 
        ret = ethnl_parse_header_dev_get(&req_info,
@@ -157,34 +156,35 @@ int ethnl_set_channels(struct sk_buff *skb, struct genl_info *info)
 
        /* ensure new channel counts are within limits */
        if (channels.rx_count > channels.max_rx)
-               err_attr = tb[ETHTOOL_A_CHANNELS_RX_COUNT];
+               err_attr = ETHTOOL_A_CHANNELS_RX_COUNT;
        else if (channels.tx_count > channels.max_tx)
-               err_attr = tb[ETHTOOL_A_CHANNELS_TX_COUNT];
+               err_attr = ETHTOOL_A_CHANNELS_TX_COUNT;
        else if (channels.other_count > channels.max_other)
-               err_attr = tb[ETHTOOL_A_CHANNELS_OTHER_COUNT];
+               err_attr = ETHTOOL_A_CHANNELS_OTHER_COUNT;
        else if (channels.combined_count > channels.max_combined)
-               err_attr = tb[ETHTOOL_A_CHANNELS_COMBINED_COUNT];
+               err_attr = ETHTOOL_A_CHANNELS_COMBINED_COUNT;
        else
-               err_attr = NULL;
+               err_attr = 0;
        if (err_attr) {
                ret = -EINVAL;
-               NL_SET_ERR_MSG_ATTR(info->extack, err_attr,
+               NL_SET_ERR_MSG_ATTR(info->extack, tb[err_attr],
                                    "requested channel count exceeds maximum");
                goto out_ops;
        }
 
        /* ensure there is at least one RX and one TX channel */
        if (!channels.combined_count && !channels.rx_count)
-               err_attr = tb[ETHTOOL_A_CHANNELS_RX_COUNT];
+               err_attr = ETHTOOL_A_CHANNELS_RX_COUNT;
        else if (!channels.combined_count && !channels.tx_count)
-               err_attr = tb[ETHTOOL_A_CHANNELS_TX_COUNT];
+               err_attr = ETHTOOL_A_CHANNELS_TX_COUNT;
        else
-               err_attr = NULL;
+               err_attr = 0;
        if (err_attr) {
                if (mod_combined)
-                       err_attr = tb[ETHTOOL_A_CHANNELS_COMBINED_COUNT];
+                       err_attr = ETHTOOL_A_CHANNELS_COMBINED_COUNT;
                ret = -EINVAL;
-               NL_SET_ERR_MSG_ATTR(info->extack, err_attr, "requested channel counts would result in no RX or TX channel being configured");
+               NL_SET_ERR_MSG_ATTR(info->extack, tb[err_attr],
+                                   "requested channel counts would result in no RX or TX channel being configured");
                goto out_ops;
        }
 
index 471d33a..bfaf327 100644 (file)
@@ -519,16 +519,10 @@ int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info)
                ret_val = -ENOENT;
                goto doi_remove_return;
        }
-       if (!refcount_dec_and_test(&doi_def->refcount)) {
-               spin_unlock(&cipso_v4_doi_list_lock);
-               ret_val = -EBUSY;
-               goto doi_remove_return;
-       }
        list_del_rcu(&doi_def->list);
        spin_unlock(&cipso_v4_doi_list_lock);
 
-       cipso_v4_cache_invalidate();
-       call_rcu(&doi_def->rcu, cipso_v4_doi_free_rcu);
+       cipso_v4_doi_putdef(doi_def);
        ret_val = 0;
 
 doi_remove_return:
@@ -585,9 +579,6 @@ void cipso_v4_doi_putdef(struct cipso_v4_doi *doi_def)
 
        if (!refcount_dec_and_test(&doi_def->refcount))
                return;
-       spin_lock(&cipso_v4_doi_list_lock);
-       list_del_rcu(&doi_def->list);
-       spin_unlock(&cipso_v4_doi_list_lock);
 
        cipso_v4_cache_invalidate();
        call_rcu(&doi_def->rcu, cipso_v4_doi_free_rcu);
@@ -1162,7 +1153,7 @@ static void cipso_v4_gentag_hdr(const struct cipso_v4_doi *doi_def,
 {
        buf[0] = IPOPT_CIPSO;
        buf[1] = CIPSO_V4_HDR_LEN + len;
-       *(__be32 *)&buf[2] = htonl(doi_def->doi);
+       put_unaligned_be32(doi_def->doi, &buf[2]);
 }
 
 /**
index ff327a6..da21dfc 100644 (file)
@@ -65,7 +65,7 @@ EXPORT_SYMBOL_GPL(inet_peer_base_init);
 #define PEER_MAX_GC 32
 
 /* Exported for sysctl_net_ipv4.  */
-int inet_peer_threshold __read_mostly = 65536 + 128;   /* start to throw entries more
+int inet_peer_threshold __read_mostly; /* start to throw entries more
                                         * aggressively at this stage */
 int inet_peer_minttl __read_mostly = 120 * HZ; /* TTL under high load: 120 sec */
 int inet_peer_maxttl __read_mostly = 10 * 60 * HZ;     /* usual time to live: 10 min */
@@ -73,20 +73,13 @@ int inet_peer_maxttl __read_mostly = 10 * 60 * HZ;  /* usual time to live: 10 min
 /* Called from ip_output.c:ip_init  */
 void __init inet_initpeers(void)
 {
-       struct sysinfo si;
+       u64 nr_entries;
 
-       /* Use the straight interface to information about memory. */
-       si_meminfo(&si);
-       /* The values below were suggested by Alexey Kuznetsov
-        * <kuznet@ms2.inr.ac.ru>.  I don't have any opinion about the values
-        * myself.  --SAW
-        */
-       if (si.totalram <= (32768*1024)/PAGE_SIZE)
-               inet_peer_threshold >>= 1; /* max pool size about 1MB on IA32 */
-       if (si.totalram <= (16384*1024)/PAGE_SIZE)
-               inet_peer_threshold >>= 1; /* about 512KB */
-       if (si.totalram <= (8192*1024)/PAGE_SIZE)
-               inet_peer_threshold >>= 2; /* about 128KB */
+        /* 1% of physical memory */
+       nr_entries = div64_ul((u64)totalram_pages() << PAGE_SHIFT,
+                             100 * L1_CACHE_ALIGN(sizeof(struct inet_peer)));
+
+       inet_peer_threshold = clamp_val(nr_entries, 4096, 65536 + 128);
 
        peer_cachep = kmem_cache_create("inet_peer_cache",
                        sizeof(struct inet_peer),
index 76a420c..f6cc26d 100644 (file)
@@ -502,8 +502,7 @@ static int tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb,
                if (!skb_is_gso(skb) &&
                    (inner_iph->frag_off & htons(IP_DF)) &&
                    mtu < pkt_size) {
-                       memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
-                       icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
+                       icmp_ndo_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
                        return -E2BIG;
                }
        }
@@ -527,7 +526,7 @@ static int tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb,
 
                if (!skb_is_gso(skb) && mtu >= IPV6_MIN_MTU &&
                                        mtu < pkt_size) {
-                       icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
+                       icmpv6_ndo_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
                        return -E2BIG;
                }
        }
index abc171e..eb20708 100644 (file)
@@ -238,13 +238,13 @@ static netdev_tx_t vti_xmit(struct sk_buff *skb, struct net_device *dev,
        if (skb->len > mtu) {
                skb_dst_update_pmtu_no_confirm(skb, mtu);
                if (skb->protocol == htons(ETH_P_IP)) {
-                       icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
-                                 htonl(mtu));
+                       icmp_ndo_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
+                                     htonl(mtu));
                } else {
                        if (mtu < IPV6_MIN_MTU)
                                mtu = IPV6_MIN_MTU;
 
-                       icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
+                       icmpv6_ndo_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
                }
 
                dst_release(dst);
index f1c6cbd..743777b 100644 (file)
@@ -1399,7 +1399,7 @@ out:
 
 /* rtnl */
 /* remove all nexthops tied to a device being deleted */
-static void nexthop_flush_dev(struct net_device *dev)
+static void nexthop_flush_dev(struct net_device *dev, unsigned long event)
 {
        unsigned int hash = nh_dev_hashfn(dev->ifindex);
        struct net *net = dev_net(dev);
@@ -1411,6 +1411,10 @@ static void nexthop_flush_dev(struct net_device *dev)
                if (nhi->fib_nhc.nhc_dev != dev)
                        continue;
 
+               if (nhi->reject_nh &&
+                   (event == NETDEV_DOWN || event == NETDEV_CHANGE))
+                       continue;
+
                remove_nexthop(net, nhi->nh_parent, NULL);
        }
 }
@@ -2189,11 +2193,11 @@ static int nh_netdev_event(struct notifier_block *this,
        switch (event) {
        case NETDEV_DOWN:
        case NETDEV_UNREGISTER:
-               nexthop_flush_dev(dev);
+               nexthop_flush_dev(dev, event);
                break;
        case NETDEV_CHANGE:
                if (!(dev_get_flags(dev) & (IFF_RUNNING | IFF_LOWER_UP)))
-                       nexthop_flush_dev(dev);
+                       nexthop_flush_dev(dev, event);
                break;
        case NETDEV_CHANGEMTU:
                info_ext = ptr;
index a3422e4..de7cc84 100644 (file)
@@ -3469,16 +3469,23 @@ static int do_tcp_setsockopt(struct sock *sk, int level, int optname,
                break;
 
        case TCP_QUEUE_SEQ:
-               if (sk->sk_state != TCP_CLOSE)
+               if (sk->sk_state != TCP_CLOSE) {
                        err = -EPERM;
-               else if (tp->repair_queue == TCP_SEND_QUEUE)
-                       WRITE_ONCE(tp->write_seq, val);
-               else if (tp->repair_queue == TCP_RECV_QUEUE) {
-                       WRITE_ONCE(tp->rcv_nxt, val);
-                       WRITE_ONCE(tp->copied_seq, val);
-               }
-               else
+               } else if (tp->repair_queue == TCP_SEND_QUEUE) {
+                       if (!tcp_rtx_queue_empty(sk))
+                               err = -EPERM;
+                       else
+                               WRITE_ONCE(tp->write_seq, val);
+               } else if (tp->repair_queue == TCP_RECV_QUEUE) {
+                       if (tp->rcv_nxt != tp->copied_seq) {
+                               err = -EPERM;
+                       } else {
+                               WRITE_ONCE(tp->rcv_nxt, val);
+                               WRITE_ONCE(tp->copied_seq, val);
+                       }
+               } else {
                        err = -EINVAL;
+               }
                break;
 
        case TCP_REPAIR_OPTIONS:
@@ -4143,7 +4150,8 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
 
                if (get_user(len, optlen))
                        return -EFAULT;
-               if (len < offsetofend(struct tcp_zerocopy_receive, length))
+               if (len < 0 ||
+                   len < offsetofend(struct tcp_zerocopy_receive, length))
                        return -EINVAL;
                if (unlikely(len > sizeof(zc))) {
                        err = check_zeroed_user(optval + sizeof(zc),
index b76c48e..c5b4b58 100644 (file)
@@ -526,7 +526,7 @@ struct sk_buff *udp_gro_receive(struct list_head *head, struct sk_buff *skb,
        }
 
        if (!sk || NAPI_GRO_CB(skb)->encap_mark ||
-           (skb->ip_summed != CHECKSUM_PARTIAL &&
+           (uh->check && skb->ip_summed != CHECKSUM_PARTIAL &&
             NAPI_GRO_CB(skb)->csum_cnt == 0 &&
             !NAPI_GRO_CB(skb)->csum_valid) ||
            !udp_sk(sk)->gro_receive)
index 51184a7..1578ed9 100644 (file)
@@ -83,6 +83,9 @@ struct calipso_map_cache_entry {
 
 static struct calipso_map_cache_bkt *calipso_cache;
 
+static void calipso_cache_invalidate(void);
+static void calipso_doi_putdef(struct calipso_doi *doi_def);
+
 /* Label Mapping Cache Functions
  */
 
@@ -444,15 +447,10 @@ static int calipso_doi_remove(u32 doi, struct netlbl_audit *audit_info)
                ret_val = -ENOENT;
                goto doi_remove_return;
        }
-       if (!refcount_dec_and_test(&doi_def->refcount)) {
-               spin_unlock(&calipso_doi_list_lock);
-               ret_val = -EBUSY;
-               goto doi_remove_return;
-       }
        list_del_rcu(&doi_def->list);
        spin_unlock(&calipso_doi_list_lock);
 
-       call_rcu(&doi_def->rcu, calipso_doi_free_rcu);
+       calipso_doi_putdef(doi_def);
        ret_val = 0;
 
 doi_remove_return:
@@ -508,10 +506,8 @@ static void calipso_doi_putdef(struct calipso_doi *doi_def)
 
        if (!refcount_dec_and_test(&doi_def->refcount))
                return;
-       spin_lock(&calipso_doi_list_lock);
-       list_del_rcu(&doi_def->list);
-       spin_unlock(&calipso_doi_list_lock);
 
+       calipso_cache_invalidate();
        call_rcu(&doi_def->rcu, calipso_doi_free_rcu);
 }
 
index c3bc89b..1baf43a 100644 (file)
@@ -678,8 +678,8 @@ static int prepare_ip6gre_xmit_ipv6(struct sk_buff *skb,
 
                tel = (struct ipv6_tlv_tnl_enc_lim *)&skb_network_header(skb)[offset];
                if (tel->encap_limit == 0) {
-                       icmpv6_send(skb, ICMPV6_PARAMPROB,
-                                   ICMPV6_HDR_FIELD, offset + 2);
+                       icmpv6_ndo_send(skb, ICMPV6_PARAMPROB,
+                                       ICMPV6_HDR_FIELD, offset + 2);
                        return -1;
                }
                *encap_limit = tel->encap_limit - 1;
@@ -805,8 +805,8 @@ static inline int ip6gre_xmit_ipv4(struct sk_buff *skb, struct net_device *dev)
        if (err != 0) {
                /* XXX: send ICMP error even if DF is not set. */
                if (err == -EMSGSIZE)
-                       icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
-                                 htonl(mtu));
+                       icmp_ndo_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
+                                     htonl(mtu));
                return -1;
        }
 
@@ -837,7 +837,7 @@ static inline int ip6gre_xmit_ipv6(struct sk_buff *skb, struct net_device *dev)
                          &mtu, skb->protocol);
        if (err != 0) {
                if (err == -EMSGSIZE)
-                       icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
+                       icmpv6_ndo_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
                return -1;
        }
 
@@ -1063,10 +1063,10 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
                /* XXX: send ICMP error even if DF is not set. */
                if (err == -EMSGSIZE) {
                        if (skb->protocol == htons(ETH_P_IP))
-                               icmp_send(skb, ICMP_DEST_UNREACH,
-                                         ICMP_FRAG_NEEDED, htonl(mtu));
+                               icmp_ndo_send(skb, ICMP_DEST_UNREACH,
+                                             ICMP_FRAG_NEEDED, htonl(mtu));
                        else
-                               icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
+                               icmpv6_ndo_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
                }
 
                goto tx_err;
index a7950ba..3fa0eca 100644 (file)
@@ -1332,8 +1332,8 @@ ipxip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev,
 
                                tel = (void *)&skb_network_header(skb)[offset];
                                if (tel->encap_limit == 0) {
-                                       icmpv6_send(skb, ICMPV6_PARAMPROB,
-                                               ICMPV6_HDR_FIELD, offset + 2);
+                                       icmpv6_ndo_send(skb, ICMPV6_PARAMPROB,
+                                                       ICMPV6_HDR_FIELD, offset + 2);
                                        return -1;
                                }
                                encap_limit = tel->encap_limit - 1;
@@ -1385,11 +1385,11 @@ ipxip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev,
                if (err == -EMSGSIZE)
                        switch (protocol) {
                        case IPPROTO_IPIP:
-                               icmp_send(skb, ICMP_DEST_UNREACH,
-                                         ICMP_FRAG_NEEDED, htonl(mtu));
+                               icmp_ndo_send(skb, ICMP_DEST_UNREACH,
+                                             ICMP_FRAG_NEEDED, htonl(mtu));
                                break;
                        case IPPROTO_IPV6:
-                               icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
+                               icmpv6_ndo_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
                                break;
                        default:
                                break;
index 0225fd6..f10e7a7 100644 (file)
@@ -521,10 +521,10 @@ vti6_xmit(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
                        if (mtu < IPV6_MIN_MTU)
                                mtu = IPV6_MIN_MTU;
 
-                       icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
+                       icmpv6_ndo_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
                } else {
-                       icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
-                                 htonl(mtu));
+                       icmp_ndo_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
+                                     htonl(mtu));
                }
 
                err = -EMSGSIZE;
index 9363686..63ccd9f 100644 (file)
@@ -987,7 +987,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
                        skb_dst_update_pmtu_no_confirm(skb, mtu);
 
                if (skb->len > mtu && !skb_is_gso(skb)) {
-                       icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
+                       icmpv6_ndo_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
                        ip_rt_put(rt);
                        goto tx_error;
                }
index 7be5103..203890e 100644 (file)
@@ -649,9 +649,9 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,
        /* Parse and check optional cookie */
        if (session->peer_cookie_len > 0) {
                if (memcmp(ptr, &session->peer_cookie[0], session->peer_cookie_len)) {
-                       pr_warn_ratelimited("%s: cookie mismatch (%u/%u). Discarding.\n",
-                                           tunnel->name, tunnel->tunnel_id,
-                                           session->session_id);
+                       pr_debug_ratelimited("%s: cookie mismatch (%u/%u). Discarding.\n",
+                                            tunnel->name, tunnel->tunnel_id,
+                                            session->session_id);
                        atomic_long_inc(&session->stats.rx_cookie_discards);
                        goto discard;
                }
@@ -702,8 +702,8 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,
                 * If user has configured mandatory sequence numbers, discard.
                 */
                if (session->recv_seq) {
-                       pr_warn_ratelimited("%s: recv data has no seq numbers when required. Discarding.\n",
-                                           session->name);
+                       pr_debug_ratelimited("%s: recv data has no seq numbers when required. Discarding.\n",
+                                            session->name);
                        atomic_long_inc(&session->stats.rx_seq_discards);
                        goto discard;
                }
@@ -718,8 +718,8 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,
                        session->send_seq = 0;
                        l2tp_session_set_header_len(session, tunnel->version);
                } else if (session->send_seq) {
-                       pr_warn_ratelimited("%s: recv data has no seq numbers when required. Discarding.\n",
-                                           session->name);
+                       pr_debug_ratelimited("%s: recv data has no seq numbers when required. Discarding.\n",
+                                            session->name);
                        atomic_long_inc(&session->stats.rx_seq_discards);
                        goto discard;
                }
@@ -809,9 +809,9 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb)
 
        /* Short packet? */
        if (!pskb_may_pull(skb, L2TP_HDR_SIZE_MAX)) {
-               pr_warn_ratelimited("%s: recv short packet (len=%d)\n",
-                                   tunnel->name, skb->len);
-               goto error;
+               pr_debug_ratelimited("%s: recv short packet (len=%d)\n",
+                                    tunnel->name, skb->len);
+               goto invalid;
        }
 
        /* Point to L2TP header */
@@ -824,9 +824,9 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb)
        /* Check protocol version */
        version = hdrflags & L2TP_HDR_VER_MASK;
        if (version != tunnel->version) {
-               pr_warn_ratelimited("%s: recv protocol version mismatch: got %d expected %d\n",
-                                   tunnel->name, version, tunnel->version);
-               goto error;
+               pr_debug_ratelimited("%s: recv protocol version mismatch: got %d expected %d\n",
+                                    tunnel->name, version, tunnel->version);
+               goto invalid;
        }
 
        /* Get length of L2TP packet */
@@ -834,7 +834,7 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb)
 
        /* If type is control packet, it is handled by userspace. */
        if (hdrflags & L2TP_HDRFLAG_T)
-               goto error;
+               goto pass;
 
        /* Skip flags */
        ptr += 2;
@@ -863,21 +863,24 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb)
                        l2tp_session_dec_refcount(session);
 
                /* Not found? Pass to userspace to deal with */
-               pr_warn_ratelimited("%s: no session found (%u/%u). Passing up.\n",
-                                   tunnel->name, tunnel_id, session_id);
-               goto error;
+               pr_debug_ratelimited("%s: no session found (%u/%u). Passing up.\n",
+                                    tunnel->name, tunnel_id, session_id);
+               goto pass;
        }
 
        if (tunnel->version == L2TP_HDR_VER_3 &&
            l2tp_v3_ensure_opt_in_linear(session, skb, &ptr, &optr))
-               goto error;
+               goto invalid;
 
        l2tp_recv_common(session, skb, ptr, optr, hdrflags, length);
        l2tp_session_dec_refcount(session);
 
        return 0;
 
-error:
+invalid:
+       atomic_long_inc(&tunnel->stats.rx_invalid);
+
+pass:
        /* Put UDP header back */
        __skb_push(skb, sizeof(struct udphdr));
 
index cb21d90..98ea98e 100644 (file)
@@ -39,6 +39,7 @@ struct l2tp_stats {
        atomic_long_t           rx_oos_packets;
        atomic_long_t           rx_errors;
        atomic_long_t           rx_cookie_discards;
+       atomic_long_t           rx_invalid;
 };
 
 struct l2tp_tunnel;
index 83956c9..96eb91b 100644 (file)
@@ -428,6 +428,9 @@ static int l2tp_nl_tunnel_send(struct sk_buff *skb, u32 portid, u32 seq, int fla
                              L2TP_ATTR_STATS_PAD) ||
            nla_put_u64_64bit(skb, L2TP_ATTR_RX_ERRORS,
                              atomic_long_read(&tunnel->stats.rx_errors),
+                             L2TP_ATTR_STATS_PAD) ||
+           nla_put_u64_64bit(skb, L2TP_ATTR_RX_INVALID,
+                             atomic_long_read(&tunnel->stats.rx_invalid),
                              L2TP_ATTR_STATS_PAD))
                goto nla_put_failure;
        nla_nest_end(skb, nest);
@@ -771,6 +774,9 @@ static int l2tp_nl_session_send(struct sk_buff *skb, u32 portid, u32 seq, int fl
                              L2TP_ATTR_STATS_PAD) ||
            nla_put_u64_64bit(skb, L2TP_ATTR_RX_ERRORS,
                              atomic_long_read(&session->stats.rx_errors),
+                             L2TP_ATTR_STATS_PAD) ||
+           nla_put_u64_64bit(skb, L2TP_ATTR_RX_INVALID,
+                             atomic_long_read(&session->stats.rx_invalid),
                              L2TP_ATTR_STATS_PAD))
                goto nla_put_failure;
        nla_nest_end(skb, nest);
index b169014..1482259 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/netdev_features.h>
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
+#include <net/mpls.h>
 
 static struct sk_buff *mpls_gso_segment(struct sk_buff *skb,
                                       netdev_features_t features)
@@ -27,6 +28,8 @@ static struct sk_buff *mpls_gso_segment(struct sk_buff *skb,
 
        skb_reset_network_header(skb);
        mpls_hlen = skb_inner_network_header(skb) - skb_network_header(skb);
+       if (unlikely(!mpls_hlen || mpls_hlen % MPLS_HLEN))
+               goto out;
        if (unlikely(!pskb_may_pull(skb, mpls_hlen)))
                goto out;
 
index c5d5e68..7695857 100644 (file)
@@ -1061,6 +1061,12 @@ out:
        }
 }
 
+static void __mptcp_clean_una_wakeup(struct sock *sk)
+{
+       __mptcp_clean_una(sk);
+       mptcp_write_space(sk);
+}
+
 static void mptcp_enter_memory_pressure(struct sock *sk)
 {
        struct mptcp_subflow_context *subflow;
@@ -1189,6 +1195,7 @@ static bool mptcp_tx_cache_refill(struct sock *sk, int size,
                         */
                        while (skbs->qlen > 1) {
                                skb = __skb_dequeue_tail(skbs);
+                               *total_ts -= skb->truesize;
                                __kfree_skb(skb);
                        }
                        return skbs->qlen > 0;
@@ -1444,7 +1451,7 @@ static void mptcp_push_release(struct sock *sk, struct sock *ssk,
        release_sock(ssk);
 }
 
-static void mptcp_push_pending(struct sock *sk, unsigned int flags)
+static void __mptcp_push_pending(struct sock *sk, unsigned int flags)
 {
        struct sock *prev_ssk = NULL, *ssk = NULL;
        struct mptcp_sock *msk = mptcp_sk(sk);
@@ -1696,14 +1703,14 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 
 wait_for_memory:
                mptcp_set_nospace(sk);
-               mptcp_push_pending(sk, msg->msg_flags);
+               __mptcp_push_pending(sk, msg->msg_flags);
                ret = sk_stream_wait_memory(sk, &timeo);
                if (ret)
                        goto out;
        }
 
        if (copied)
-               mptcp_push_pending(sk, msg->msg_flags);
+               __mptcp_push_pending(sk, msg->msg_flags);
 
 out:
        release_sock(sk);
@@ -2115,6 +2122,14 @@ static struct sock *mptcp_subflow_get_retrans(const struct mptcp_sock *msk)
        return backup;
 }
 
+static void mptcp_dispose_initial_subflow(struct mptcp_sock *msk)
+{
+       if (msk->subflow) {
+               iput(SOCK_INODE(msk->subflow));
+               msk->subflow = NULL;
+       }
+}
+
 /* subflow sockets can be either outgoing (connect) or incoming
  * (accept).
  *
@@ -2126,6 +2141,8 @@ static struct sock *mptcp_subflow_get_retrans(const struct mptcp_sock *msk)
 static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk,
                              struct mptcp_subflow_context *subflow)
 {
+       struct mptcp_sock *msk = mptcp_sk(sk);
+
        list_del(&subflow->node);
 
        lock_sock_nested(ssk, SINGLE_DEPTH_NESTING);
@@ -2154,6 +2171,18 @@ static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk,
        release_sock(ssk);
 
        sock_put(ssk);
+
+       if (ssk == msk->last_snd)
+               msk->last_snd = NULL;
+
+       if (ssk == msk->ack_hint)
+               msk->ack_hint = NULL;
+
+       if (ssk == msk->first)
+               msk->first = NULL;
+
+       if (msk->subflow && ssk == msk->subflow->sk)
+               mptcp_dispose_initial_subflow(msk);
 }
 
 void mptcp_close_ssk(struct sock *sk, struct sock *ssk,
@@ -2238,14 +2267,58 @@ static void mptcp_check_fastclose(struct mptcp_sock *msk)
        mptcp_close_wake_up(sk);
 }
 
-static void mptcp_worker(struct work_struct *work)
+static void __mptcp_retrans(struct sock *sk)
 {
-       struct mptcp_sock *msk = container_of(work, struct mptcp_sock, work);
-       struct sock *ssk, *sk = &msk->sk.icsk_inet.sk;
+       struct mptcp_sock *msk = mptcp_sk(sk);
        struct mptcp_sendmsg_info info = {};
        struct mptcp_data_frag *dfrag;
        size_t copied = 0;
-       int state, ret;
+       struct sock *ssk;
+       int ret;
+
+       __mptcp_clean_una_wakeup(sk);
+       dfrag = mptcp_rtx_head(sk);
+       if (!dfrag)
+               return;
+
+       ssk = mptcp_subflow_get_retrans(msk);
+       if (!ssk)
+               goto reset_timer;
+
+       lock_sock(ssk);
+
+       /* limit retransmission to the bytes already sent on some subflows */
+       info.sent = 0;
+       info.limit = dfrag->already_sent;
+       while (info.sent < dfrag->already_sent) {
+               if (!mptcp_alloc_tx_skb(sk, ssk))
+                       break;
+
+               ret = mptcp_sendmsg_frag(sk, ssk, dfrag, &info);
+               if (ret <= 0)
+                       break;
+
+               MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_RETRANSSEGS);
+               copied += ret;
+               info.sent += ret;
+       }
+       if (copied)
+               tcp_push(ssk, 0, info.mss_now, tcp_sk(ssk)->nonagle,
+                        info.size_goal);
+
+       mptcp_set_timeout(sk, ssk);
+       release_sock(ssk);
+
+reset_timer:
+       if (!mptcp_timer_pending(sk))
+               mptcp_reset_timer(sk);
+}
+
+static void mptcp_worker(struct work_struct *work)
+{
+       struct mptcp_sock *msk = container_of(work, struct mptcp_sock, work);
+       struct sock *sk = &msk->sk.icsk_inet.sk;
+       int state;
 
        lock_sock(sk);
        state = sk->sk_state;
@@ -2280,45 +2353,8 @@ static void mptcp_worker(struct work_struct *work)
        if (test_and_clear_bit(MPTCP_WORK_CLOSE_SUBFLOW, &msk->flags))
                __mptcp_close_subflow(msk);
 
-       if (!test_and_clear_bit(MPTCP_WORK_RTX, &msk->flags))
-               goto unlock;
-
-       __mptcp_clean_una(sk);
-       dfrag = mptcp_rtx_head(sk);
-       if (!dfrag)
-               goto unlock;
-
-       ssk = mptcp_subflow_get_retrans(msk);
-       if (!ssk)
-               goto reset_unlock;
-
-       lock_sock(ssk);
-
-       /* limit retransmission to the bytes already sent on some subflows */
-       info.sent = 0;
-       info.limit = dfrag->already_sent;
-       while (info.sent < dfrag->already_sent) {
-               if (!mptcp_alloc_tx_skb(sk, ssk))
-                       break;
-
-               ret = mptcp_sendmsg_frag(sk, ssk, dfrag, &info);
-               if (ret <= 0)
-                       break;
-
-               MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_RETRANSSEGS);
-               copied += ret;
-               info.sent += ret;
-       }
-       if (copied)
-               tcp_push(ssk, 0, info.mss_now, tcp_sk(ssk)->nonagle,
-                        info.size_goal);
-
-       mptcp_set_timeout(sk, ssk);
-       release_sock(ssk);
-
-reset_unlock:
-       if (!mptcp_timer_pending(sk))
-               mptcp_reset_timer(sk);
+       if (test_and_clear_bit(MPTCP_WORK_RTX, &msk->flags))
+               __mptcp_retrans(sk);
 
 unlock:
        release_sock(sk);
@@ -2523,12 +2559,6 @@ static void __mptcp_destroy_sock(struct sock *sk)
 
        might_sleep();
 
-       /* dispose the ancillatory tcp socket, if any */
-       if (msk->subflow) {
-               iput(SOCK_INODE(msk->subflow));
-               msk->subflow = NULL;
-       }
-
        /* be sure to always acquire the join list lock, to sync vs
         * mptcp_finish_join().
         */
@@ -2553,6 +2583,7 @@ static void __mptcp_destroy_sock(struct sock *sk)
        sk_stream_kill_queues(sk);
        xfrm_sk_free_policy(sk);
        sk_refcnt_debug_release(sk);
+       mptcp_dispose_initial_subflow(msk);
        sock_put(sk);
 }
 
@@ -2934,13 +2965,14 @@ static void mptcp_release_cb(struct sock *sk)
 {
        unsigned long flags, nflags;
 
-       /* push_pending may touch wmem_reserved, do it before the later
-        * cleanup
-        */
-       if (test_and_clear_bit(MPTCP_CLEAN_UNA, &mptcp_sk(sk)->flags))
-               __mptcp_clean_una(sk);
-       if (test_and_clear_bit(MPTCP_PUSH_PENDING, &mptcp_sk(sk)->flags)) {
-               /* mptcp_push_pending() acquires the subflow socket lock
+       for (;;) {
+               flags = 0;
+               if (test_and_clear_bit(MPTCP_PUSH_PENDING, &mptcp_sk(sk)->flags))
+                       flags |= MPTCP_PUSH_PENDING;
+               if (!flags)
+                       break;
+
+               /* the following actions acquire the subflow socket lock
                 *
                 * 1) can't be invoked in atomic scope
                 * 2) must avoid ABBA deadlock with msk socket spinlock: the RX
@@ -2949,13 +2981,21 @@ static void mptcp_release_cb(struct sock *sk)
                 */
 
                spin_unlock_bh(&sk->sk_lock.slock);
-               mptcp_push_pending(sk, 0);
+               if (flags & MPTCP_PUSH_PENDING)
+                       __mptcp_push_pending(sk, 0);
+
+               cond_resched();
                spin_lock_bh(&sk->sk_lock.slock);
        }
+
+       if (test_and_clear_bit(MPTCP_CLEAN_UNA, &mptcp_sk(sk)->flags))
+               __mptcp_clean_una_wakeup(sk);
        if (test_and_clear_bit(MPTCP_ERROR_REPORT, &mptcp_sk(sk)->flags))
                __mptcp_error_report(sk);
 
-       /* clear any wmem reservation and errors */
+       /* push_pending may touch wmem_reserved, ensure we do the cleanup
+        * later
+        */
        __mptcp_update_wmem(sk);
        __mptcp_update_rmem(sk);
 
@@ -3285,6 +3325,9 @@ static int mptcp_stream_accept(struct socket *sock, struct socket *newsock,
                /* PM/worker can now acquire the first subflow socket
                 * lock without racing with listener queue cleanup,
                 * we can notify it, if needed.
+                *
+                * Even if remote has reset the initial subflow by now
+                * the refcnt is still at least one.
                 */
                subflow = mptcp_subflow_ctx(msk->first);
                list_add(&subflow->node, &msk->conn_list);
index 91827d9..e21a5bc 100644 (file)
 #define TCPOLEN_MPTCP_DSS_MAP64                14
 #define TCPOLEN_MPTCP_DSS_CHECKSUM     2
 #define TCPOLEN_MPTCP_ADD_ADDR         16
-#define TCPOLEN_MPTCP_ADD_ADDR_PORT    20
+#define TCPOLEN_MPTCP_ADD_ADDR_PORT    18
 #define TCPOLEN_MPTCP_ADD_ADDR_BASE    8
-#define TCPOLEN_MPTCP_ADD_ADDR_BASE_PORT       12
+#define TCPOLEN_MPTCP_ADD_ADDR_BASE_PORT       10
 #define TCPOLEN_MPTCP_ADD_ADDR6                28
-#define TCPOLEN_MPTCP_ADD_ADDR6_PORT   32
+#define TCPOLEN_MPTCP_ADD_ADDR6_PORT   30
 #define TCPOLEN_MPTCP_ADD_ADDR6_BASE   20
-#define TCPOLEN_MPTCP_ADD_ADDR6_BASE_PORT      24
-#define TCPOLEN_MPTCP_PORT_LEN         4
+#define TCPOLEN_MPTCP_ADD_ADDR6_BASE_PORT      22
+#define TCPOLEN_MPTCP_PORT_LEN         2
+#define TCPOLEN_MPTCP_PORT_ALIGN       2
 #define TCPOLEN_MPTCP_RM_ADDR_BASE     4
 #define TCPOLEN_MPTCP_PRIO             3
 #define TCPOLEN_MPTCP_PRIO_ALIGN       4
@@ -701,8 +702,9 @@ static inline unsigned int mptcp_add_addr_len(int family, bool echo, bool port)
                len = TCPOLEN_MPTCP_ADD_ADDR6_BASE;
        if (!echo)
                len += MPTCPOPT_THMAC_LEN;
+       /* account for 2 trailing 'nop' options */
        if (port)
-               len += TCPOLEN_MPTCP_PORT_LEN;
+               len += TCPOLEN_MPTCP_PORT_LEN + TCPOLEN_MPTCP_PORT_ALIGN;
 
        return len;
 }
index e1fbcab..3d47d67 100644 (file)
@@ -687,11 +687,6 @@ create_child:
                        /* move the msk reference ownership to the subflow */
                        subflow_req->msk = NULL;
                        ctx->conn = (struct sock *)owner;
-                       if (!mptcp_finish_join(child))
-                               goto dispose_child;
-
-                       SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINACKRX);
-                       tcp_rsk(req)->drop_req = true;
 
                        if (subflow_use_different_sport(owner, sk)) {
                                pr_debug("ack inet_sport=%d %d",
@@ -699,10 +694,16 @@ create_child:
                                         ntohs(inet_sk((struct sock *)owner)->inet_sport));
                                if (!mptcp_pm_sport_in_anno_list(owner, sk)) {
                                        SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_MISMATCHPORTACKRX);
-                                       goto out;
+                                       goto dispose_child;
                                }
                                SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINPORTACKRX);
                        }
+
+                       if (!mptcp_finish_join(child))
+                               goto dispose_child;
+
+                       SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINACKRX);
+                       tcp_rsk(req)->drop_req = true;
                }
        }
 
@@ -1297,6 +1298,7 @@ failed_unlink:
        spin_lock_bh(&msk->join_list_lock);
        list_del(&subflow->node);
        spin_unlock_bh(&msk->join_list_lock);
+       sock_put(mptcp_subflow_tcp_sock(subflow));
 
 failed:
        subflow->disposable = 1;
index 118f415..b055187 100644 (file)
@@ -219,7 +219,7 @@ nf_ct_lookup_helper(struct nf_conn *ct, struct net *net)
                        return NULL;
                pr_info("nf_conntrack: default automatic helper assignment "
                        "has been turned off for security reasons and CT-based "
-                       " firewall rule not found. Use the iptables CT target "
+                       "firewall rule not found. Use the iptables CT target "
                        "to attach helpers instead.\n");
                net->ct.auto_assign_helper_warned = 1;
                return NULL;
@@ -228,7 +228,6 @@ nf_ct_lookup_helper(struct nf_conn *ct, struct net *net)
        return __nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
 }
 
-
 int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl,
                              gfp_t flags)
 {
index 1d7e1c5..ec23330 100644 (file)
@@ -982,8 +982,10 @@ int nf_conntrack_tcp_packet(struct nf_conn *ct,
                                        IP_CT_EXP_CHALLENGE_ACK;
                }
                spin_unlock_bh(&ct->lock);
-               nf_ct_l4proto_log_invalid(skb, ct, "invalid packet ignored in "
-                                         "state %s ", tcp_conntrack_names[old_state]);
+               nf_ct_l4proto_log_invalid(skb, ct,
+                                         "packet (index %d) in dir %d ignored, state %s",
+                                         index, dir,
+                                         tcp_conntrack_names[old_state]);
                return NF_ACCEPT;
        case TCP_CONNTRACK_MAX:
                /* Special case for SYN proxy: when the SYN to the server or
index e87b6bd..4731d21 100644 (file)
@@ -646,8 +646,8 @@ nf_nat_ipv4_fn(void *priv, struct sk_buff *skb,
 }
 
 static unsigned int
-nf_nat_ipv4_in(void *priv, struct sk_buff *skb,
-              const struct nf_hook_state *state)
+nf_nat_ipv4_pre_routing(void *priv, struct sk_buff *skb,
+                       const struct nf_hook_state *state)
 {
        unsigned int ret;
        __be32 daddr = ip_hdr(skb)->daddr;
@@ -659,6 +659,23 @@ nf_nat_ipv4_in(void *priv, struct sk_buff *skb,
        return ret;
 }
 
+static unsigned int
+nf_nat_ipv4_local_in(void *priv, struct sk_buff *skb,
+                    const struct nf_hook_state *state)
+{
+       __be32 saddr = ip_hdr(skb)->saddr;
+       struct sock *sk = skb->sk;
+       unsigned int ret;
+
+       ret = nf_nat_ipv4_fn(priv, skb, state);
+
+       if (ret == NF_ACCEPT && sk && saddr != ip_hdr(skb)->saddr &&
+           !inet_sk_transparent(sk))
+               skb_orphan(skb); /* TCP edemux obtained wrong socket */
+
+       return ret;
+}
+
 static unsigned int
 nf_nat_ipv4_out(void *priv, struct sk_buff *skb,
                const struct nf_hook_state *state)
@@ -736,7 +753,7 @@ nf_nat_ipv4_local_fn(void *priv, struct sk_buff *skb,
 static const struct nf_hook_ops nf_nat_ipv4_ops[] = {
        /* Before packet filtering, change destination */
        {
-               .hook           = nf_nat_ipv4_in,
+               .hook           = nf_nat_ipv4_pre_routing,
                .pf             = NFPROTO_IPV4,
                .hooknum        = NF_INET_PRE_ROUTING,
                .priority       = NF_IP_PRI_NAT_DST,
@@ -757,7 +774,7 @@ static const struct nf_hook_ops nf_nat_ipv4_ops[] = {
        },
        /* After packet filtering, change source */
        {
-               .hook           = nf_nat_ipv4_fn,
+               .hook           = nf_nat_ipv4_local_in,
                .pf             = NFPROTO_IPV4,
                .hooknum        = NF_INET_LOCAL_IN,
                .priority       = NF_IP_PRI_NAT_SRC,
index c1eb5cd..224c8e5 100644 (file)
@@ -916,6 +916,12 @@ static int nf_tables_updtable(struct nft_ctx *ctx)
        if (flags == ctx->table->flags)
                return 0;
 
+       if ((nft_table_has_owner(ctx->table) &&
+            !(flags & NFT_TABLE_F_OWNER)) ||
+           (!nft_table_has_owner(ctx->table) &&
+            flags & NFT_TABLE_F_OWNER))
+               return -EOPNOTSUPP;
+
        trans = nft_trans_alloc(ctx, NFT_MSG_NEWTABLE,
                                sizeof(struct nft_trans_table));
        if (trans == NULL)
@@ -9022,8 +9028,12 @@ static void __nft_release_hooks(struct net *net)
 {
        struct nft_table *table;
 
-       list_for_each_entry(table, &net->nft.tables, list)
+       list_for_each_entry(table, &net->nft.tables, list) {
+               if (nft_table_has_owner(table))
+                       continue;
+
                __nft_release_hook(net, table);
+       }
 }
 
 static void __nft_release_table(struct net *net, struct nft_table *table)
@@ -9073,13 +9083,12 @@ static void __nft_release_table(struct net *net, struct nft_table *table)
        nf_tables_table_destroy(&ctx);
 }
 
-static void __nft_release_tables(struct net *net, u32 nlpid)
+static void __nft_release_tables(struct net *net)
 {
        struct nft_table *table, *nt;
 
        list_for_each_entry_safe(table, nt, &net->nft.tables, list) {
-               if (nft_table_has_owner(table) &&
-                   nlpid != table->nlpid)
+               if (nft_table_has_owner(table))
                        continue;
 
                __nft_release_table(net, table);
@@ -9145,7 +9154,7 @@ static void __net_exit nf_tables_exit_net(struct net *net)
        mutex_lock(&net->nft.commit_mutex);
        if (!list_empty(&net->nft.commit_list))
                __nf_tables_abort(net, NFNL_ABORT_NONE);
-       __nft_release_tables(net, 0);
+       __nft_release_tables(net);
        mutex_unlock(&net->nft.commit_mutex);
        WARN_ON_ONCE(!list_empty(&net->nft.tables));
        WARN_ON_ONCE(!list_empty(&net->nft.module_list));
index acce622..bce6ca2 100644 (file)
@@ -330,6 +330,7 @@ static int match_revfn(u8 af, const char *name, u8 revision, int *bestp)
        const struct xt_match *m;
        int have_rev = 0;
 
+       mutex_lock(&xt[af].mutex);
        list_for_each_entry(m, &xt[af].match, list) {
                if (strcmp(m->name, name) == 0) {
                        if (m->revision > *bestp)
@@ -338,6 +339,7 @@ static int match_revfn(u8 af, const char *name, u8 revision, int *bestp)
                                have_rev = 1;
                }
        }
+       mutex_unlock(&xt[af].mutex);
 
        if (af != NFPROTO_UNSPEC && !have_rev)
                return match_revfn(NFPROTO_UNSPEC, name, revision, bestp);
@@ -350,6 +352,7 @@ static int target_revfn(u8 af, const char *name, u8 revision, int *bestp)
        const struct xt_target *t;
        int have_rev = 0;
 
+       mutex_lock(&xt[af].mutex);
        list_for_each_entry(t, &xt[af].target, list) {
                if (strcmp(t->name, name) == 0) {
                        if (t->revision > *bestp)
@@ -358,6 +361,7 @@ static int target_revfn(u8 af, const char *name, u8 revision, int *bestp)
                                have_rev = 1;
                }
        }
+       mutex_unlock(&xt[af].mutex);
 
        if (af != NFPROTO_UNSPEC && !have_rev)
                return target_revfn(NFPROTO_UNSPEC, name, revision, bestp);
@@ -371,12 +375,10 @@ int xt_find_revision(u8 af, const char *name, u8 revision, int target,
 {
        int have_rev, best = -1;
 
-       mutex_lock(&xt[af].mutex);
        if (target == 1)
                have_rev = target_revfn(af, name, revision, &best);
        else
                have_rev = match_revfn(af, name, revision, &best);
-       mutex_unlock(&xt[af].mutex);
 
        /* Nothing at all?  Return 0 to try loading module. */
        if (best == -1) {
index 726dda9..4f50a64 100644 (file)
@@ -575,6 +575,7 @@ list_start:
 
                break;
        }
+       cipso_v4_doi_putdef(doi_def);
        rcu_read_unlock();
 
        genlmsg_end(ans_skb, data);
@@ -583,12 +584,14 @@ list_start:
 list_retry:
        /* XXX - this limit is a guesstimate */
        if (nlsze_mult < 4) {
+               cipso_v4_doi_putdef(doi_def);
                rcu_read_unlock();
                kfree_skb(ans_skb);
                nlsze_mult *= 2;
                goto list_start;
        }
 list_failure_lock:
+       cipso_v4_doi_putdef(doi_def);
        rcu_read_unlock();
 list_failure:
        kfree_skb(ans_skb);
index b343582..edb6ac1 100644 (file)
@@ -439,7 +439,7 @@ int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len)
        if (len == 0 || len & 3)
                return -EINVAL;
 
-       skb = netdev_alloc_skb(NULL, len);
+       skb = __netdev_alloc_skb(NULL, len, GFP_ATOMIC | __GFP_NOWARN);
        if (!skb)
                return -ENOMEM;
 
@@ -958,8 +958,10 @@ static int qrtr_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
        plen = (len + 3) & ~3;
        skb = sock_alloc_send_skb(sk, plen + QRTR_HDR_MAX_SIZE,
                                  msg->msg_flags & MSG_DONTWAIT, &rc);
-       if (!skb)
+       if (!skb) {
+               rc = -ENOMEM;
                goto out_node;
+       }
 
        skb_reserve(skb, QRTR_HDR_MAX_SIZE);
 
index e2e4353..f87d077 100644 (file)
@@ -2168,7 +2168,7 @@ static int tc_dump_tclass_qdisc(struct Qdisc *q, struct sk_buff *skb,
 
 static int tc_dump_tclass_root(struct Qdisc *root, struct sk_buff *skb,
                               struct tcmsg *tcm, struct netlink_callback *cb,
-                              int *t_p, int s_t)
+                              int *t_p, int s_t, bool recur)
 {
        struct Qdisc *q;
        int b;
@@ -2179,7 +2179,7 @@ static int tc_dump_tclass_root(struct Qdisc *root, struct sk_buff *skb,
        if (tc_dump_tclass_qdisc(root, skb, tcm, cb, t_p, s_t) < 0)
                return -1;
 
-       if (!qdisc_dev(root))
+       if (!qdisc_dev(root) || !recur)
                return 0;
 
        if (tcm->tcm_parent) {
@@ -2214,13 +2214,13 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb)
        s_t = cb->args[0];
        t = 0;
 
-       if (tc_dump_tclass_root(dev->qdisc, skb, tcm, cb, &t, s_t) < 0)
+       if (tc_dump_tclass_root(dev->qdisc, skb, tcm, cb, &t, s_t, true) < 0)
                goto done;
 
        dev_queue = dev_ingress_queue(dev);
        if (dev_queue &&
            tc_dump_tclass_root(dev_queue->qdisc_sleeping, skb, tcm, cb,
-                               &t, s_t) < 0)
+                               &t, s_t, false) < 0)
                goto done;
 
 done:
index a9c6af5..5ba4567 100644 (file)
@@ -75,7 +75,7 @@ int sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn)
                return 1;
 
        /* Verify that we can hold this TSN and that it will not
-        * overlfow our map
+        * overflow our map
         */
        if (!TSN_lt(tsn, map->base_tsn + SCTP_TSN_MAP_SIZE))
                return -1;
index bd4678d..6dff643 100644 (file)
@@ -1825,11 +1825,14 @@ static int
 svcauth_gss_release(struct svc_rqst *rqstp)
 {
        struct gss_svc_data *gsd = (struct gss_svc_data *)rqstp->rq_auth_data;
-       struct rpc_gss_wire_cred *gc = &gsd->clcred;
+       struct rpc_gss_wire_cred *gc;
        struct xdr_buf *resbuf = &rqstp->rq_res;
        int stat = -EINVAL;
        struct sunrpc_net *sn = net_generic(SVC_NET(rqstp), sunrpc_net_id);
 
+       if (!gsd)
+               goto out;
+       gc = &gsd->clcred;
        if (gc->gc_proc != RPC_GSS_PROC_DATA)
                goto out;
        /* Release can be called twice, but we only wrap once. */
@@ -1870,10 +1873,10 @@ out_err:
        if (rqstp->rq_cred.cr_group_info)
                put_group_info(rqstp->rq_cred.cr_group_info);
        rqstp->rq_cred.cr_group_info = NULL;
-       if (gsd->rsci)
+       if (gsd && gsd->rsci) {
                cache_put(&gsd->rsci->h, sn->rsc_cache);
-       gsd->rsci = NULL;
-
+               gsd->rsci = NULL;
+       }
        return stat;
 }
 
index cf702a5..39ed0e0 100644 (file)
@@ -963,8 +963,11 @@ void rpc_execute(struct rpc_task *task)
 
        rpc_set_active(task);
        rpc_make_runnable(rpciod_workqueue, task);
-       if (!is_async)
+       if (!is_async) {
+               unsigned int pflags = memalloc_nofs_save();
                __rpc_execute(task);
+               memalloc_nofs_restore(pflags);
+       }
 }
 
 static void rpc_async_schedule(struct work_struct *work)
index 61fb8a1..d76dc9d 100644 (file)
@@ -1413,7 +1413,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
 
  sendit:
        if (svc_authorise(rqstp))
-               goto close;
+               goto close_xprt;
        return 1;               /* Caller can now send it */
 
 release_dropit:
@@ -1425,6 +1425,8 @@ release_dropit:
        return 0;
 
  close:
+       svc_authorise(rqstp);
+close_xprt:
        if (rqstp->rq_xprt && test_bit(XPT_TEMP, &rqstp->rq_xprt->xpt_flags))
                svc_close_xprt(rqstp->rq_xprt);
        dprintk("svc: svc_process close\n");
@@ -1433,7 +1435,7 @@ release_dropit:
 err_short_len:
        svc_printk(rqstp, "short len %zd, dropping request\n",
                        argv->iov_len);
-       goto close;
+       goto close_xprt;
 
 err_bad_rpc:
        serv->sv_stats->rpcbadfmt++;
index dcc50ae..3cdd71a 100644 (file)
@@ -1060,7 +1060,7 @@ static int svc_close_list(struct svc_serv *serv, struct list_head *xprt_list, st
        struct svc_xprt *xprt;
        int ret = 0;
 
-       spin_lock(&serv->sv_lock);
+       spin_lock_bh(&serv->sv_lock);
        list_for_each_entry(xprt, xprt_list, xpt_list) {
                if (xprt->xpt_net != net)
                        continue;
@@ -1068,7 +1068,7 @@ static int svc_close_list(struct svc_serv *serv, struct list_head *xprt_list, st
                set_bit(XPT_CLOSE, &xprt->xpt_flags);
                svc_xprt_enqueue(xprt);
        }
-       spin_unlock(&serv->sv_lock);
+       spin_unlock_bh(&serv->sv_lock);
        return ret;
 }
 
index 4a1edbb..9150df3 100644 (file)
@@ -252,9 +252,9 @@ xprt_setup_rdma_bc(struct xprt_create *args)
        xprt->timeout = &xprt_rdma_bc_timeout;
        xprt_set_bound(xprt);
        xprt_set_connected(xprt);
-       xprt->bind_timeout = RPCRDMA_BIND_TO;
-       xprt->reestablish_timeout = RPCRDMA_INIT_REEST_TO;
-       xprt->idle_timeout = RPCRDMA_IDLE_DISC_TO;
+       xprt->bind_timeout = 0;
+       xprt->reestablish_timeout = 0;
+       xprt->idle_timeout = 0;
 
        xprt->prot = XPRT_TRANSPORT_BC_RDMA;
        xprt->ops = &xprt_rdma_bc_procs;
index 6d28f23..7d34290 100644 (file)
@@ -266,46 +266,33 @@ void svc_rdma_release_rqst(struct svc_rqst *rqstp)
                svc_rdma_recv_ctxt_put(rdma, ctxt);
 }
 
-static bool svc_rdma_refresh_recvs(struct svcxprt_rdma *rdma,
-                                  unsigned int wanted, bool temp)
+static int __svc_rdma_post_recv(struct svcxprt_rdma *rdma,
+                               struct svc_rdma_recv_ctxt *ctxt)
 {
-       const struct ib_recv_wr *bad_wr = NULL;
-       struct svc_rdma_recv_ctxt *ctxt;
-       struct ib_recv_wr *recv_chain;
        int ret;
 
-       recv_chain = NULL;
-       while (wanted--) {
-               ctxt = svc_rdma_recv_ctxt_get(rdma);
-               if (!ctxt)
-                       break;
-
-               trace_svcrdma_post_recv(ctxt);
-               ctxt->rc_temp = temp;
-               ctxt->rc_recv_wr.next = recv_chain;
-               recv_chain = &ctxt->rc_recv_wr;
-               rdma->sc_pending_recvs++;
-       }
-       if (!recv_chain)
-               return false;
-
-       ret = ib_post_recv(rdma->sc_qp, recv_chain, &bad_wr);
+       trace_svcrdma_post_recv(ctxt);
+       ret = ib_post_recv(rdma->sc_qp, &ctxt->rc_recv_wr, NULL);
        if (ret)
                goto err_post;
-       return true;
+       return 0;
 
 err_post:
-       while (bad_wr) {
-               ctxt = container_of(bad_wr, struct svc_rdma_recv_ctxt,
-                                   rc_recv_wr);
-               bad_wr = bad_wr->next;
-               svc_rdma_recv_ctxt_put(rdma, ctxt);
-       }
-
        trace_svcrdma_rq_post_err(rdma, ret);
-       /* Since we're destroying the xprt, no need to reset
-        * sc_pending_recvs. */
-       return false;
+       svc_rdma_recv_ctxt_put(rdma, ctxt);
+       return ret;
+}
+
+static int svc_rdma_post_recv(struct svcxprt_rdma *rdma)
+{
+       struct svc_rdma_recv_ctxt *ctxt;
+
+       if (test_bit(XPT_CLOSE, &rdma->sc_xprt.xpt_flags))
+               return 0;
+       ctxt = svc_rdma_recv_ctxt_get(rdma);
+       if (!ctxt)
+               return -ENOMEM;
+       return __svc_rdma_post_recv(rdma, ctxt);
 }
 
 /**
@@ -316,7 +303,20 @@ err_post:
  */
 bool svc_rdma_post_recvs(struct svcxprt_rdma *rdma)
 {
-       return svc_rdma_refresh_recvs(rdma, rdma->sc_max_requests, true);
+       struct svc_rdma_recv_ctxt *ctxt;
+       unsigned int i;
+       int ret;
+
+       for (i = 0; i < rdma->sc_max_requests; i++) {
+               ctxt = svc_rdma_recv_ctxt_get(rdma);
+               if (!ctxt)
+                       return false;
+               ctxt->rc_temp = true;
+               ret = __svc_rdma_post_recv(rdma, ctxt);
+               if (ret)
+                       return false;
+       }
+       return true;
 }
 
 /**
@@ -324,6 +324,8 @@ bool svc_rdma_post_recvs(struct svcxprt_rdma *rdma)
  * @cq: Completion Queue context
  * @wc: Work Completion object
  *
+ * NB: The svc_xprt/svcxprt_rdma is pinned whenever it's possible that
+ * the Receive completion handler could be running.
  */
 static void svc_rdma_wc_receive(struct ib_cq *cq, struct ib_wc *wc)
 {
@@ -331,8 +333,6 @@ static void svc_rdma_wc_receive(struct ib_cq *cq, struct ib_wc *wc)
        struct ib_cqe *cqe = wc->wr_cqe;
        struct svc_rdma_recv_ctxt *ctxt;
 
-       rdma->sc_pending_recvs--;
-
        /* WARNING: Only wc->wr_cqe and wc->status are reliable */
        ctxt = container_of(cqe, struct svc_rdma_recv_ctxt, rc_cqe);
 
@@ -340,6 +340,9 @@ static void svc_rdma_wc_receive(struct ib_cq *cq, struct ib_wc *wc)
        if (wc->status != IB_WC_SUCCESS)
                goto flushed;
 
+       if (svc_rdma_post_recv(rdma))
+               goto post_err;
+
        /* All wc fields are now known to be valid */
        ctxt->rc_byte_len = wc->byte_len;
 
@@ -350,18 +353,11 @@ static void svc_rdma_wc_receive(struct ib_cq *cq, struct ib_wc *wc)
        spin_unlock(&rdma->sc_rq_dto_lock);
        if (!test_bit(RDMAXPRT_CONN_PENDING, &rdma->sc_flags))
                svc_xprt_enqueue(&rdma->sc_xprt);
-
-       if (!test_bit(XPT_CLOSE, &rdma->sc_xprt.xpt_flags) &&
-           rdma->sc_pending_recvs < rdma->sc_max_requests)
-               if (!svc_rdma_refresh_recvs(rdma, RPCRDMA_MAX_RECV_BATCH,
-                                           false))
-                       goto post_err;
-
        return;
 
 flushed:
-       svc_rdma_recv_ctxt_put(rdma, ctxt);
 post_err:
+       svc_rdma_recv_ctxt_put(rdma, ctxt);
        set_bit(XPT_CLOSE, &rdma->sc_xprt.xpt_flags);
        svc_xprt_enqueue(&rdma->sc_xprt);
 }
index db0cb73..1e2a110 100644 (file)
@@ -1699,5 +1699,7 @@ int main(int argc, char **argv)
 
        xdpsock_cleanup();
 
+       munmap(bufs, NUM_FRAMES * opt_xsk_frame_size);
+
        return 0;
 }
index eee5918..8cd67b1 100644 (file)
@@ -327,7 +327,7 @@ $(obj)/%.dtb.S: $(obj)/%.dtb FORCE
 
 quiet_cmd_dtc = DTC     $@
 cmd_dtc = $(HOSTCC) -E $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; \
-       $(DTC) -O $(patsubst .%,%,$(suffix $@)) -o $@ -b 0 \
+       $(DTC) -o $@ -b 0 \
                $(addprefix -i,$(dir $<) $(DTC_INCLUDE)) $(DTC_FLAGS) \
                -d $(depfile).dtc.tmp $(dtc-tmp) ; \
        cat $(depfile).pre.tmp $(depfile).dtc.tmp > $(depfile)
@@ -352,7 +352,7 @@ define rule_dtc
 endef
 
 $(obj)/%.dt.yaml: $(src)/%.dts $(DTC) $(DT_TMP_SCHEMA) FORCE
-       $(call if_changed_rule,dtc,yaml)
+       $(call if_changed_rule,dtc)
 
 dtc-tmp = $(subst $(comma),_,$(dot-target).dts.tmp)
 
index 5c113ca..39e65fe 100755 (executable)
@@ -57,9 +57,9 @@ if arg_contain --version "$@"; then
 fi
 
 if arg_contain -E "$@"; then
-       # For scripts/gcc-version.sh; This emulates GCC 20.0.0
+       # For scripts/cc-version.sh; This emulates GCC 20.0.0
        if arg_contain - "$@"; then
-               sed 's/^__GNUC__$/20/; s/^__GNUC_MINOR__$/0/; s/^__GNUC_PATCHLEVEL__$/0/'
+               sed -n '/^GCC/{s/__GNUC__/20/; s/__GNUC_MINOR__/0/; s/__GNUC_PATCHLEVEL__/0/; p;}'
                exit 0
        else
                echo "no input files" >&2
@@ -73,6 +73,15 @@ if arg_contain -S "$@"; then
                echo "%gs"
                exit 0
        fi
+
+       # For arch/powerpc/tools/gcc-check-mprofile-kernel.sh
+       if arg_contain -m64 "$@" && arg_contain -mlittle-endian "$@" &&
+               arg_contain -mprofile-kernel "$@"; then
+               if ! test -t 0 && ! grep -q notrace; then
+                       echo "_mcount"
+               fi
+               exit 0
+       fi
 fi
 
 # To set GCC_PLUGINS
@@ -85,3 +94,8 @@ if arg_contain -print-file-name=plugin "$@"; then
        echo $plugin_dir
        exit 0
 fi
+
+# inverted return value
+if arg_contain -D__SIZEOF_INT128__=0 "$@"; then
+       exit 1
+fi
index b5487cc..1952d3b 100644 (file)
@@ -22,6 +22,7 @@ always-y += $(GCC_PLUGIN)
 GCC_PLUGINS_DIR = $(shell $(CC) -print-file-name=plugin)
 
 plugin_cxxflags        = -Wp,-MMD,$(depfile) $(KBUILD_HOSTCXXFLAGS) -fPIC \
+                 -include $(srctree)/include/linux/compiler-version.h \
                   -I $(GCC_PLUGINS_DIR)/include -I $(obj) -std=gnu++11 \
                   -fno-rtti -fno-exceptions -fasynchronous-unwind-tables \
                   -ggdb -Wno-narrowing -Wno-unused-variable \
index a463273..1bf3aad 100755 (executable)
@@ -29,7 +29,7 @@ orig_args="$@"
 # Get the first line of the --version output.
 IFS='
 '
-set -- $("$@" --version)
+set -- $(LC_ALL=C "$@" --version)
 
 # Split the line on spaces.
 IFS=' '
@@ -44,14 +44,20 @@ if [ "$1" = GNU -a "$2" = ld ]; then
 elif [ "$1" = GNU -a "$2" = gold ]; then
        echo "gold linker is not supported as it is not capable of linking the kernel proper." >&2
        exit 1
-elif [ "$1" = LLD ]; then
-       version=$2
-       min_version=$lld_min_version
-       name=LLD
-       disp_name=LLD
 else
-       echo "$orig_args: unknown linker" >&2
-       exit 1
+       while [ $# -gt 1 -a "$1" != "LLD" ]; do
+               shift
+       done
+
+       if [ "$1" = LLD ]; then
+               version=$2
+               min_version=$lld_min_version
+               name=LLD
+               disp_name=LLD
+       else
+               echo "$orig_args: unknown linker" >&2
+               exit 1
+       fi
 fi
 
 # Some distributions append a package release number, as in 2.34-4.fc32
index 28f4d25..1c519c8 100644 (file)
@@ -543,8 +543,7 @@ int cap_convert_nscap(struct user_namespace *mnt_userns, struct dentry *dentry,
        __u32 magic, nsmagic;
        struct inode *inode = d_backing_inode(dentry);
        struct user_namespace *task_ns = current_user_ns(),
-               *fs_ns = inode->i_sb->s_user_ns,
-               *ancestor;
+               *fs_ns = inode->i_sb->s_user_ns;
        kuid_t rootid;
        size_t newsize;
 
@@ -567,15 +566,6 @@ int cap_convert_nscap(struct user_namespace *mnt_userns, struct dentry *dentry,
        if (nsrootid == -1)
                return -EINVAL;
 
-       /*
-        * Do not allow allow adding a v3 filesystem capability xattr
-        * if the rootid field is ambiguous.
-        */
-       for (ancestor = task_ns->parent; ancestor; ancestor = ancestor->parent) {
-               if (from_kuid(ancestor, rootid) == 0)
-                       return -EINVAL;
-       }
-
        newsize = sizeof(struct vfs_ns_cap_data);
        nscap = kmalloc(newsize, GFP_ATOMIC);
        if (!nscap)
index 8a24e5a..5263718 100644 (file)
@@ -33,7 +33,6 @@
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("A loopback soundcard");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{ALSA,Loopback soundcard}}");
 
 #define MAX_PCM_SUBSTREAMS     8
 
index 316c9af..01a3eab 100644 (file)
@@ -25,7 +25,6 @@
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("Dummy soundcard (/dev/null)");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{ALSA,Dummy soundcard}}");
 
 #define MAX_PCM_DEVICES                4
 #define MAX_PCM_SUBSTREAMS     128
index ce5fd17..df4b7f9 100644 (file)
@@ -53,7 +53,6 @@
 MODULE_AUTHOR("Michael T. Mayers");
 MODULE_DESCRIPTION("MOTU MidiTimePiece AV multiport MIDI");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{MOTU,MidiTimePiece AV multiport MIDI}}");
 
 // io resources
 #define MTPAV_IOBASE           0x378
index 9c708b6..322d530 100644 (file)
@@ -37,7 +37,6 @@ MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
 MODULE_AUTHOR("Matthias Koenig <mk@phasorlab.de>");
 MODULE_DESCRIPTION("ESI Miditerminal 4140");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{ESI,Miditerminal 4140}}");
 
 /*********************************************************************
  * Chip specific
index fd79e57..7689fa2 100644 (file)
@@ -22,7 +22,6 @@
 MODULE_AUTHOR("Stas Sergeev <stsp@users.sourceforge.net>");
 MODULE_DESCRIPTION("PC-Speaker driver");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{PC-Speaker, pcsp}}");
 MODULE_ALIAS("platform:pcspkr");
 
 static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
index c876cf9..2f4514e 100644 (file)
@@ -57,7 +57,6 @@ MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
 MODULE_AUTHOR("Levent Guendogdu, Tobias Gehrig, Matthias Koenig");
 MODULE_DESCRIPTION("Midiman Portman2x4");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Midiman,Portman2x4}}");
 
 /*********************************************************************
  * Chip specific
index 3947f08..6d5d1ca 100644 (file)
@@ -34,7 +34,6 @@
 
 MODULE_DESCRIPTION("MIDI serial u16550");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{ALSA, MIDI serial u16550}}");
 
 #define SNDRV_SERIAL_SOUNDCANVAS 0 /* Roland Soundcanvas; F5 NN selects part */
 #define SNDRV_SERIAL_MS124T 1      /* Midiator MS-124T */
index f1fb68b..4206d93 100644 (file)
@@ -43,7 +43,6 @@
 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
 MODULE_DESCRIPTION("Dummy soundcard for virtual rawmidi devices");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{ALSA,Virtual rawmidi device}}");
 
 #define MAX_MIDI_DEVICES       4
 
index 8e0c038..1a14c08 100644 (file)
@@ -493,11 +493,10 @@ void snd_dice_stream_stop_duplex(struct snd_dice *dice)
        struct reg_params tx_params, rx_params;
 
        if (dice->substreams_counter == 0) {
-               if (get_register_params(dice, &tx_params, &rx_params) >= 0) {
-                       amdtp_domain_stop(&dice->domain);
+               if (get_register_params(dice, &tx_params, &rx_params) >= 0)
                        finish_session(dice, &tx_params, &rx_params);
-               }
 
+               amdtp_domain_stop(&dice->domain);
                release_resources(dice);
        }
 }
index d053bec..e223723 100644 (file)
@@ -39,6 +39,11 @@ int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt)
        if (!nhlt)
                return 0;
 
+       if (nhlt->header.length <= sizeof(struct acpi_table_header)) {
+               dev_warn(dev, "Invalid DMIC description table\n");
+               return 0;
+       }
+
        for (j = 0, epnt = nhlt->desc; j < nhlt->endpoint_count; j++,
             epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length)) {
 
index ca18fe3..f11af98 100644 (file)
 MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
 MODULE_DESCRIPTION("AD1816A, AD1815");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Highscreen,Sound-Boostar 16 3D},"
-               "{Analog Devices,AD1815},"
-               "{Analog Devices,AD1816A},"
-               "{TerraTec,Base 64},"
-               "{TerraTec,AudioSystem EWS64S},"
-               "{Aztech/Newcom SC-16 3D},"
-               "{Shark Predator ISA}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 1-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
index 6f221ee..edafb49 100644 (file)
@@ -22,9 +22,6 @@
 MODULE_DESCRIPTION(CRD_NAME);
 MODULE_AUTHOR("Tugrul Galatali <galatalt@stuy.edu>, Jaroslav Kysela <perex@perex.cz>");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Analog Devices,AD1848},"
-               "{Analog Devices,AD1847},"
-               "{Crystal Semiconductors,CS4248}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
index 1085f5b..bacb7a1 100644 (file)
 #define PFX "als100: "
 
 MODULE_DESCRIPTION("Avance Logic ALS007/ALS1X0");
-MODULE_SUPPORTED_DEVICE("{{Diamond Technologies DT-019X},"
-               "{Avance Logic ALS-007}}"
-               "{{Avance Logic,ALS100 - PRO16PNP},"
-               "{Avance Logic,ALS110},"
-               "{Avance Logic,ALS120},"
-               "{Avance Logic,ALS200},"
-               "{3D Melody,MF1000},"
-               "{Digimate,3D Sound},"
-               "{Avance Logic,ALS120},"
-               "{RTL,RTL3000}}");
-
 MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
 MODULE_LICENSE("GPL");
 
index 4ed5209..867e9ae 100644 (file)
 MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
 MODULE_DESCRIPTION("Aztech Systems AZT2320");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Aztech Systems,PRO16V},"
-               "{Aztech Systems,AZT2320},"
-               "{Aztech Systems,AZT3300},"
-               "{Aztech Systems,AZT2320},"
-               "{Aztech Systems,AZT3000}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
index 19e2585..bc112df 100644 (file)
@@ -51,7 +51,6 @@
 MODULE_AUTHOR("George Talusan <gstalusan@uwaterloo.ca>");
 MODULE_DESCRIPTION("C-Media CMI8330/CMI8329");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8330,isapnp:{CMI0001,@@@0001,@X@0001}}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
index c56cbc0..ec054b9 100644 (file)
@@ -23,7 +23,6 @@
 MODULE_DESCRIPTION(CRD_NAME);
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Crystal Semiconductors,CS4231}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
index 63fb0cb..186d7d4 100644 (file)
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Cirrus Logic CS4232-9");
-MODULE_SUPPORTED_DEVICE("{{Turtle Beach,TBS-2000},"
-               "{Turtle Beach,Tropez Plus},"
-               "{SIC CrystalWave 32},"
-               "{Hewlett Packard,Omnibook 5500},"
-               "{TerraTec,Maestro 32/96},"
-               "{Philips,PCA70PS}},"
-               "{{Crystal Semiconductors,CS4235},"
-               "{Crystal Semiconductors,CS4236},"
-               "{Crystal Semiconductors,CS4237},"
-               "{Crystal Semiconductors,CS4238},"
-               "{Crystal Semiconductors,CS4239},"
-               "{Acer,AW37},"
-               "{Acer,AW35/Pro},"
-               "{Crystal,3D},"
-               "{Crystal Computer,TidalWave128},"
-               "{Dell,Optiplex GX1},"
-               "{Dell,Workstation 400 sound},"
-               "{EliteGroup,P5TX-LA sound},"
-               "{Gallant,SC-70P},"
-               "{Gateway,E1000 Onboard CS4236B},"
-               "{Genius,Sound Maker 3DJ},"
-               "{Hewlett Packard,HP6330 sound},"
-               "{IBM,PC 300PL sound},"
-               "{IBM,Aptiva 2137 E24},"
-               "{IBM,IntelliStation M Pro},"
-               "{Intel,Marlin Spike Mobo CS4235},"
-               "{Intel PR440FX Onboard},"
-               "{Guillemot,MaxiSound 16 PnP},"
-               "{NewClear,3D},"
-               "{TerraTec,AudioSystem EWS64L/XL},"
-               "{Typhoon Soundsystem,CS4236B},"
-               "{Turtle Beach,Malibu},"
-               "{Unknown,Digital PC 5000 Onboard}}");
-
 MODULE_ALIAS("snd_cs4232");
 
 #define IDENT "CS4232+"
index 4a1f61f..750d499 100644 (file)
 MODULE_DESCRIPTION(CRD_NAME);
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{ESS,ES688 PnP AudioDrive,pnp:ESS0100},"
-               "{ESS,ES1688 PnP AudioDrive,pnp:ESS0102},"
-               "{ESS,ES688 AudioDrive,pnp:ESS6881},"
-               "{ESS,ES1688 AudioDrive,pnp:ESS1681}}");
-
 MODULE_ALIAS("snd_es968");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
index 9beef80..375a4a6 100644 (file)
@@ -1929,17 +1929,9 @@ static int snd_es18xx_mixer(struct snd_card *card)
 
 /* Card level */
 
-MODULE_AUTHOR("Christian Fischbach <fishbach@pool.informatik.rwth-aachen.de>, Abramo Bagnara <abramo@alsa-project.org>");  
+MODULE_AUTHOR("Christian Fischbach <fishbach@pool.informatik.rwth-aachen.de>, Abramo Bagnara <abramo@alsa-project.org>");
 MODULE_DESCRIPTION("ESS ES18xx AudioDrive");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{ESS,ES1868 PnP AudioDrive},"
-               "{ESS,ES1869 PnP AudioDrive},"
-               "{ESS,ES1878 PnP AudioDrive},"
-               "{ESS,ES1879 PnP AudioDrive},"
-               "{ESS,ES1887 PnP AudioDrive},"
-               "{ESS,ES1888 PnP AudioDrive},"
-               "{ESS,ES1887 AudioDrive},"
-               "{ESS,ES1888 AudioDrive}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
index 015f88a..0fba5d8 100644 (file)
@@ -23,7 +23,6 @@
 MODULE_DESCRIPTION(CRD_NAME);
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Gravis,UltraSound Classic}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
index c9f31b4..da2b2ca 100644 (file)
@@ -27,7 +27,6 @@
 MODULE_DESCRIPTION(CRD_NAME);
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Gravis,UltraSound Extreme}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
index dc09fbd..24b945f 100644 (file)
@@ -21,7 +21,6 @@
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("Gravis UltraSound MAX");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Gravis,UltraSound MAX}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
index e4d412e..99581fb 100644 (file)
@@ -28,14 +28,8 @@ MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_LICENSE("GPL");
 #ifndef SNDRV_STB
 MODULE_DESCRIPTION("AMD InterWave");
-MODULE_SUPPORTED_DEVICE("{{Gravis,UltraSound Plug & Play},"
-               "{STB,SoundRage32},"
-               "{MED,MED3210},"
-               "{Dynasonix,Dynasonix Pro},"
-               "{Panasonic,PCA761AW}}");
 #else
 MODULE_DESCRIPTION("AMD InterWave STB with TEA6330T");
-MODULE_SUPPORTED_DEVICE("{{AMD,InterWave STB with TEA6330T}}");
 #endif
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
index 7649a8a..9bde11d 100644 (file)
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("Yamaha OPL3SA2+");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Yamaha,YMF719E-S},"
-               "{Genius,Sound Maker 3DX},"
-               "{Yamaha,OPL3SA3},"
-               "{Intel,AL440LX sound},"
-               "{NeoMagic,MagicWave 3DX}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
index 2093334..a510b20 100644 (file)
@@ -33,9 +33,6 @@
 MODULE_AUTHOR("Martin Langer <martin-langer@gmx.de>");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Miro miroSOUND PCM1 pro, PCM12, PCM20 Radio");
-MODULE_SUPPORTED_DEVICE("{{Miro,miroSOUND PCM1 pro}, "
-                       "{Miro,miroSOUND PCM12}, "
-                       "{Miro,miroSOUND PCM20 Radio}}");
 
 static int index = SNDRV_DEFAULT_IDX1;         /* Index 0-MAX */
 static char *id = SNDRV_DEFAULT_STR1;          /* ID for this card */
index 758f5b5..08e61d9 100644 (file)
@@ -36,17 +36,11 @@ MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
 MODULE_LICENSE("GPL");
 #ifdef OPTi93X
 MODULE_DESCRIPTION("OPTi93X");
-MODULE_SUPPORTED_DEVICE("{{OPTi,82C931/3}}");
 #else  /* OPTi93X */
 #ifdef CS4231
 MODULE_DESCRIPTION("OPTi92X - CS4231");
-MODULE_SUPPORTED_DEVICE("{{OPTi,82C924 (CS4231)},"
-               "{OPTi,82C925 (CS4231)}}");
 #else  /* CS4231 */
 MODULE_DESCRIPTION("OPTi92X - AD1848");
-MODULE_SUPPORTED_DEVICE("{{OPTi,82C924 (AD1848)},"
-               "{OPTi,82C925 (AD1848)},"
-               "{OAK,Mozart}}");
 #endif /* CS4231 */
 #endif /* OPTi93X */
 
index 0e2e0ab..7ba5dd1 100644 (file)
@@ -28,9 +28,6 @@
 #define PFX "jazz16: "
 
 MODULE_DESCRIPTION("Media Vision Jazz16");
-MODULE_SUPPORTED_DEVICE("{{Media Vision ??? },"
-               "{RTL,RTL3000}}");
-
 MODULE_AUTHOR("Krzysztof Helt <krzysztof.h1@wp.pl>");
 MODULE_LICENSE("GPL");
 
index db284b7..63ef960 100644 (file)
@@ -31,16 +31,8 @@ MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_LICENSE("GPL");
 #ifndef SNDRV_SBAWE
 MODULE_DESCRIPTION("Sound Blaster 16");
-MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB 16},"
-               "{Creative Labs,SB Vibra16S},"
-               "{Creative Labs,SB Vibra16C},"
-               "{Creative Labs,SB Vibra16CL},"
-               "{Creative Labs,SB Vibra16X}}");
 #else
 MODULE_DESCRIPTION("Sound Blaster AWE");
-MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB AWE 32},"
-               "{Creative Labs,SB AWE 64},"
-               "{Creative Labs,SB AWE 64 Gold}}");
 #endif
 
 #if 0
index 8e3e67b..6c9d534 100644 (file)
@@ -17,7 +17,6 @@
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("Sound Blaster 1.0/2.0/Pro");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB 1.0/SB 2.0/SB Pro}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
index def1375..3462663 100644 (file)
@@ -29,9 +29,6 @@
 MODULE_AUTHOR("Krzysztof Helt");
 MODULE_DESCRIPTION("Gallant SC-6000");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Gallant, SC-6000},"
-                       "{AudioExcel, Audio Excel DSP 16},"
-                       "{Zoltrix, AV302}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
index b750a4f..a443797 100644 (file)
@@ -21,7 +21,6 @@
 MODULE_AUTHOR("Paul Barton-Davis <pbd@op.net>");
 MODULE_DESCRIPTION("Turtle Beach Wavefront");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Turtle Beach,Maui/Tropez/Tropez+}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;         /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;          /* ID for this card */
index 5bf1ea1..989f656 100644 (file)
@@ -32,7 +32,6 @@
 MODULE_AUTHOR("Vivien Chappelier <vivien.chappelier@linux-mips.org>");
 MODULE_DESCRIPTION("SGI O2 Audio");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Silicon Graphics, O2 Audio}}");
 
 static int index = SNDRV_DEFAULT_IDX1;  /* Index 0-MAX */
 static char *id = SNDRV_DEFAULT_STR1;   /* ID for this card */
index 5d835d2..4520022 100644 (file)
@@ -43,7 +43,6 @@
 MODULE_AUTHOR("Kyle McMartin <kyle@parisc-linux.org>, Thibaut Varene <t-bone@parisc-linux.org>");
 MODULE_DESCRIPTION("Analog Devices AD1889 ALSA sound driver");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Analog Devices,AD1889}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
 module_param_array(index, int, NULL, 0444);
index 51f2479..0d66b92 100644 (file)
@@ -29,7 +29,6 @@
 MODULE_AUTHOR("Matt Wu <Matt_Wu@acersoftech.com.cn>");
 MODULE_DESCRIPTION("ALI M5451");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{ALI,M5451,pci},{ALI,M5451}}");
 
 static int index = SNDRV_DEFAULT_IDX1; /* Index */
 static char *id = SNDRV_DEFAULT_STR1;  /* ID for this card */
index 1dc8c4e..bd4fd09 100644 (file)
@@ -86,7 +86,6 @@ enum {DEVICE_ALS300, DEVICE_ALS300_PLUS};
 MODULE_AUTHOR("Ash Willis <ashwillis@programmer.net>");
 MODULE_DESCRIPTION("Avance Logic ALS300");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Avance Logic,ALS300},{Avance Logic,ALS300+}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
index 2edc745..139ac2a 100644 (file)
@@ -68,7 +68,6 @@
 MODULE_AUTHOR("Bart Hartgers <bart@etpmod.phys.tue.nl>, Andreas Mohr");
 MODULE_DESCRIPTION("Avance Logic ALS4000");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Avance Logic,ALS4000}}");
 
 #if IS_REACHABLE(CONFIG_GAMEPORT)
 #define SUPPORT_JOYSTICK 1
index a25d754..579425c 100644 (file)
@@ -23,7 +23,6 @@
 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
 MODULE_DESCRIPTION("ATI IXP AC97 controller");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{ATI,IXP150/200/250/300/400/600}}");
 
 static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
 static char *id = SNDRV_DEFAULT_STR1;  /* ID for this card */
index ae88217..45e75af 100644 (file)
@@ -23,7 +23,6 @@
 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
 MODULE_DESCRIPTION("ATI IXP MC97 controller");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{ATI,IXP150/200/250}}");
 
 static int index = -2; /* Exclude the first card */
 static char *id = SNDRV_DEFAULT_STR1;  /* ID for this card */
index 5dd98e6..1b37b72 100644 (file)
@@ -41,8 +41,6 @@ MODULE_PARM_DESC(pcifix, "Enable VIA-workaround for " CARD_NAME " soundcard.");
 
 MODULE_DESCRIPTION("Aureal vortex");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Aureal Semiconductor Inc., Aureal Vortex Sound Processor}}");
-
 MODULE_DEVICE_TABLE(pci, snd_vortex_ids);
 
 static void vortex_fix_latency(struct pci_dev *vortex)
index 2ac594d..51dcf1b 100644 (file)
 MODULE_AUTHOR("Andreas Mohr <andi AT lisas.de>");
 MODULE_DESCRIPTION("Aztech AZF3328 (PCI168)");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}");
 
 #if IS_REACHABLE(CONFIG_GAMEPORT)
 #define SUPPORT_GAMEPORT 1
index cf9f8d8..91512b3 100644 (file)
@@ -23,8 +23,6 @@
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
 MODULE_DESCRIPTION("Brooktree Bt87x audio driver");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Brooktree,Bt878},"
-               "{Brooktree,Bt879}}");
 
 static int index[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -2}; /* Exclude the first card */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
index ee20f9a..bee4710 100644 (file)
 MODULE_AUTHOR("James Courtier-Dutton <James@superbug.demon.co.uk>");
 MODULE_DESCRIPTION("CA0106");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Creative,SB CA0106 chip}}");
 
 // module parameters (see "Module Parameters")
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
index 7363d61..5984463 100644 (file)
 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
 MODULE_DESCRIPTION("C-Media CMI8x38 PCI");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8738},"
-               "{C-Media,CMI8738B},"
-               "{C-Media,CMI8338A},"
-               "{C-Media,CMI8338B}}");
 
 #if IS_REACHABLE(CONFIG_GAMEPORT)
 #define SUPPORT_JOYSTICK 1
index 94d2a6a..bf3bb70 100644 (file)
@@ -25,7 +25,6 @@
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("Cirrus Logic CS4281");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Cirrus Logic,CS4281}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
index a6e0a44..1db7b41 100644 (file)
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("Cirrus Logic Sound Fusion CS46XX");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Cirrus Logic,Sound Fusion (CS4280)},"
-               "{Cirrus Logic,Sound Fusion (CS4610)},"
-               "{Cirrus Logic,Sound Fusion (CS4612)},"
-               "{Cirrus Logic,Sound Fusion (CS4615)},"
-               "{Cirrus Logic,Sound Fusion (CS4622)},"
-               "{Cirrus Logic,Sound Fusion (CS4624)},"
-               "{Cirrus Logic,Sound Fusion (CS4630)}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
index 359bc6a..9b716b5 100644 (file)
@@ -393,4 +393,3 @@ module_pci_driver(cs5535audio_driver);
 MODULE_AUTHOR("Jaya Kumar");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("CS5535 Audio");
-MODULE_SUPPORTED_DEVICE("CS5535 Audio");
index 8c07c64..713d36e 100644 (file)
@@ -18,7 +18,6 @@
 MODULE_AUTHOR("Creative Technology Ltd");
 MODULE_DESCRIPTION("X-Fi driver version 1.03");
 MODULE_LICENSE("GPL v2");
-MODULE_SUPPORTED_DEVICE("{{Creative Labs, Sound Blaster X-Fi}");
 
 static unsigned int reference_rate = 48000;
 static unsigned int multiple = 2;
index a20b2bb..9bd67ac 100644 (file)
@@ -10,7 +10,6 @@
 MODULE_AUTHOR("Giuliano Pochini <pochini@shiny.it>");
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Echoaudio " ECHOCARD_NAME " soundcards driver");
-MODULE_SUPPORTED_DEVICE("{{Echoaudio," ECHOCARD_NAME "}}");
 MODULE_DEVICE_TABLE(pci, snd_echo_ids);
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
index 353934c..45833bc 100644 (file)
@@ -18,8 +18,6 @@
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("EMU10K1");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB Live!/PCI512/E-mu APS},"
-              "{Creative Labs,SB Audigy}}");
 
 #if IS_ENABLED(CONFIG_SND_SEQUENCER)
 #define ENABLE_SYNTH
index 785ec0c..d9a12cd 100644 (file)
@@ -31,7 +31,6 @@
 MODULE_AUTHOR("Francisco Moraes <fmoraes@nc.rr.com>");
 MODULE_DESCRIPTION("EMU10K1X");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Dell Creative Labs,SB Live!}");
 
 // module parameters (see "Module Parameters")
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
index 93c4fd3..3ccccdb 100644 (file)
@@ -52,17 +52,9 @@ MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Thomas Sailer <sailer@ife.ee.et
 MODULE_LICENSE("GPL");
 #ifdef CHIP1370
 MODULE_DESCRIPTION("Ensoniq AudioPCI ES1370");
-MODULE_SUPPORTED_DEVICE("{{Ensoniq,AudioPCI-97 ES1370},"
-               "{Creative Labs,SB PCI64/128 (ES1370)}}");
 #endif
 #ifdef CHIP1371
 MODULE_DESCRIPTION("Ensoniq/Creative AudioPCI ES1371+");
-MODULE_SUPPORTED_DEVICE("{{Ensoniq,AudioPCI ES1371/73},"
-               "{Ensoniq,AudioPCI ES1373},"
-               "{Creative Labs,Ectiva EV1938},"
-               "{Creative Labs,SB PCI64/128 (ES1371/73)},"
-               "{Creative Labs,Vibra PCI128},"
-               "{Ectiva,EV1938}}");
 #endif
 
 #if IS_REACHABLE(CONFIG_GAMEPORT)
index 3b5d68c..afc6634 100644 (file)
 MODULE_AUTHOR("Jaromir Koutek <miri@punknet.cz>");
 MODULE_DESCRIPTION("ESS Solo-1");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{ESS,ES1938},"
-                "{ESS,ES1946},"
-                "{ESS,ES1969},"
-               "{TerraTec,128i PCI}}");
 
 #if IS_REACHABLE(CONFIG_GAMEPORT)
 #define SUPPORT_JOYSTICK 1
index 747fa69..5fa1861 100644 (file)
 
 MODULE_DESCRIPTION("ESS Maestro");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{ESS,Maestro 2e},"
-               "{ESS,Maestro 2},"
-               "{ESS,Maestro 1},"
-               "{TerraTec,DMX}}");
 
 #if IS_REACHABLE(CONFIG_GAMEPORT)
 #define SUPPORT_JOYSTICK 1
index c6ad623..6279eb1 100644 (file)
@@ -26,8 +26,6 @@
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("ForteMedia FM801");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{ForteMedia,FM801},"
-               "{Genius,SoundMaker Live 5.1}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
index 6a85645..17a25e4 100644 (file)
@@ -47,6 +47,10 @@ static void hda_codec_unsol_event(struct hdac_device *dev, unsigned int ev)
        if (codec->bus->shutdown)
                return;
 
+       /* ignore unsol events during system suspend/resume */
+       if (codec->core.dev.power.power_state.event != PM_EVENT_ON)
+               return;
+
        if (codec->patch_ops.unsol_event)
                codec->patch_ops.unsol_event(codec, ev);
 }
index 9087981..ca2f2ec 100644 (file)
@@ -609,13 +609,6 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
                                     20,
                                     178000000);
 
-       /* by some reason, the playback stream stalls on PulseAudio with
-        * tsched=1 when a capture stream triggers.  Until we figure out the
-        * real cause, disable tsched mode by telling the PCM info flag.
-        */
-       if (chip->driver_caps & AZX_DCAPS_AMD_WORKAROUND)
-               runtime->hw.info |= SNDRV_PCM_INFO_BATCH;
-
        if (chip->align_buffer_size)
                /* constrain buffer sizes to be multiple of 128
                   bytes. This is more efficient in terms of memory
index 8b7c550..f5cba7a 100644 (file)
@@ -4065,7 +4065,7 @@ static int add_micmute_led_hook(struct hda_codec *codec)
 
        spec->micmute_led.led_mode = MICMUTE_LED_FOLLOW_MUTE;
        spec->micmute_led.capture = 0;
-       spec->micmute_led.led_value = 0;
+       spec->micmute_led.led_value = -1;
        spec->micmute_led.old_hook = spec->cap_sync_hook;
        spec->cap_sync_hook = update_micmute_led;
        if (!snd_hda_gen_add_kctl(spec, NULL, &micmute_led_mode_ctl))
index 5b492c3..b59b0f3 100644 (file)
@@ -208,40 +208,6 @@ MODULE_PARM_DESC(snoop, "Enable/disable snooping");
 
 
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
-                        "{Intel, ICH6M},"
-                        "{Intel, ICH7},"
-                        "{Intel, ESB2},"
-                        "{Intel, ICH8},"
-                        "{Intel, ICH9},"
-                        "{Intel, ICH10},"
-                        "{Intel, PCH},"
-                        "{Intel, CPT},"
-                        "{Intel, PPT},"
-                        "{Intel, LPT},"
-                        "{Intel, LPT_LP},"
-                        "{Intel, WPT_LP},"
-                        "{Intel, SPT},"
-                        "{Intel, SPT_LP},"
-                        "{Intel, HPT},"
-                        "{Intel, PBG},"
-                        "{Intel, SCH},"
-                        "{ATI, SB450},"
-                        "{ATI, SB600},"
-                        "{ATI, RS600},"
-                        "{ATI, RS690},"
-                        "{ATI, RS780},"
-                        "{ATI, R600},"
-                        "{ATI, RV630},"
-                        "{ATI, RV610},"
-                        "{ATI, RV670},"
-                        "{ATI, RV635},"
-                        "{ATI, RV620},"
-                        "{ATI, RV770},"
-                        "{VIA, VT8251},"
-                        "{VIA, VT8237A},"
-                        "{SiS, SIS966},"
-                        "{ULI, M5461}}");
 MODULE_DESCRIPTION("Intel HDA driver");
 
 #if defined(CONFIG_PM) && defined(CONFIG_VGA_SWITCHEROO)
@@ -1026,6 +992,8 @@ static int azx_prepare(struct device *dev)
        chip = card->private_data;
        chip->pm_prepared = 1;
 
+       flush_work(&azx_bus(chip)->unsol_work);
+
        /* HDA controller always requires different WAKEEN for runtime suspend
         * and system suspend, so don't use direct-complete here.
         */
index c966f49..b2b620f 100644 (file)
@@ -1309,6 +1309,7 @@ static const struct snd_pci_quirk ca0132_quirks[] = {
        SND_PCI_QUIRK(0x1102, 0x0013, "Recon3D", QUIRK_R3D),
        SND_PCI_QUIRK(0x1102, 0x0018, "Recon3D", QUIRK_R3D),
        SND_PCI_QUIRK(0x1102, 0x0051, "Sound Blaster AE-5", QUIRK_AE5),
+       SND_PCI_QUIRK(0x1102, 0x0191, "Sound Blaster AE-5 Plus", QUIRK_AE5),
        SND_PCI_QUIRK(0x1102, 0x0081, "Sound Blaster AE-7", QUIRK_AE7),
        {}
 };
index f2aa226..c20dad4 100644 (file)
@@ -149,6 +149,21 @@ static int cx_auto_vmaster_mute_led(struct led_classdev *led_cdev,
        return 0;
 }
 
+static void cxt_init_gpio_led(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       unsigned int mask = spec->gpio_mute_led_mask | spec->gpio_mic_led_mask;
+
+       if (mask) {
+               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
+                                   mask);
+               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION,
+                                   mask);
+               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+                                   spec->gpio_led);
+       }
+}
+
 static int cx_auto_init(struct hda_codec *codec)
 {
        struct conexant_spec *spec = codec->spec;
@@ -156,6 +171,7 @@ static int cx_auto_init(struct hda_codec *codec)
        if (!spec->dynamic_eapd)
                cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true);
 
+       cxt_init_gpio_led(codec);
        snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
 
        return 0;
@@ -215,6 +231,7 @@ enum {
        CXT_FIXUP_HP_SPECTRE,
        CXT_FIXUP_HP_GATE_MIC,
        CXT_FIXUP_MUTE_LED_GPIO,
+       CXT_FIXUP_HP_ZBOOK_MUTE_LED,
        CXT_FIXUP_HEADSET_MIC,
        CXT_FIXUP_HP_MIC_NO_PRESENCE,
 };
@@ -654,31 +671,36 @@ static int cxt_gpio_micmute_update(struct led_classdev *led_cdev,
        return 0;
 }
 
-
-static void cxt_fixup_mute_led_gpio(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
+static void cxt_setup_mute_led(struct hda_codec *codec,
+                              unsigned int mute, unsigned int mic_mute)
 {
        struct conexant_spec *spec = codec->spec;
-       static const struct hda_verb gpio_init[] = {
-               { 0x01, AC_VERB_SET_GPIO_MASK, 0x03 },
-               { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03 },
-               {}
-       };
 
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+       spec->gpio_led = 0;
+       spec->mute_led_polarity = 0;
+       if (mute) {
                snd_hda_gen_add_mute_led_cdev(codec, cxt_gpio_mute_update);
-               spec->gpio_led = 0;
-               spec->mute_led_polarity = 0;
-               spec->gpio_mute_led_mask = 0x01;
-               spec->gpio_mic_led_mask = 0x02;
+               spec->gpio_mute_led_mask = mute;
+       }
+       if (mic_mute) {
                snd_hda_gen_add_micmute_led_cdev(codec, cxt_gpio_micmute_update);
+               spec->gpio_mic_led_mask = mic_mute;
        }
-       snd_hda_add_verbs(codec, gpio_init);
-       if (spec->gpio_led)
-               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
-                                   spec->gpio_led);
 }
 
+static void cxt_fixup_mute_led_gpio(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               cxt_setup_mute_led(codec, 0x01, 0x02);
+}
+
+static void cxt_fixup_hp_zbook_mute_led(struct hda_codec *codec,
+                                       const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               cxt_setup_mute_led(codec, 0x10, 0x20);
+}
 
 /* ThinkPad X200 & co with cxt5051 */
 static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = {
@@ -839,6 +861,10 @@ static const struct hda_fixup cxt_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = cxt_fixup_mute_led_gpio,
        },
+       [CXT_FIXUP_HP_ZBOOK_MUTE_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cxt_fixup_hp_zbook_mute_led,
+       },
        [CXT_FIXUP_HEADSET_MIC] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = cxt_fixup_headset_mic,
@@ -917,6 +943,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
        SND_PCI_QUIRK(0x103c, 0x8299, "HP 800 G3 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x8402, "HP ProBook 645 G4", CXT_FIXUP_MUTE_LED_GPIO),
+       SND_PCI_QUIRK(0x103c, 0x8427, "HP ZBook Studio G5", CXT_FIXUP_HP_ZBOOK_MUTE_LED),
        SND_PCI_QUIRK(0x103c, 0x8455, "HP Z2 G4", CXT_FIXUP_HP_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x8456, "HP Z2 G4 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x8457, "HP Z2 G4 mini", CXT_FIXUP_HP_MIC_NO_PRESENCE),
@@ -956,6 +983,7 @@ static const struct hda_model_fixup cxt5066_fixup_models[] = {
        { .id = CXT_FIXUP_MUTE_LED_EAPD, .name = "mute-led-eapd" },
        { .id = CXT_FIXUP_HP_DOCK, .name = "hp-dock" },
        { .id = CXT_FIXUP_MUTE_LED_GPIO, .name = "mute-led-gpio" },
+       { .id = CXT_FIXUP_HP_ZBOOK_MUTE_LED, .name = "hp-zbook-mute-led" },
        { .id = CXT_FIXUP_HP_MIC_NO_PRESENCE, .name = "hp-mic-fix" },
        {}
 };
index e6d0843..45ae845 100644 (file)
@@ -2480,6 +2480,18 @@ static void generic_hdmi_free(struct hda_codec *codec)
 }
 
 #ifdef CONFIG_PM
+static int generic_hdmi_suspend(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int pin_idx;
+
+       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+               struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+               cancel_delayed_work_sync(&per_pin->work);
+       }
+       return 0;
+}
+
 static int generic_hdmi_resume(struct hda_codec *codec)
 {
        struct hdmi_spec *spec = codec->spec;
@@ -2503,6 +2515,7 @@ static const struct hda_codec_ops generic_hdmi_patch_ops = {
        .build_controls         = generic_hdmi_build_controls,
        .unsol_event            = hdmi_unsol_event,
 #ifdef CONFIG_PM
+       .suspend                = generic_hdmi_suspend,
        .resume                 = generic_hdmi_resume,
 #endif
 };
index b47504f..316b9b4 100644 (file)
@@ -4225,6 +4225,12 @@ static void alc_fixup_hp_gpio_led(struct hda_codec *codec,
        }
 }
 
+static void alc236_fixup_hp_gpio_led(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       alc_fixup_hp_gpio_led(codec, action, 0x02, 0x01);
+}
+
 static void alc269_fixup_hp_gpio_led(struct hda_codec *codec,
                                const struct hda_fixup *fix, int action)
 {
@@ -6381,6 +6387,7 @@ enum {
        ALC294_FIXUP_ASUS_GX502_VERBS,
        ALC285_FIXUP_HP_GPIO_LED,
        ALC285_FIXUP_HP_MUTE_LED,
+       ALC236_FIXUP_HP_GPIO_LED,
        ALC236_FIXUP_HP_MUTE_LED,
        ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET,
        ALC295_FIXUP_ASUS_MIC_NO_PRESENCE,
@@ -7616,6 +7623,10 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc285_fixup_hp_mute_led,
        },
+       [ALC236_FIXUP_HP_GPIO_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc236_fixup_hp_gpio_led,
+       },
        [ALC236_FIXUP_HP_MUTE_LED] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc236_fixup_hp_mute_led,
@@ -8045,9 +8056,12 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x8783, "HP ZBook Fury 15 G7 Mobile Workstation",
                      ALC285_FIXUP_HP_GPIO_AMP_INIT),
        SND_PCI_QUIRK(0x103c, 0x87c8, "HP", ALC287_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x87e5, "HP ProBook 440 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x87f4, "HP", ALC287_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x87f5, "HP", ALC287_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x87f7, "HP Spectre x360 14", ALC245_FIXUP_HP_X360_AMP),
+       SND_PCI_QUIRK(0x103c, 0x8846, "HP EliteBook 850 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x884c, "HP EliteBook 840 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
        SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
        SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -8242,7 +8256,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1b35, 0x1237, "CZC L101", ALC269_FIXUP_CZC_L101),
        SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */
        SND_PCI_QUIRK(0x1d72, 0x1602, "RedmiBook", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1d72, 0x1701, "XiaomiNotebook Pro", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1d72, 0x1901, "RedmiBook 14", ALC256_FIXUP_ASUS_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1d72, 0x1947, "RedmiBook Air", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
        SND_PCI_QUIRK(0x10ec, 0x118c, "Medion EE4254 MD62100", ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE),
        SND_PCI_QUIRK(0x1c06, 0x2013, "Lemote A1802", ALC269_FIXUP_LEMOTE_A1802),
        SND_PCI_QUIRK(0x1c06, 0x2015, "Lemote A190X", ALC269_FIXUP_LEMOTE_A190X),
index f814dbb..d54cd51 100644 (file)
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("ICEnsemble ICE1712 (Envy24)");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{"
-              HOONTECH_DEVICE_DESC
-              DELTA_DEVICE_DESC
-              EWS_DEVICE_DESC
-              "{ICEnsemble,Generic ICE1712},"
-              "{ICEnsemble,Generic Envy24}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
index c0fca94..ef2367d 100644 (file)
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("VIA ICEnsemble ICE1724/1720 (Envy24HT/PT)");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{"
-              REVO_DEVICE_DESC
-              AMP_AUDIO2000_DEVICE_DESC
-              AUREON_DEVICE_DESC
-              VT1720_MOBO_DEVICE_DESC
-              PONTIS_DEVICE_DESC
-              PRODIGY192_DEVICE_DESC
-              PRODIGY_HIFI_DEVICE_DESC
-              JULI_DEVICE_DESC
-              MAYA44_DEVICE_DESC
-              PHASE_DEVICE_DESC
-              WTM_DEVICE_DESC
-              SE_DEVICE_DESC
-              QTET_DEVICE_DESC
-               "{VIA,VT1720},"
-               "{VIA,VT1724},"
-               "{ICEnsemble,Generic ICE1724},"
-               "{ICEnsemble,Generic Envy24HT}"
-               "{ICEnsemble,Generic Envy24PT}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
index 3349e45..35903d1 100644 (file)
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("Intel 82801AA,82901AB,i810,i820,i830,i840,i845,MX440; SiS 7012; Ali 5455");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Intel,82801AA-ICH},"
-               "{Intel,82901AB-ICH0},"
-               "{Intel,82801BA-ICH2},"
-               "{Intel,82801CA-ICH3},"
-               "{Intel,82801DB-ICH4},"
-               "{Intel,ICH5},"
-               "{Intel,ICH6},"
-               "{Intel,ICH7},"
-               "{Intel,6300ESB},"
-               "{Intel,ESB2},"
-               "{Intel,MX440},"
-               "{SiS,SI7012},"
-               "{NVidia,nForce Audio},"
-               "{NVidia,nForce2 Audio},"
-               "{NVidia,nForce3 Audio},"
-               "{NVidia,MCP04},"
-               "{NVidia,MCP501},"
-               "{NVidia,CK804},"
-               "{NVidia,CK8},"
-               "{NVidia,CK8S},"
-               "{AMD,AMD768},"
-               "{AMD,AMD8111},"
-               "{ALI,M5455}}");
 
 static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
 static char *id = SNDRV_DEFAULT_STR1;  /* ID for this card */
index 19872ce..13ef838 100644 (file)
@@ -25,21 +25,6 @@ MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("Intel 82801AA,82901AB,i810,i820,i830,i840,i845,MX440; "
                   "SiS 7013; NVidia MCP/2/2S/3 modems");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Intel,82801AA-ICH},"
-               "{Intel,82901AB-ICH0},"
-               "{Intel,82801BA-ICH2},"
-               "{Intel,82801CA-ICH3},"
-               "{Intel,82801DB-ICH4},"
-               "{Intel,ICH5},"
-               "{Intel,ICH6},"
-               "{Intel,ICH7},"
-               "{Intel,MX440},"
-               "{SiS,7013},"
-               "{NVidia,NForce Modem},"
-               "{NVidia,NForce2 Modem},"
-               "{NVidia,NForce2s Modem},"
-               "{NVidia,NForce3 Modem},"
-               "{AMD,AMD768}}");
 
 static int index = -2; /* Exclude the first card */
 static char *id = SNDRV_DEFAULT_STR1;  /* ID for this card */
index 2eddd9d..80ac3c6 100644 (file)
@@ -388,7 +388,6 @@ struct snd_korg1212 {
 
 MODULE_DESCRIPTION("korg1212");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{KORG,korg1212}}");
 MODULE_FIRMWARE("korg/k1212.dsp");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
index 491c90f..03b4be4 100644 (file)
@@ -54,7 +54,6 @@ MODULE_PARM_DESC(sample_rate_min, "Minimal sample rate");
  */
 
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Digigram, Lola}}");
 MODULE_DESCRIPTION("Digigram Lola driver");
 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
 
index b92ea07..1be97c3 100644 (file)
@@ -21,8 +21,6 @@
 MODULE_AUTHOR("Tim Blechmann");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("digigram lx6464es");
-MODULE_SUPPORTED_DEVICE("{digigram lx6464es{}}");
-
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
index d2c2cd6..cdc4b61 100644 (file)
 MODULE_AUTHOR("Zach Brown <zab@zabbo.net>, Takashi Iwai <tiwai@suse.de>");
 MODULE_DESCRIPTION("ESS Maestro3 PCI");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{ESS,Maestro3 PCI},"
-               "{ESS,ES1988},"
-               "{ESS,Allegro PCI},"
-               "{ESS,Allegro-1 PCI},"
-               "{ESS,Canyon3D-2/LE PCI}}");
 MODULE_FIRMWARE("ess/maestro3_assp_kernel.fw");
 MODULE_FIRMWARE("ess/maestro3_assp_minisrc.fw");
 
index efff220..a0bbb38 100644 (file)
@@ -32,7 +32,6 @@
 MODULE_AUTHOR("Digigram <alsa@digigram.com>");
 MODULE_DESCRIPTION("Digigram " CARD_NAME);
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Digigram," CARD_NAME "}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;             /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;              /* ID for this card */
index 9759946..6cb689a 100644 (file)
@@ -32,8 +32,6 @@
 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
 MODULE_DESCRIPTION("NeoMagic NM256AV/ZX");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{NeoMagic,NM256AV},"
-               "{NeoMagic,NM256ZX}}");
 
 /*
  * some compile conditions.
index a751fcc..e335c4b 100644 (file)
@@ -56,9 +56,6 @@
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
 MODULE_DESCRIPTION("C-Media CMI8788 driver");
 MODULE_LICENSE("GPL v2");
-MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8786}"
-                       ",{C-Media,CMI8787}"
-                       ",{C-Media,CMI8788}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
index 78c35a0..434f885 100644 (file)
@@ -29,7 +29,6 @@
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
 MODULE_DESCRIPTION("Studio Evolution SE6X driver");
 MODULE_LICENSE("GPL v2");
-MODULE_SUPPORTED_DEVICE("{{Studio Evolution,SE6X}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
index 98ab163..baa3244 100644 (file)
@@ -16,7 +16,6 @@
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
 MODULE_DESCRIPTION("Asus Virtuoso driver");
 MODULE_LICENSE("GPL v2");
-MODULE_SUPPORTED_DEVICE("{{Asus,AV66},{Asus,AV100},{Asus,AV200}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
index c2e4831..751f974 100644 (file)
@@ -35,7 +35,6 @@ MODULE_AUTHOR("Markus Bollinger <bollinger@digigram.com>, "
              "Marc Titinger <titinger@digigram.com>");
 MODULE_DESCRIPTION("Digigram " DRIVER_NAME " " PCXHR_DRIVER_VERSION_STRING);
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Digigram," DRIVER_NAME "}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
index fcc2073..56827db 100644 (file)
 MODULE_AUTHOR("Peter Gruber <nokos@gmx.net>");
 MODULE_DESCRIPTION("riptide");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Conexant,Riptide}}");
 MODULE_FIRMWARE("riptide.hex");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
index 4eabece..54f3e39 100644 (file)
@@ -88,7 +88,6 @@ MODULE_PARM_DESC(fullduplex, "Support full-duplex mode.");
 MODULE_AUTHOR("Martin Langer <martin-langer@gmx.de>, Pilo Chambert <pilo.c@wanadoo.fr>");
 MODULE_DESCRIPTION("RME Digi32, Digi32/8, Digi32 PRO");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{RME,Digi32}," "{RME,Digi32/8}," "{RME,Digi32 PRO}}");
 
 /* Defines for RME Digi32 series */
 #define RME32_SPDIF_NCHANNELS 2
index 84eef6a..66082e9 100644 (file)
@@ -31,11 +31,6 @@ MODULE_AUTHOR("Anders Torger <torger@ludd.luth.se>");
 MODULE_DESCRIPTION("RME Digi96, Digi96/8, Digi96/8 PRO, Digi96/8 PST, "
                   "Digi96/8 PAD");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{RME,Digi96},"
-               "{RME,Digi96/8},"
-               "{RME,Digi96/8 PRO},"
-               "{RME,Digi96/8 PST},"
-               "{RME,Digi96/8 PAD}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
index 6d90293..4cf879c 100644 (file)
@@ -44,9 +44,6 @@ MODULE_PARM_DESC(enable, "Enable/disable specific Hammerfall DSP soundcards.");
 MODULE_AUTHOR("Paul Davis <paul@linuxaudiosystems.com>, Marcus Andersson, Thomas Charbonnel <thomas@undata.org>");
 MODULE_DESCRIPTION("RME Hammerfall DSP");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{RME Hammerfall-DSP},"
-               "{RME HDSP-9652},"
-               "{RME HDSP-9632}}");
 MODULE_FIRMWARE("rpm_firmware.bin");
 MODULE_FIRMWARE("multiface_firmware.bin");
 MODULE_FIRMWARE("multiface_firmware_rev11.bin");
index b667115..8d900c1 100644 (file)
@@ -165,7 +165,6 @@ MODULE_AUTHOR
 );
 MODULE_DESCRIPTION("RME HDSPM");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
 
 /* --- Write registers. ---
   These are defined as byte-offsets from the iobase value.  */
index 012fbec..4df992e 100644 (file)
@@ -39,8 +39,6 @@ MODULE_PARM_DESC(precise_ptr, "Enable precise pointer (doesn't work reliably).")
 MODULE_AUTHOR("Paul Davis <pbd@op.net>, Winfried Ritsch");
 MODULE_DESCRIPTION("RME Digi9652/Digi9636");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{RME,Hammerfall},"
-               "{RME,Hammerfall-Light}}");
 
 /* The Hammerfall has two sets of 24 ADAT + 2 S/PDIF channels, one for
    capture, one for playback. Both the ADAT and S/PDIF channels appear
index 8ffa2f5..00ab51c 100644 (file)
@@ -24,7 +24,6 @@
 MODULE_AUTHOR("David Dillow <dave@thedillows.org>");
 MODULE_DESCRIPTION("SiS7019");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{SiS,SiS7019 Audio Accelerator}}");
 
 static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
 static char *id = SNDRV_DEFAULT_STR1;  /* ID for this card */
index 26fd1d0..7de1099 100644 (file)
@@ -29,7 +29,6 @@
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("S3 SonicVibes PCI");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{S3,SonicVibes PCI}}");
 
 #if IS_REACHABLE(CONFIG_GAMEPORT)
 #define SUPPORT_JOYSTICK 1
index 5bc79da..a510412 100644 (file)
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, <audio@tridentmicro.com>");
 MODULE_DESCRIPTION("Trident 4D-WaveDX/NX & SiS SI7018");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Trident,4DWave DX},"
-               "{Trident,4DWave NX},"
-               "{SiS,SI7018 PCI Audio},"
-               "{Best Union,Miss Melody 4DWave PCI},"
-               "{HIS,4DWave PCI},"
-               "{Warpspeed,ONSpeed 4DWave PCI},"
-               "{Aztech Systems,PCI 64-Q3D},"
-               "{Addonics,SV 750},"
-               "{CHIC,True Sound 4Dwave},"
-               "{Shark,Predator4D-PCI},"
-               "{Jaton,SonicWave 4D},"
-               "{Hoontech,SoundTrack Digital 4DWave NX}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
index 154d88c..fd1f2f9 100644 (file)
@@ -56,7 +56,6 @@
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("VIA VT82xx audio");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{VIA,VT82C686A/B/C,pci},{VIA,VT8233A/C,8235}}");
 
 #if IS_REACHABLE(CONFIG_GAMEPORT)
 #define SUPPORT_JOYSTICK 1
index addfa19..3025330 100644 (file)
@@ -38,7 +38,6 @@
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("VIA VT82xx modem");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{VIA,VT82C686A/B/C modem,pci}}");
 
 static int index = -2; /* Exclude the first card */
 static char *id = SNDRV_DEFAULT_STR1;  /* ID for this card */
index f7800ed..2a9e1a7 100644 (file)
@@ -20,7 +20,6 @@
 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
 MODULE_DESCRIPTION("Digigram VX222 V2/Mic");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Digigram," CARD_NAME "}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
index 9b0d18a..99be149 100644 (file)
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("Yamaha DS-1 PCI");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Yamaha,YMF724},"
-               "{Yamaha,YMF724F},"
-               "{Yamaha,YMF740},"
-               "{Yamaha,YMF740C},"
-               "{Yamaha,YMF744},"
-               "{Yamaha,YMF754}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
index 27d9da6..1445823 100644 (file)
@@ -22,7 +22,6 @@
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("Sound Core " CARD_NAME);
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Sound Core," CARD_NAME "}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
index afd30a9..6363204 100644 (file)
 #include <sound/initval.h>
 #include <sound/tlv.h>
 
-/*
- */
-
 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
 MODULE_DESCRIPTION("Digigram VXPocket");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Digigram,VXPocket},{Digigram,VXPocket440}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
index 96ef550..9fb51eb 100644 (file)
@@ -18,7 +18,6 @@
 #define CHIP_NAME "PMac"
 
 MODULE_DESCRIPTION("PowerMac");
-MODULE_SUPPORTED_DEVICE("{{Apple,PowerMac}}");
 MODULE_LICENSE("GPL");
 
 static int index = SNDRV_DEFAULT_IDX1;         /* Index 0-MAX */
index 8fa6843..6e9d6bd 100644 (file)
@@ -32,7 +32,6 @@
 MODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk>");
 MODULE_DESCRIPTION("Dreamcast AICA sound (pcm) driver");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Yamaha/SEGA, AICA}}");
 MODULE_FIRMWARE("aica_firmware.bin");
 
 /* module parameters */
index feb2850..8ebd972 100644 (file)
@@ -25,7 +25,6 @@
 MODULE_AUTHOR("Rafael Ignacio Zurita <rizurita@yahoo.com>");
 MODULE_DESCRIPTION("SuperH DAC audio driver");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{SuperH DAC audio support}}");
 
 /* Module Parameters */
 static int index = SNDRV_DEFAULT_IDX1;
index e4cf14e..1c87b42 100644 (file)
@@ -186,7 +186,6 @@ config SND_SOC_ALL_CODECS
        imply SND_SOC_SI476X
        imply SND_SOC_SIMPLE_AMPLIFIER
        imply SND_SOC_SIMPLE_MUX
-       imply SND_SOC_SIRF_AUDIO_CODEC
        imply SND_SOC_SPDIF
        imply SND_SOC_SSM2305
        imply SND_SOC_SSM2518
@@ -1279,10 +1278,6 @@ config SND_SOC_SIMPLE_MUX
        tristate "Simple Audio Mux"
        select GPIOLIB
 
-config SND_SOC_SIRF_AUDIO_CODEC
-       tristate "SiRF SoC internal audio codec"
-       select REGMAP_MMIO
-
 config SND_SOC_SPDIF
        tristate "S/PDIF CODEC"
 
index 472caad..85a1d00 100644 (file)
@@ -812,6 +812,7 @@ static const struct of_device_id ak4458_of_match[] = {
        { .compatible = "asahi-kasei,ak4497", .data = &ak4497_drvdata},
        { },
 };
+MODULE_DEVICE_TABLE(of, ak4458_of_match);
 
 static struct i2c_driver ak4458_i2c_driver = {
        .driver = {
index 8a32b01..85bdd05 100644 (file)
@@ -419,6 +419,7 @@ static const struct of_device_id ak5558_i2c_dt_ids[] __maybe_unused = {
        { .compatible = "asahi-kasei,ak5558"},
        { }
 };
+MODULE_DEVICE_TABLE(of, ak5558_i2c_dt_ids);
 
 static struct i2c_driver ak5558_i2c_driver = {
        .driver = {
diff --git a/sound/soc/codecs/arizona-jack.c b/sound/soc/codecs/arizona-jack.c
new file mode 100644 (file)
index 0000000..56d2ce0
--- /dev/null
@@ -0,0 +1,1819 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * extcon-arizona.c - Extcon driver Wolfson Arizona devices
+ *
+ *  Copyright (C) 2012-2014 Wolfson Microelectronics plc
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+#include <linux/extcon-provider.h>
+
+#include <sound/soc.h>
+
+#include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/pdata.h>
+#include <linux/mfd/arizona/registers.h>
+#include <dt-bindings/mfd/arizona.h>
+
+#define ARIZONA_MAX_MICD_RANGE 8
+
+#define ARIZONA_MICD_CLAMP_MODE_JDL      0x4
+#define ARIZONA_MICD_CLAMP_MODE_JDH      0x5
+#define ARIZONA_MICD_CLAMP_MODE_JDL_GP5H 0x9
+#define ARIZONA_MICD_CLAMP_MODE_JDH_GP5H 0xb
+
+#define ARIZONA_TST_CAP_DEFAULT 0x3
+#define ARIZONA_TST_CAP_CLAMP   0x1
+
+#define ARIZONA_HPDET_MAX 10000
+
+#define HPDET_DEBOUNCE 500
+#define DEFAULT_MICD_TIMEOUT 2000
+
+#define ARIZONA_HPDET_WAIT_COUNT 15
+#define ARIZONA_HPDET_WAIT_DELAY_MS 20
+
+#define QUICK_HEADPHONE_MAX_OHM 3
+#define MICROPHONE_MIN_OHM      1257
+#define MICROPHONE_MAX_OHM      30000
+
+#define MICD_DBTIME_TWO_READINGS 2
+#define MICD_DBTIME_FOUR_READINGS 4
+
+#define MICD_LVL_1_TO_7 (ARIZONA_MICD_LVL_1 | ARIZONA_MICD_LVL_2 | \
+                        ARIZONA_MICD_LVL_3 | ARIZONA_MICD_LVL_4 | \
+                        ARIZONA_MICD_LVL_5 | ARIZONA_MICD_LVL_6 | \
+                        ARIZONA_MICD_LVL_7)
+
+#define MICD_LVL_0_TO_7 (ARIZONA_MICD_LVL_0 | MICD_LVL_1_TO_7)
+
+#define MICD_LVL_0_TO_8 (MICD_LVL_0_TO_7 | ARIZONA_MICD_LVL_8)
+
+struct arizona_extcon_info {
+       struct device *dev;
+       struct arizona *arizona;
+       struct mutex lock;
+       struct regulator *micvdd;
+       struct input_dev *input;
+
+       u16 last_jackdet;
+
+       int micd_mode;
+       const struct arizona_micd_config *micd_modes;
+       int micd_num_modes;
+
+       const struct arizona_micd_range *micd_ranges;
+       int num_micd_ranges;
+
+       bool micd_reva;
+       bool micd_clamp;
+
+       struct delayed_work hpdet_work;
+       struct delayed_work micd_detect_work;
+       struct delayed_work micd_timeout_work;
+
+       bool hpdet_active;
+       bool hpdet_done;
+       bool hpdet_retried;
+
+       int num_hpdet_res;
+       unsigned int hpdet_res[3];
+
+       bool mic;
+       bool detecting;
+       int jack_flips;
+
+       int hpdet_ip_version;
+
+       struct extcon_dev *edev;
+
+       struct gpio_desc *micd_pol_gpio;
+};
+
+static const struct arizona_micd_config micd_default_modes[] = {
+       { ARIZONA_ACCDET_SRC, 1, 0 },
+       { 0,                  2, 1 },
+};
+
+static const struct arizona_micd_range micd_default_ranges[] = {
+       { .max =  11, .key = BTN_0 },
+       { .max =  28, .key = BTN_1 },
+       { .max =  54, .key = BTN_2 },
+       { .max = 100, .key = BTN_3 },
+       { .max = 186, .key = BTN_4 },
+       { .max = 430, .key = BTN_5 },
+};
+
+/* The number of levels in arizona_micd_levels valid for button thresholds */
+#define ARIZONA_NUM_MICD_BUTTON_LEVELS 64
+
+static const int arizona_micd_levels[] = {
+       3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 34, 36, 39, 41, 44, 46,
+       49, 52, 54, 57, 60, 62, 65, 67, 70, 73, 75, 78, 81, 83, 89, 94, 100,
+       105, 111, 116, 122, 127, 139, 150, 161, 173, 186, 196, 209, 220, 245,
+       270, 295, 321, 348, 375, 402, 430, 489, 550, 614, 681, 752, 903, 1071,
+       1257, 30000,
+};
+
+static const unsigned int arizona_cable[] = {
+       EXTCON_MECHANICAL,
+       EXTCON_JACK_MICROPHONE,
+       EXTCON_JACK_HEADPHONE,
+       EXTCON_JACK_LINE_OUT,
+       EXTCON_NONE,
+};
+
+static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info);
+
+static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info,
+                                   bool clamp)
+{
+       struct arizona *arizona = info->arizona;
+       unsigned int mask = 0, val = 0;
+       unsigned int cap_sel = 0;
+       int ret;
+
+       switch (arizona->type) {
+       case WM8998:
+       case WM1814:
+               mask = 0;
+               break;
+       case WM5110:
+       case WM8280:
+               mask = ARIZONA_HP1L_SHRTO | ARIZONA_HP1L_FLWR |
+                      ARIZONA_HP1L_SHRTI;
+               if (clamp) {
+                       val = ARIZONA_HP1L_SHRTO;
+                       cap_sel = ARIZONA_TST_CAP_CLAMP;
+               } else {
+                       val = ARIZONA_HP1L_FLWR | ARIZONA_HP1L_SHRTI;
+                       cap_sel = ARIZONA_TST_CAP_DEFAULT;
+               }
+
+               ret = regmap_update_bits(arizona->regmap,
+                                        ARIZONA_HP_TEST_CTRL_1,
+                                        ARIZONA_HP1_TST_CAP_SEL_MASK,
+                                        cap_sel);
+               if (ret != 0)
+                       dev_warn(arizona->dev,
+                                "Failed to set TST_CAP_SEL: %d\n", ret);
+               break;
+       default:
+               mask = ARIZONA_RMV_SHRT_HP1L;
+               if (clamp)
+                       val = ARIZONA_RMV_SHRT_HP1L;
+               break;
+       }
+
+       snd_soc_dapm_mutex_lock(arizona->dapm);
+
+       arizona->hpdet_clamp = clamp;
+
+       /* Keep the HP output stages disabled while doing the clamp */
+       if (clamp) {
+               ret = regmap_update_bits(arizona->regmap,
+                                        ARIZONA_OUTPUT_ENABLES_1,
+                                        ARIZONA_OUT1L_ENA |
+                                        ARIZONA_OUT1R_ENA, 0);
+               if (ret != 0)
+                       dev_warn(arizona->dev,
+                               "Failed to disable headphone outputs: %d\n",
+                                ret);
+       }
+
+       if (mask) {
+               ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1L,
+                                        mask, val);
+               if (ret != 0)
+                       dev_warn(arizona->dev, "Failed to do clamp: %d\n",
+                                ret);
+
+               ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1R,
+                                        mask, val);
+               if (ret != 0)
+                       dev_warn(arizona->dev, "Failed to do clamp: %d\n",
+                                ret);
+       }
+
+       /* Restore the desired state while not doing the clamp */
+       if (!clamp) {
+               ret = regmap_update_bits(arizona->regmap,
+                                        ARIZONA_OUTPUT_ENABLES_1,
+                                        ARIZONA_OUT1L_ENA |
+                                        ARIZONA_OUT1R_ENA, arizona->hp_ena);
+               if (ret != 0)
+                       dev_warn(arizona->dev,
+                                "Failed to restore headphone outputs: %d\n",
+                                ret);
+       }
+
+       snd_soc_dapm_mutex_unlock(arizona->dapm);
+}
+
+static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
+{
+       struct arizona *arizona = info->arizona;
+
+       mode %= info->micd_num_modes;
+
+       gpiod_set_value_cansleep(info->micd_pol_gpio,
+                                info->micd_modes[mode].gpio);
+
+       regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
+                          ARIZONA_MICD_BIAS_SRC_MASK,
+                          info->micd_modes[mode].bias <<
+                          ARIZONA_MICD_BIAS_SRC_SHIFT);
+       regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
+                          ARIZONA_ACCDET_SRC, info->micd_modes[mode].src);
+
+       info->micd_mode = mode;
+
+       dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
+}
+
+static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info)
+{
+       switch (info->micd_modes[0].bias) {
+       case 1:
+               return "MICBIAS1";
+       case 2:
+               return "MICBIAS2";
+       case 3:
+               return "MICBIAS3";
+       default:
+               return "MICVDD";
+       }
+}
+
+static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
+{
+       struct arizona *arizona = info->arizona;
+       const char *widget = arizona_extcon_get_micbias(info);
+       struct snd_soc_dapm_context *dapm = arizona->dapm;
+       struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
+       int ret;
+
+       ret = snd_soc_component_force_enable_pin(component, widget);
+       if (ret != 0)
+               dev_warn(arizona->dev, "Failed to enable %s: %d\n",
+                        widget, ret);
+
+       snd_soc_dapm_sync(dapm);
+
+       if (!arizona->pdata.micd_force_micbias) {
+               ret = snd_soc_component_disable_pin(component, widget);
+               if (ret != 0)
+                       dev_warn(arizona->dev, "Failed to disable %s: %d\n",
+                                widget, ret);
+
+               snd_soc_dapm_sync(dapm);
+       }
+}
+
+static void arizona_start_mic(struct arizona_extcon_info *info)
+{
+       struct arizona *arizona = info->arizona;
+       bool change;
+       int ret;
+       unsigned int mode;
+
+       /* Microphone detection can't use idle mode */
+       pm_runtime_get_sync(info->dev);
+
+       if (info->detecting) {
+               ret = regulator_allow_bypass(info->micvdd, false);
+               if (ret != 0) {
+                       dev_err(arizona->dev,
+                               "Failed to regulate MICVDD: %d\n",
+                               ret);
+               }
+       }
+
+       ret = regulator_enable(info->micvdd);
+       if (ret != 0) {
+               dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
+                       ret);
+       }
+
+       if (info->micd_reva) {
+               const struct reg_sequence reva[] = {
+                       { 0x80,  0x3 },
+                       { 0x294, 0x0 },
+                       { 0x80,  0x0 },
+               };
+
+               regmap_multi_reg_write(arizona->regmap, reva, ARRAY_SIZE(reva));
+       }
+
+       if (info->detecting && arizona->pdata.micd_software_compare)
+               mode = ARIZONA_ACCDET_MODE_ADC;
+       else
+               mode = ARIZONA_ACCDET_MODE_MIC;
+
+       regmap_update_bits(arizona->regmap,
+                          ARIZONA_ACCESSORY_DETECT_MODE_1,
+                          ARIZONA_ACCDET_MODE_MASK, mode);
+
+       arizona_extcon_pulse_micbias(info);
+
+       ret = regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
+                                      ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
+                                      &change);
+       if (ret < 0) {
+               dev_err(arizona->dev, "Failed to enable micd: %d\n", ret);
+       } else if (!change) {
+               regulator_disable(info->micvdd);
+               pm_runtime_put_autosuspend(info->dev);
+       }
+}
+
+static void arizona_stop_mic(struct arizona_extcon_info *info)
+{
+       struct arizona *arizona = info->arizona;
+       const char *widget = arizona_extcon_get_micbias(info);
+       struct snd_soc_dapm_context *dapm = arizona->dapm;
+       struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
+       bool change = false;
+       int ret;
+
+       ret = regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
+                                      ARIZONA_MICD_ENA, 0,
+                                      &change);
+       if (ret < 0)
+               dev_err(arizona->dev, "Failed to disable micd: %d\n", ret);
+
+       ret = snd_soc_component_disable_pin(component, widget);
+       if (ret != 0)
+               dev_warn(arizona->dev,
+                        "Failed to disable %s: %d\n",
+                        widget, ret);
+
+       snd_soc_dapm_sync(dapm);
+
+       if (info->micd_reva) {
+               const struct reg_sequence reva[] = {
+                       { 0x80,  0x3 },
+                       { 0x294, 0x2 },
+                       { 0x80,  0x0 },
+               };
+
+               regmap_multi_reg_write(arizona->regmap, reva, ARRAY_SIZE(reva));
+       }
+
+       ret = regulator_allow_bypass(info->micvdd, true);
+       if (ret != 0) {
+               dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
+                       ret);
+       }
+
+       if (change) {
+               regulator_disable(info->micvdd);
+               pm_runtime_mark_last_busy(info->dev);
+               pm_runtime_put_autosuspend(info->dev);
+       }
+}
+
+static struct {
+       unsigned int threshold;
+       unsigned int factor_a;
+       unsigned int factor_b;
+} arizona_hpdet_b_ranges[] = {
+       { 100,  5528,   362464 },
+       { 169, 11084,  6186851 },
+       { 169, 11065, 65460395 },
+};
+
+#define ARIZONA_HPDET_B_RANGE_MAX 0x3fb
+
+static struct {
+       int min;
+       int max;
+} arizona_hpdet_c_ranges[] = {
+       { 0,       30 },
+       { 8,      100 },
+       { 100,   1000 },
+       { 1000, 10000 },
+};
+
+static int arizona_hpdet_read(struct arizona_extcon_info *info)
+{
+       struct arizona *arizona = info->arizona;
+       unsigned int val, range;
+       int ret;
+
+       ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val);
+       if (ret != 0) {
+               dev_err(arizona->dev, "Failed to read HPDET status: %d\n",
+                       ret);
+               return ret;
+       }
+
+       switch (info->hpdet_ip_version) {
+       case 0:
+               if (!(val & ARIZONA_HP_DONE)) {
+                       dev_err(arizona->dev, "HPDET did not complete: %x\n",
+                               val);
+                       return -EAGAIN;
+               }
+
+               val &= ARIZONA_HP_LVL_MASK;
+               break;
+
+       case 1:
+               if (!(val & ARIZONA_HP_DONE_B)) {
+                       dev_err(arizona->dev, "HPDET did not complete: %x\n",
+                               val);
+                       return -EAGAIN;
+               }
+
+               ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val);
+               if (ret != 0) {
+                       dev_err(arizona->dev, "Failed to read HP value: %d\n",
+                               ret);
+                       return -EAGAIN;
+               }
+
+               regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
+                           &range);
+               range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
+                          >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
+
+               if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 &&
+                   (val < arizona_hpdet_b_ranges[range].threshold ||
+                    val >= ARIZONA_HPDET_B_RANGE_MAX)) {
+                       range++;
+                       dev_dbg(arizona->dev, "Moving to HPDET range %d\n",
+                               range);
+                       regmap_update_bits(arizona->regmap,
+                                          ARIZONA_HEADPHONE_DETECT_1,
+                                          ARIZONA_HP_IMPEDANCE_RANGE_MASK,
+                                          range <<
+                                          ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
+                       return -EAGAIN;
+               }
+
+               /* If we go out of range report top of range */
+               if (val < arizona_hpdet_b_ranges[range].threshold ||
+                   val >= ARIZONA_HPDET_B_RANGE_MAX) {
+                       dev_dbg(arizona->dev, "Measurement out of range\n");
+                       return ARIZONA_HPDET_MAX;
+               }
+
+               dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
+                       val, range);
+
+               val = arizona_hpdet_b_ranges[range].factor_b
+                       / ((val * 100) -
+                          arizona_hpdet_b_ranges[range].factor_a);
+               break;
+
+       case 2:
+               if (!(val & ARIZONA_HP_DONE_B)) {
+                       dev_err(arizona->dev, "HPDET did not complete: %x\n",
+                               val);
+                       return -EAGAIN;
+               }
+
+               val &= ARIZONA_HP_LVL_B_MASK;
+               /* Convert to ohms, the value is in 0.5 ohm increments */
+               val /= 2;
+
+               regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
+                           &range);
+               range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
+                          >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
+
+               /* Skip up a range, or report? */
+               if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
+                   (val >= arizona_hpdet_c_ranges[range].max)) {
+                       range++;
+                       dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
+                               arizona_hpdet_c_ranges[range].min,
+                               arizona_hpdet_c_ranges[range].max);
+                       regmap_update_bits(arizona->regmap,
+                                          ARIZONA_HEADPHONE_DETECT_1,
+                                          ARIZONA_HP_IMPEDANCE_RANGE_MASK,
+                                          range <<
+                                          ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
+                       return -EAGAIN;
+               }
+
+               if (range && (val < arizona_hpdet_c_ranges[range].min)) {
+                       dev_dbg(arizona->dev, "Reporting range boundary %d\n",
+                               arizona_hpdet_c_ranges[range].min);
+                       val = arizona_hpdet_c_ranges[range].min;
+               }
+               break;
+
+       default:
+               dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
+                        info->hpdet_ip_version);
+               return -EINVAL;
+       }
+
+       dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
+       return val;
+}
+
+static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
+                              bool *mic)
+{
+       struct arizona *arizona = info->arizona;
+       int id_gpio = arizona->pdata.hpdet_id_gpio;
+
+       if (!arizona->pdata.hpdet_acc_id)
+               return 0;
+
+       /*
+        * If we're using HPDET for accessory identification we need
+        * to take multiple measurements, step through them in sequence.
+        */
+       info->hpdet_res[info->num_hpdet_res++] = *reading;
+
+       /* Only check the mic directly if we didn't already ID it */
+       if (id_gpio && info->num_hpdet_res == 1) {
+               dev_dbg(arizona->dev, "Measuring mic\n");
+
+               regmap_update_bits(arizona->regmap,
+                                  ARIZONA_ACCESSORY_DETECT_MODE_1,
+                                  ARIZONA_ACCDET_MODE_MASK |
+                                  ARIZONA_ACCDET_SRC,
+                                  ARIZONA_ACCDET_MODE_HPR |
+                                  info->micd_modes[0].src);
+
+               gpio_set_value_cansleep(id_gpio, 1);
+
+               regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
+                                  ARIZONA_HP_POLL, ARIZONA_HP_POLL);
+               return -EAGAIN;
+       }
+
+       /* OK, got both.  Now, compare... */
+       dev_dbg(arizona->dev, "HPDET measured %d %d\n",
+               info->hpdet_res[0], info->hpdet_res[1]);
+
+       /* Take the headphone impedance for the main report */
+       *reading = info->hpdet_res[0];
+
+       /* Sometimes we get false readings due to slow insert */
+       if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
+               dev_dbg(arizona->dev, "Retrying high impedance\n");
+               info->num_hpdet_res = 0;
+               info->hpdet_retried = true;
+               arizona_start_hpdet_acc_id(info);
+               pm_runtime_put(info->dev);
+               return -EAGAIN;
+       }
+
+       /*
+        * If we measure the mic as high impedance
+        */
+       if (!id_gpio || info->hpdet_res[1] > 50) {
+               dev_dbg(arizona->dev, "Detected mic\n");
+               *mic = true;
+               info->detecting = true;
+       } else {
+               dev_dbg(arizona->dev, "Detected headphone\n");
+       }
+
+       /* Make sure everything is reset back to the real polarity */
+       regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1,
+                          ARIZONA_ACCDET_SRC, info->micd_modes[0].src);
+
+       return 0;
+}
+
+static irqreturn_t arizona_hpdet_irq(int irq, void *data)
+{
+       struct arizona_extcon_info *info = data;
+       struct arizona *arizona = info->arizona;
+       int id_gpio = arizona->pdata.hpdet_id_gpio;
+       unsigned int report = EXTCON_JACK_HEADPHONE;
+       int ret, reading, state;
+       bool mic = false;
+
+       mutex_lock(&info->lock);
+
+       /* If we got a spurious IRQ for some reason then ignore it */
+       if (!info->hpdet_active) {
+               dev_warn(arizona->dev, "Spurious HPDET IRQ\n");
+               mutex_unlock(&info->lock);
+               return IRQ_NONE;
+       }
+
+       /* If the cable was removed while measuring ignore the result */
+       state = extcon_get_state(info->edev, EXTCON_MECHANICAL);
+       if (state < 0) {
+               dev_err(arizona->dev, "Failed to check cable state: %d\n", state);
+               goto out;
+       } else if (!state) {
+               dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
+               goto done;
+       }
+
+       ret = arizona_hpdet_read(info);
+       if (ret == -EAGAIN)
+               goto out;
+       else if (ret < 0)
+               goto done;
+       reading = ret;
+
+       /* Reset back to starting range */
+       regmap_update_bits(arizona->regmap,
+                          ARIZONA_HEADPHONE_DETECT_1,
+                          ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
+                          0);
+
+       ret = arizona_hpdet_do_id(info, &reading, &mic);
+       if (ret == -EAGAIN)
+               goto out;
+       else if (ret < 0)
+               goto done;
+
+       /* Report high impedence cables as line outputs */
+       if (reading >= 5000)
+               report = EXTCON_JACK_LINE_OUT;
+       else
+               report = EXTCON_JACK_HEADPHONE;
+
+       ret = extcon_set_state_sync(info->edev, report, true);
+       if (ret != 0)
+               dev_err(arizona->dev, "Failed to report HP/line: %d\n",
+                       ret);
+
+done:
+       /* Reset back to starting range */
+       regmap_update_bits(arizona->regmap,
+                          ARIZONA_HEADPHONE_DETECT_1,
+                          ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
+                          0);
+
+       arizona_extcon_hp_clamp(info, false);
+
+       if (id_gpio)
+               gpio_set_value_cansleep(id_gpio, 0);
+
+       /* If we have a mic then reenable MICDET */
+       if (state && (mic || info->mic))
+               arizona_start_mic(info);
+
+       if (info->hpdet_active) {
+               pm_runtime_put_autosuspend(info->dev);
+               info->hpdet_active = false;
+       }
+
+       /* Do not set hp_det done when the cable has been unplugged */
+       if (state)
+               info->hpdet_done = true;
+
+out:
+       mutex_unlock(&info->lock);
+
+       return IRQ_HANDLED;
+}
+
+static void arizona_identify_headphone(struct arizona_extcon_info *info)
+{
+       struct arizona *arizona = info->arizona;
+       int ret;
+
+       if (info->hpdet_done)
+               return;
+
+       dev_dbg(arizona->dev, "Starting HPDET\n");
+
+       /* Make sure we keep the device enabled during the measurement */
+       pm_runtime_get_sync(info->dev);
+
+       info->hpdet_active = true;
+
+       arizona_stop_mic(info);
+
+       arizona_extcon_hp_clamp(info, true);
+
+       ret = regmap_update_bits(arizona->regmap,
+                                ARIZONA_ACCESSORY_DETECT_MODE_1,
+                                ARIZONA_ACCDET_MODE_MASK,
+                                arizona->pdata.hpdet_channel);
+       if (ret != 0) {
+               dev_err(arizona->dev, "Failed to set HPDET mode: %d\n", ret);
+               goto err;
+       }
+
+       ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
+                                ARIZONA_HP_POLL, ARIZONA_HP_POLL);
+       if (ret != 0) {
+               dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
+                       ret);
+               goto err;
+       }
+
+       return;
+
+err:
+       arizona_extcon_hp_clamp(info, false);
+       pm_runtime_put_autosuspend(info->dev);
+
+       /* Just report headphone */
+       ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true);
+       if (ret != 0)
+               dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
+
+       if (info->mic)
+               arizona_start_mic(info);
+
+       info->hpdet_active = false;
+}
+
+static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
+{
+       struct arizona *arizona = info->arizona;
+       int hp_reading = 32;
+       bool mic;
+       int ret;
+
+       dev_dbg(arizona->dev, "Starting identification via HPDET\n");
+
+       /* Make sure we keep the device enabled during the measurement */
+       pm_runtime_get_sync(info->dev);
+
+       info->hpdet_active = true;
+
+       arizona_extcon_hp_clamp(info, true);
+
+       ret = regmap_update_bits(arizona->regmap,
+                                ARIZONA_ACCESSORY_DETECT_MODE_1,
+                                ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
+                                info->micd_modes[0].src |
+                                arizona->pdata.hpdet_channel);
+       if (ret != 0) {
+               dev_err(arizona->dev, "Failed to set HPDET mode: %d\n", ret);
+               goto err;
+       }
+
+       if (arizona->pdata.hpdet_acc_id_line) {
+               ret = regmap_update_bits(arizona->regmap,
+                                        ARIZONA_HEADPHONE_DETECT_1,
+                                        ARIZONA_HP_POLL, ARIZONA_HP_POLL);
+               if (ret != 0) {
+                       dev_err(arizona->dev,
+                               "Can't start HPDETL measurement: %d\n",
+                               ret);
+                       goto err;
+               }
+       } else {
+               arizona_hpdet_do_id(info, &hp_reading, &mic);
+       }
+
+       return;
+
+err:
+       /* Just report headphone */
+       ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true);
+       if (ret != 0)
+               dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
+
+       info->hpdet_active = false;
+}
+
+static void arizona_micd_timeout_work(struct work_struct *work)
+{
+       struct arizona_extcon_info *info = container_of(work,
+                                               struct arizona_extcon_info,
+                                               micd_timeout_work.work);
+
+       mutex_lock(&info->lock);
+
+       dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
+
+       info->detecting = false;
+
+       arizona_identify_headphone(info);
+
+       mutex_unlock(&info->lock);
+}
+
+static int arizona_micd_adc_read(struct arizona_extcon_info *info)
+{
+       struct arizona *arizona = info->arizona;
+       unsigned int val;
+       int ret;
+
+       /* Must disable MICD before we read the ADCVAL */
+       regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
+                          ARIZONA_MICD_ENA, 0);
+
+       ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_4, &val);
+       if (ret != 0) {
+               dev_err(arizona->dev,
+                       "Failed to read MICDET_ADCVAL: %d\n", ret);
+               return ret;
+       }
+
+       dev_dbg(arizona->dev, "MICDET_ADCVAL: %x\n", val);
+
+       val &= ARIZONA_MICDET_ADCVAL_MASK;
+       if (val < ARRAY_SIZE(arizona_micd_levels))
+               val = arizona_micd_levels[val];
+       else
+               val = INT_MAX;
+
+       if (val <= QUICK_HEADPHONE_MAX_OHM)
+               val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_0;
+       else if (val <= MICROPHONE_MIN_OHM)
+               val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_1;
+       else if (val <= MICROPHONE_MAX_OHM)
+               val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_8;
+       else
+               val = ARIZONA_MICD_LVL_8;
+
+       return val;
+}
+
+static int arizona_micd_read(struct arizona_extcon_info *info)
+{
+       struct arizona *arizona = info->arizona;
+       unsigned int val = 0;
+       int ret, i;
+
+       for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
+               ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
+               if (ret != 0) {
+                       dev_err(arizona->dev,
+                               "Failed to read MICDET: %d\n", ret);
+                       return ret;
+               }
+
+               dev_dbg(arizona->dev, "MICDET: %x\n", val);
+
+               if (!(val & ARIZONA_MICD_VALID)) {
+                       dev_warn(arizona->dev,
+                                "Microphone detection state invalid\n");
+                       return -EINVAL;
+               }
+       }
+
+       if (i == 10 && !(val & MICD_LVL_0_TO_8)) {
+               dev_err(arizona->dev, "Failed to get valid MICDET value\n");
+               return -EINVAL;
+       }
+
+       return val;
+}
+
+static int arizona_micdet_reading(void *priv)
+{
+       struct arizona_extcon_info *info = priv;
+       struct arizona *arizona = info->arizona;
+       int ret, val;
+
+       if (info->detecting && arizona->pdata.micd_software_compare)
+               ret = arizona_micd_adc_read(info);
+       else
+               ret = arizona_micd_read(info);
+       if (ret < 0)
+               return ret;
+
+       val = ret;
+
+       /* Due to jack detect this should never happen */
+       if (!(val & ARIZONA_MICD_STS)) {
+               dev_warn(arizona->dev, "Detected open circuit\n");
+               info->mic = false;
+               info->detecting = false;
+               arizona_identify_headphone(info);
+               return 0;
+       }
+
+       /* If we got a high impedence we should have a headset, report it. */
+       if (val & ARIZONA_MICD_LVL_8) {
+               info->mic = true;
+               info->detecting = false;
+
+               arizona_identify_headphone(info);
+
+               ret = extcon_set_state_sync(info->edev,
+                                             EXTCON_JACK_MICROPHONE, true);
+               if (ret != 0)
+                       dev_err(arizona->dev, "Headset report failed: %d\n",
+                               ret);
+
+               /* Don't need to regulate for button detection */
+               ret = regulator_allow_bypass(info->micvdd, true);
+               if (ret != 0) {
+                       dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
+                               ret);
+               }
+
+               return 0;
+       }
+
+       /* If we detected a lower impedence during initial startup
+        * then we probably have the wrong polarity, flip it.  Don't
+        * do this for the lowest impedences to speed up detection of
+        * plain headphones.  If both polarities report a low
+        * impedence then give up and report headphones.
+        */
+       if (val & MICD_LVL_1_TO_7) {
+               if (info->jack_flips >= info->micd_num_modes * 10) {
+                       dev_dbg(arizona->dev, "Detected HP/line\n");
+
+                       info->detecting = false;
+
+                       arizona_identify_headphone(info);
+               } else {
+                       info->micd_mode++;
+                       if (info->micd_mode == info->micd_num_modes)
+                               info->micd_mode = 0;
+                       arizona_extcon_set_mode(info, info->micd_mode);
+
+                       info->jack_flips++;
+
+                       if (arizona->pdata.micd_software_compare)
+                               regmap_update_bits(arizona->regmap,
+                                                  ARIZONA_MIC_DETECT_1,
+                                                  ARIZONA_MICD_ENA,
+                                                  ARIZONA_MICD_ENA);
+
+                       queue_delayed_work(system_power_efficient_wq,
+                                          &info->micd_timeout_work,
+                                          msecs_to_jiffies(arizona->pdata.micd_timeout));
+               }
+
+               return 0;
+       }
+
+       /*
+        * If we're still detecting and we detect a short then we've
+        * got a headphone.
+        */
+       dev_dbg(arizona->dev, "Headphone detected\n");
+       info->detecting = false;
+
+       arizona_identify_headphone(info);
+
+       return 0;
+}
+
+static int arizona_button_reading(void *priv)
+{
+       struct arizona_extcon_info *info = priv;
+       struct arizona *arizona = info->arizona;
+       int val, key, lvl, i;
+
+       val = arizona_micd_read(info);
+       if (val < 0)
+               return val;
+
+       /*
+        * If we're still detecting and we detect a short then we've
+        * got a headphone.  Otherwise it's a button press.
+        */
+       if (val & MICD_LVL_0_TO_7) {
+               if (info->mic) {
+                       dev_dbg(arizona->dev, "Mic button detected\n");
+
+                       lvl = val & ARIZONA_MICD_LVL_MASK;
+                       lvl >>= ARIZONA_MICD_LVL_SHIFT;
+
+                       for (i = 0; i < info->num_micd_ranges; i++)
+                               input_report_key(info->input,
+                                                info->micd_ranges[i].key, 0);
+
+                       if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
+                               key = info->micd_ranges[ffs(lvl) - 1].key;
+                               input_report_key(info->input, key, 1);
+                               input_sync(info->input);
+                       } else {
+                               dev_err(arizona->dev, "Button out of range\n");
+                       }
+               } else {
+                       dev_warn(arizona->dev, "Button with no mic: %x\n",
+                                val);
+               }
+       } else {
+               dev_dbg(arizona->dev, "Mic button released\n");
+               for (i = 0; i < info->num_micd_ranges; i++)
+                       input_report_key(info->input,
+                                        info->micd_ranges[i].key, 0);
+               input_sync(info->input);
+               arizona_extcon_pulse_micbias(info);
+       }
+
+       return 0;
+}
+
+static void arizona_micd_detect(struct work_struct *work)
+{
+       struct arizona_extcon_info *info = container_of(work,
+                                               struct arizona_extcon_info,
+                                               micd_detect_work.work);
+       struct arizona *arizona = info->arizona;
+       int ret;
+
+       cancel_delayed_work_sync(&info->micd_timeout_work);
+
+       mutex_lock(&info->lock);
+
+       /* If the cable was removed while measuring ignore the result */
+       ret = extcon_get_state(info->edev, EXTCON_MECHANICAL);
+       if (ret < 0) {
+               dev_err(arizona->dev, "Failed to check cable state: %d\n",
+                               ret);
+               mutex_unlock(&info->lock);
+               return;
+       } else if (!ret) {
+               dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n");
+               mutex_unlock(&info->lock);
+               return;
+       }
+
+       if (info->detecting)
+               arizona_micdet_reading(info);
+       else
+               arizona_button_reading(info);
+
+       pm_runtime_mark_last_busy(info->dev);
+       mutex_unlock(&info->lock);
+}
+
+static irqreturn_t arizona_micdet(int irq, void *data)
+{
+       struct arizona_extcon_info *info = data;
+       struct arizona *arizona = info->arizona;
+       int debounce = arizona->pdata.micd_detect_debounce;
+
+       cancel_delayed_work_sync(&info->micd_detect_work);
+       cancel_delayed_work_sync(&info->micd_timeout_work);
+
+       mutex_lock(&info->lock);
+       if (!info->detecting)
+               debounce = 0;
+       mutex_unlock(&info->lock);
+
+       if (debounce)
+               queue_delayed_work(system_power_efficient_wq,
+                                  &info->micd_detect_work,
+                                  msecs_to_jiffies(debounce));
+       else
+               arizona_micd_detect(&info->micd_detect_work.work);
+
+       return IRQ_HANDLED;
+}
+
+static void arizona_hpdet_work(struct work_struct *work)
+{
+       struct arizona_extcon_info *info = container_of(work,
+                                               struct arizona_extcon_info,
+                                               hpdet_work.work);
+
+       mutex_lock(&info->lock);
+       arizona_start_hpdet_acc_id(info);
+       mutex_unlock(&info->lock);
+}
+
+static int arizona_hpdet_wait(struct arizona_extcon_info *info)
+{
+       struct arizona *arizona = info->arizona;
+       unsigned int val;
+       int i, ret;
+
+       for (i = 0; i < ARIZONA_HPDET_WAIT_COUNT; i++) {
+               ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2,
+                               &val);
+               if (ret) {
+                       dev_err(arizona->dev,
+                               "Failed to read HPDET state: %d\n", ret);
+                       return ret;
+               }
+
+               switch (info->hpdet_ip_version) {
+               case 0:
+                       if (val & ARIZONA_HP_DONE)
+                               return 0;
+                       break;
+               default:
+                       if (val & ARIZONA_HP_DONE_B)
+                               return 0;
+                       break;
+               }
+
+               msleep(ARIZONA_HPDET_WAIT_DELAY_MS);
+       }
+
+       dev_warn(arizona->dev, "HPDET did not appear to complete\n");
+
+       return -ETIMEDOUT;
+}
+
+static irqreturn_t arizona_jackdet(int irq, void *data)
+{
+       struct arizona_extcon_info *info = data;
+       struct arizona *arizona = info->arizona;
+       unsigned int val, present, mask;
+       bool cancelled_hp, cancelled_mic;
+       int ret, i;
+
+       cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
+       cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
+
+       pm_runtime_get_sync(info->dev);
+
+       mutex_lock(&info->lock);
+
+       if (info->micd_clamp) {
+               mask = ARIZONA_MICD_CLAMP_STS;
+               present = 0;
+       } else {
+               mask = ARIZONA_JD1_STS;
+               if (arizona->pdata.jd_invert)
+                       present = 0;
+               else
+                       present = ARIZONA_JD1_STS;
+       }
+
+       ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
+       if (ret != 0) {
+               dev_err(arizona->dev, "Failed to read jackdet status: %d\n",
+                       ret);
+               mutex_unlock(&info->lock);
+               pm_runtime_put_autosuspend(info->dev);
+               return IRQ_NONE;
+       }
+
+       val &= mask;
+       if (val == info->last_jackdet) {
+               dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
+               if (cancelled_hp)
+                       queue_delayed_work(system_power_efficient_wq,
+                                          &info->hpdet_work,
+                                          msecs_to_jiffies(HPDET_DEBOUNCE));
+
+               if (cancelled_mic) {
+                       int micd_timeout = arizona->pdata.micd_timeout;
+
+                       queue_delayed_work(system_power_efficient_wq,
+                                          &info->micd_timeout_work,
+                                          msecs_to_jiffies(micd_timeout));
+               }
+
+               goto out;
+       }
+       info->last_jackdet = val;
+
+       if (info->last_jackdet == present) {
+               dev_dbg(arizona->dev, "Detected jack\n");
+               ret = extcon_set_state_sync(info->edev,
+                                             EXTCON_MECHANICAL, true);
+
+               if (ret != 0)
+                       dev_err(arizona->dev, "Mechanical report failed: %d\n",
+                               ret);
+
+               info->detecting = true;
+               info->mic = false;
+               info->jack_flips = 0;
+
+               if (!arizona->pdata.hpdet_acc_id) {
+                       arizona_start_mic(info);
+               } else {
+                       queue_delayed_work(system_power_efficient_wq,
+                                          &info->hpdet_work,
+                                          msecs_to_jiffies(HPDET_DEBOUNCE));
+               }
+
+               if (info->micd_clamp || !arizona->pdata.jd_invert)
+                       regmap_update_bits(arizona->regmap,
+                                          ARIZONA_JACK_DETECT_DEBOUNCE,
+                                          ARIZONA_MICD_CLAMP_DB |
+                                          ARIZONA_JD1_DB, 0);
+       } else {
+               dev_dbg(arizona->dev, "Detected jack removal\n");
+
+               arizona_stop_mic(info);
+
+               info->num_hpdet_res = 0;
+               for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
+                       info->hpdet_res[i] = 0;
+               info->mic = false;
+               info->hpdet_done = false;
+               info->hpdet_retried = false;
+
+               for (i = 0; i < info->num_micd_ranges; i++)
+                       input_report_key(info->input,
+                                        info->micd_ranges[i].key, 0);
+               input_sync(info->input);
+
+               for (i = 0; i < ARRAY_SIZE(arizona_cable) - 1; i++) {
+                       ret = extcon_set_state_sync(info->edev,
+                                       arizona_cable[i], false);
+                       if (ret != 0)
+                               dev_err(arizona->dev,
+                                       "Removal report failed: %d\n", ret);
+               }
+
+               /*
+                * If the jack was removed during a headphone detection we
+                * need to wait for the headphone detection to finish, as
+                * it can not be aborted. We don't want to be able to start
+                * a new headphone detection from a fresh insert until this
+                * one is finished.
+                */
+               arizona_hpdet_wait(info);
+
+               regmap_update_bits(arizona->regmap,
+                                  ARIZONA_JACK_DETECT_DEBOUNCE,
+                                  ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
+                                  ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
+       }
+
+out:
+       /* Clear trig_sts to make sure DCVDD is not forced up */
+       regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
+                    ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
+                    ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
+                    ARIZONA_JD1_FALL_TRIG_STS |
+                    ARIZONA_JD1_RISE_TRIG_STS);
+
+       mutex_unlock(&info->lock);
+
+       pm_runtime_mark_last_busy(info->dev);
+       pm_runtime_put_autosuspend(info->dev);
+
+       return IRQ_HANDLED;
+}
+
+/* Map a level onto a slot in the register bank */
+static void arizona_micd_set_level(struct arizona *arizona, int index,
+                                  unsigned int level)
+{
+       int reg;
+       unsigned int mask;
+
+       reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
+
+       if (!(index % 2)) {
+               mask = 0x3f00;
+               level <<= 8;
+       } else {
+               mask = 0x3f;
+       }
+
+       /* Program the level itself */
+       regmap_update_bits(arizona->regmap, reg, mask, level);
+}
+
+static int arizona_extcon_get_micd_configs(struct device *dev,
+                                          struct arizona *arizona)
+{
+       const char * const prop = "wlf,micd-configs";
+       const int entries_per_config = 3;
+       struct arizona_micd_config *micd_configs;
+       int nconfs, ret;
+       int i, j;
+       u32 *vals;
+
+       nconfs = device_property_count_u32(arizona->dev, prop);
+       if (nconfs <= 0)
+               return 0;
+
+       vals = kcalloc(nconfs, sizeof(u32), GFP_KERNEL);
+       if (!vals)
+               return -ENOMEM;
+
+       ret = device_property_read_u32_array(arizona->dev, prop, vals, nconfs);
+       if (ret < 0)
+               goto out;
+
+       nconfs /= entries_per_config;
+       micd_configs = devm_kcalloc(dev, nconfs, sizeof(*micd_configs),
+                                   GFP_KERNEL);
+       if (!micd_configs) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       for (i = 0, j = 0; i < nconfs; ++i) {
+               micd_configs[i].src = vals[j++] ? ARIZONA_ACCDET_SRC : 0;
+               micd_configs[i].bias = vals[j++];
+               micd_configs[i].gpio = vals[j++];
+       }
+
+       arizona->pdata.micd_configs = micd_configs;
+       arizona->pdata.num_micd_configs = nconfs;
+
+out:
+       kfree(vals);
+       return ret;
+}
+
+static int arizona_extcon_device_get_pdata(struct device *dev,
+                                          struct arizona *arizona)
+{
+       struct arizona_pdata *pdata = &arizona->pdata;
+       unsigned int val = ARIZONA_ACCDET_MODE_HPL;
+       int ret;
+
+       device_property_read_u32(arizona->dev, "wlf,hpdet-channel", &val);
+       switch (val) {
+       case ARIZONA_ACCDET_MODE_HPL:
+       case ARIZONA_ACCDET_MODE_HPR:
+               pdata->hpdet_channel = val;
+               break;
+       default:
+               dev_err(arizona->dev,
+                       "Wrong wlf,hpdet-channel DT value %d\n", val);
+               pdata->hpdet_channel = ARIZONA_ACCDET_MODE_HPL;
+       }
+
+       device_property_read_u32(arizona->dev, "wlf,micd-detect-debounce",
+                                &pdata->micd_detect_debounce);
+
+       device_property_read_u32(arizona->dev, "wlf,micd-bias-start-time",
+                                &pdata->micd_bias_start_time);
+
+       device_property_read_u32(arizona->dev, "wlf,micd-rate",
+                                &pdata->micd_rate);
+
+       device_property_read_u32(arizona->dev, "wlf,micd-dbtime",
+                                &pdata->micd_dbtime);
+
+       device_property_read_u32(arizona->dev, "wlf,micd-timeout-ms",
+                                &pdata->micd_timeout);
+
+       pdata->micd_force_micbias = device_property_read_bool(arizona->dev,
+                                               "wlf,micd-force-micbias");
+
+       pdata->micd_software_compare = device_property_read_bool(arizona->dev,
+                                               "wlf,micd-software-compare");
+
+       pdata->jd_invert = device_property_read_bool(arizona->dev,
+                                                    "wlf,jd-invert");
+
+       device_property_read_u32(arizona->dev, "wlf,gpsw", &pdata->gpsw);
+
+       pdata->jd_gpio5 = device_property_read_bool(arizona->dev,
+                                                   "wlf,use-jd2");
+       pdata->jd_gpio5_nopull = device_property_read_bool(arizona->dev,
+                                               "wlf,use-jd2-nopull");
+
+       ret = arizona_extcon_get_micd_configs(dev, arizona);
+       if (ret < 0)
+               dev_err(arizona->dev, "Failed to read micd configs: %d\n", ret);
+
+       return 0;
+}
+
+static int arizona_extcon_probe(struct platform_device *pdev)
+{
+       struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
+       struct arizona_pdata *pdata = &arizona->pdata;
+       struct arizona_extcon_info *info;
+       unsigned int val;
+       unsigned int clamp_mode;
+       int jack_irq_fall, jack_irq_rise;
+       int ret, mode, i, j;
+
+       if (!arizona->dapm || !arizona->dapm->card)
+               return -EPROBE_DEFER;
+
+       info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       if (!dev_get_platdata(arizona->dev))
+               arizona_extcon_device_get_pdata(&pdev->dev, arizona);
+
+       info->micvdd = devm_regulator_get(&pdev->dev, "MICVDD");
+       if (IS_ERR(info->micvdd)) {
+               ret = PTR_ERR(info->micvdd);
+               dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
+               return ret;
+       }
+
+       mutex_init(&info->lock);
+       info->arizona = arizona;
+       info->dev = &pdev->dev;
+       info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
+       INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
+       INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
+       INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
+       platform_set_drvdata(pdev, info);
+
+       switch (arizona->type) {
+       case WM5102:
+               switch (arizona->rev) {
+               case 0:
+                       info->micd_reva = true;
+                       break;
+               default:
+                       info->micd_clamp = true;
+                       info->hpdet_ip_version = 1;
+                       break;
+               }
+               break;
+       case WM5110:
+       case WM8280:
+               switch (arizona->rev) {
+               case 0 ... 2:
+                       break;
+               default:
+                       info->micd_clamp = true;
+                       info->hpdet_ip_version = 2;
+                       break;
+               }
+               break;
+       case WM8998:
+       case WM1814:
+               info->micd_clamp = true;
+               info->hpdet_ip_version = 2;
+               break;
+       default:
+               break;
+       }
+
+       info->edev = devm_extcon_dev_allocate(&pdev->dev, arizona_cable);
+       if (IS_ERR(info->edev)) {
+               dev_err(&pdev->dev, "failed to allocate extcon device\n");
+               return -ENOMEM;
+       }
+
+       ret = devm_extcon_dev_register(&pdev->dev, info->edev);
+       if (ret < 0) {
+               dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
+                       ret);
+               return ret;
+       }
+
+       info->input = devm_input_allocate_device(&pdev->dev);
+       if (!info->input) {
+               dev_err(arizona->dev, "Can't allocate input dev\n");
+               ret = -ENOMEM;
+               return ret;
+       }
+
+       info->input->name = "Headset";
+       info->input->phys = "arizona/extcon";
+
+       if (!pdata->micd_timeout)
+               pdata->micd_timeout = DEFAULT_MICD_TIMEOUT;
+
+       if (pdata->num_micd_configs) {
+               info->micd_modes = pdata->micd_configs;
+               info->micd_num_modes = pdata->num_micd_configs;
+       } else {
+               info->micd_modes = micd_default_modes;
+               info->micd_num_modes = ARRAY_SIZE(micd_default_modes);
+       }
+
+       if (arizona->pdata.gpsw > 0)
+               regmap_update_bits(arizona->regmap, ARIZONA_GP_SWITCH_1,
+                               ARIZONA_SW1_MODE_MASK, arizona->pdata.gpsw);
+
+       if (pdata->micd_pol_gpio > 0) {
+               if (info->micd_modes[0].gpio)
+                       mode = GPIOF_OUT_INIT_HIGH;
+               else
+                       mode = GPIOF_OUT_INIT_LOW;
+
+               ret = devm_gpio_request_one(&pdev->dev, pdata->micd_pol_gpio,
+                                           mode, "MICD polarity");
+               if (ret != 0) {
+                       dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
+                               pdata->micd_pol_gpio, ret);
+                       return ret;
+               }
+
+               info->micd_pol_gpio = gpio_to_desc(pdata->micd_pol_gpio);
+       } else {
+               if (info->micd_modes[0].gpio)
+                       mode = GPIOD_OUT_HIGH;
+               else
+                       mode = GPIOD_OUT_LOW;
+
+               /* We can't use devm here because we need to do the get
+                * against the MFD device, as that is where the of_node
+                * will reside, but if we devm against that the GPIO
+                * will not be freed if the extcon driver is unloaded.
+                */
+               info->micd_pol_gpio = gpiod_get_optional(arizona->dev,
+                                                        "wlf,micd-pol",
+                                                        mode);
+               if (IS_ERR(info->micd_pol_gpio)) {
+                       ret = PTR_ERR(info->micd_pol_gpio);
+                       dev_err(arizona->dev,
+                               "Failed to get microphone polarity GPIO: %d\n",
+                               ret);
+                       return ret;
+               }
+       }
+
+       if (arizona->pdata.hpdet_id_gpio > 0) {
+               ret = devm_gpio_request_one(&pdev->dev,
+                                           arizona->pdata.hpdet_id_gpio,
+                                           GPIOF_OUT_INIT_LOW,
+                                           "HPDET");
+               if (ret != 0) {
+                       dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
+                               arizona->pdata.hpdet_id_gpio, ret);
+                       goto err_gpio;
+               }
+       }
+
+       if (arizona->pdata.micd_bias_start_time)
+               regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
+                                  ARIZONA_MICD_BIAS_STARTTIME_MASK,
+                                  arizona->pdata.micd_bias_start_time
+                                  << ARIZONA_MICD_BIAS_STARTTIME_SHIFT);
+
+       if (arizona->pdata.micd_rate)
+               regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
+                                  ARIZONA_MICD_RATE_MASK,
+                                  arizona->pdata.micd_rate
+                                  << ARIZONA_MICD_RATE_SHIFT);
+
+       switch (arizona->pdata.micd_dbtime) {
+       case MICD_DBTIME_FOUR_READINGS:
+               regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
+                                  ARIZONA_MICD_DBTIME_MASK,
+                                  ARIZONA_MICD_DBTIME);
+               break;
+       case MICD_DBTIME_TWO_READINGS:
+               regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
+                                  ARIZONA_MICD_DBTIME_MASK, 0);
+               break;
+       default:
+               break;
+       }
+
+       BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) <
+                    ARIZONA_NUM_MICD_BUTTON_LEVELS);
+
+       if (arizona->pdata.num_micd_ranges) {
+               info->micd_ranges = pdata->micd_ranges;
+               info->num_micd_ranges = pdata->num_micd_ranges;
+       } else {
+               info->micd_ranges = micd_default_ranges;
+               info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
+       }
+
+       if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
+               dev_err(arizona->dev, "Too many MICD ranges: %d\n",
+                       arizona->pdata.num_micd_ranges);
+       }
+
+       if (info->num_micd_ranges > 1) {
+               for (i = 1; i < info->num_micd_ranges; i++) {
+                       if (info->micd_ranges[i - 1].max >
+                           info->micd_ranges[i].max) {
+                               dev_err(arizona->dev,
+                                       "MICD ranges must be sorted\n");
+                               ret = -EINVAL;
+                               goto err_gpio;
+                       }
+               }
+       }
+
+       /* Disable all buttons by default */
+       regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
+                          ARIZONA_MICD_LVL_SEL_MASK, 0x81);
+
+       /* Set up all the buttons the user specified */
+       for (i = 0; i < info->num_micd_ranges; i++) {
+               for (j = 0; j < ARIZONA_NUM_MICD_BUTTON_LEVELS; j++)
+                       if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
+                               break;
+
+               if (j == ARIZONA_NUM_MICD_BUTTON_LEVELS) {
+                       dev_err(arizona->dev, "Unsupported MICD level %d\n",
+                               info->micd_ranges[i].max);
+                       ret = -EINVAL;
+                       goto err_gpio;
+               }
+
+               dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
+                       arizona_micd_levels[j], i);
+
+               arizona_micd_set_level(arizona, i, j);
+               input_set_capability(info->input, EV_KEY,
+                                    info->micd_ranges[i].key);
+
+               /* Enable reporting of that range */
+               regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
+                                  1 << i, 1 << i);
+       }
+
+       /* Set all the remaining keys to a maximum */
+       for (; i < ARIZONA_MAX_MICD_RANGE; i++)
+               arizona_micd_set_level(arizona, i, 0x3f);
+
+       /*
+        * If we have a clamp use it, activating in conjunction with
+        * GPIO5 if that is connected for jack detect operation.
+        */
+       if (info->micd_clamp) {
+               if (arizona->pdata.jd_gpio5) {
+                       /* Put the GPIO into input mode with optional pull */
+                       val = 0xc101;
+                       if (arizona->pdata.jd_gpio5_nopull)
+                               val &= ~ARIZONA_GPN_PU;
+
+                       regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
+                                    val);
+
+                       if (arizona->pdata.jd_invert)
+                               clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH_GP5H;
+                       else
+                               clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL_GP5H;
+               } else {
+                       if (arizona->pdata.jd_invert)
+                               clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH;
+                       else
+                               clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL;
+               }
+
+               regmap_update_bits(arizona->regmap,
+                                  ARIZONA_MICD_CLAMP_CONTROL,
+                                  ARIZONA_MICD_CLAMP_MODE_MASK, clamp_mode);
+
+               regmap_update_bits(arizona->regmap,
+                                  ARIZONA_JACK_DETECT_DEBOUNCE,
+                                  ARIZONA_MICD_CLAMP_DB,
+                                  ARIZONA_MICD_CLAMP_DB);
+       }
+
+       arizona_extcon_set_mode(info, 0);
+
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_idle(&pdev->dev);
+       pm_runtime_get_sync(&pdev->dev);
+
+       if (info->micd_clamp) {
+               jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
+               jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
+       } else {
+               jack_irq_rise = ARIZONA_IRQ_JD_RISE;
+               jack_irq_fall = ARIZONA_IRQ_JD_FALL;
+       }
+
+       ret = arizona_request_irq(arizona, jack_irq_rise,
+                                 "JACKDET rise", arizona_jackdet, info);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n",
+                       ret);
+               goto err_pm;
+       }
+
+       ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n",
+                       ret);
+               goto err_rise;
+       }
+
+       ret = arizona_request_irq(arizona, jack_irq_fall,
+                                 "JACKDET fall", arizona_jackdet, info);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret);
+               goto err_rise_wake;
+       }
+
+       ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n",
+                       ret);
+               goto err_fall;
+       }
+
+       ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET,
+                                 "MICDET", arizona_micdet, info);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret);
+               goto err_fall_wake;
+       }
+
+       ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET,
+                                 "HPDET", arizona_hpdet_irq, info);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret);
+               goto err_micdet;
+       }
+
+       arizona_clk32k_enable(arizona);
+       regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE,
+                          ARIZONA_JD1_DB, ARIZONA_JD1_DB);
+       regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
+                          ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
+
+       ret = regulator_allow_bypass(info->micvdd, true);
+       if (ret != 0)
+               dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
+                        ret);
+
+       ret = input_register_device(info->input);
+       if (ret) {
+               dev_err(&pdev->dev, "Can't register input device: %d\n", ret);
+               goto err_hpdet;
+       }
+
+       pm_runtime_put(&pdev->dev);
+
+       return 0;
+
+err_hpdet:
+       arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
+err_micdet:
+       arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
+err_fall_wake:
+       arizona_set_irq_wake(arizona, jack_irq_fall, 0);
+err_fall:
+       arizona_free_irq(arizona, jack_irq_fall, info);
+err_rise_wake:
+       arizona_set_irq_wake(arizona, jack_irq_rise, 0);
+err_rise:
+       arizona_free_irq(arizona, jack_irq_rise, info);
+err_pm:
+       pm_runtime_put(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+err_gpio:
+       gpiod_put(info->micd_pol_gpio);
+       return ret;
+}
+
+static int arizona_extcon_remove(struct platform_device *pdev)
+{
+       struct arizona_extcon_info *info = platform_get_drvdata(pdev);
+       struct arizona *arizona = info->arizona;
+       int jack_irq_rise, jack_irq_fall;
+       bool change;
+       int ret;
+
+       if (info->micd_clamp) {
+               jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
+               jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
+       } else {
+               jack_irq_rise = ARIZONA_IRQ_JD_RISE;
+               jack_irq_fall = ARIZONA_IRQ_JD_FALL;
+       }
+
+       arizona_set_irq_wake(arizona, jack_irq_rise, 0);
+       arizona_set_irq_wake(arizona, jack_irq_fall, 0);
+       arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info);
+       arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info);
+       arizona_free_irq(arizona, jack_irq_rise, info);
+       arizona_free_irq(arizona, jack_irq_fall, info);
+       cancel_delayed_work_sync(&info->hpdet_work);
+       cancel_delayed_work_sync(&info->micd_detect_work);
+       cancel_delayed_work_sync(&info->micd_timeout_work);
+
+       ret = regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
+                                      ARIZONA_MICD_ENA, 0,
+                                      &change);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to disable micd on remove: %d\n",
+                       ret);
+       } else if (change) {
+               regulator_disable(info->micvdd);
+               pm_runtime_put(info->dev);
+       }
+
+       regmap_update_bits(arizona->regmap,
+                          ARIZONA_MICD_CLAMP_CONTROL,
+                          ARIZONA_MICD_CLAMP_MODE_MASK, 0);
+       regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
+                          ARIZONA_JD1_ENA, 0);
+       arizona_clk32k_disable(arizona);
+
+       gpiod_put(info->micd_pol_gpio);
+
+       pm_runtime_disable(&pdev->dev);
+
+       return 0;
+}
+
+static struct platform_driver arizona_extcon_driver = {
+       .driver         = {
+               .name   = "arizona-extcon",
+       },
+       .probe          = arizona_extcon_probe,
+       .remove         = arizona_extcon_remove,
+};
+
+module_platform_driver(arizona_extcon_driver);
+
+MODULE_DESCRIPTION("Arizona Extcon driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:extcon-arizona");
index 210fcbe..811b7b1 100644 (file)
@@ -401,7 +401,7 @@ static const struct regmap_config cs42l42_regmap = {
 };
 
 static DECLARE_TLV_DB_SCALE(adc_tlv, -9600, 100, false);
-static DECLARE_TLV_DB_SCALE(mixer_tlv, -6200, 100, false);
+static DECLARE_TLV_DB_SCALE(mixer_tlv, -6300, 100, true);
 
 static const char * const cs42l42_hpf_freq_text[] = {
        "1.86Hz", "120Hz", "235Hz", "466Hz"
@@ -458,7 +458,7 @@ static const struct snd_kcontrol_new cs42l42_snd_controls[] = {
                                CS42L42_DAC_HPF_EN_SHIFT, true, false),
        SOC_DOUBLE_R_TLV("Mixer Volume", CS42L42_MIXER_CHA_VOL,
                         CS42L42_MIXER_CHB_VOL, CS42L42_MIXER_CH_VOL_SHIFT,
-                               0x3e, 1, mixer_tlv)
+                               0x3f, 1, mixer_tlv)
 };
 
 static int cs42l42_hpdrv_evt(struct snd_soc_dapm_widget *w,
@@ -511,43 +511,6 @@ static const struct snd_soc_dapm_route cs42l42_audio_map[] = {
        {"HP", NULL, "HPDRV"}
 };
 
-static int cs42l42_set_bias_level(struct snd_soc_component *component,
-                                       enum snd_soc_bias_level level)
-{
-       struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component);
-       int ret;
-
-       switch (level) {
-       case SND_SOC_BIAS_ON:
-               break;
-       case SND_SOC_BIAS_PREPARE:
-               break;
-       case SND_SOC_BIAS_STANDBY:
-               if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
-                       regcache_cache_only(cs42l42->regmap, false);
-                       regcache_sync(cs42l42->regmap);
-                       ret = regulator_bulk_enable(
-                                               ARRAY_SIZE(cs42l42->supplies),
-                                               cs42l42->supplies);
-                       if (ret != 0) {
-                               dev_err(component->dev,
-                                       "Failed to enable regulators: %d\n",
-                                       ret);
-                               return ret;
-                       }
-               }
-               break;
-       case SND_SOC_BIAS_OFF:
-
-               regcache_cache_only(cs42l42->regmap, true);
-               regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies),
-                                                   cs42l42->supplies);
-               break;
-       }
-
-       return 0;
-}
-
 static int cs42l42_component_probe(struct snd_soc_component *component)
 {
        struct cs42l42_private *cs42l42 =
@@ -560,7 +523,6 @@ static int cs42l42_component_probe(struct snd_soc_component *component)
 
 static const struct snd_soc_component_driver soc_component_dev_cs42l42 = {
        .probe                  = cs42l42_component_probe,
-       .set_bias_level         = cs42l42_set_bias_level,
        .dapm_widgets           = cs42l42_dapm_widgets,
        .num_dapm_widgets       = ARRAY_SIZE(cs42l42_dapm_widgets),
        .dapm_routes            = cs42l42_audio_map,
@@ -691,24 +653,6 @@ static int cs42l42_pll_config(struct snd_soc_component *component)
                                        CS42L42_CLK_OASRC_SEL_MASK,
                                        CS42L42_CLK_OASRC_SEL_12 <<
                                        CS42L42_CLK_OASRC_SEL_SHIFT);
-                       /* channel 1 on low LRCLK, 32 bit */
-                       snd_soc_component_update_bits(component,
-                                       CS42L42_ASP_RX_DAI0_CH1_AP_RES,
-                                       CS42L42_ASP_RX_CH_AP_MASK |
-                                       CS42L42_ASP_RX_CH_RES_MASK,
-                                       (CS42L42_ASP_RX_CH_AP_LOW <<
-                                       CS42L42_ASP_RX_CH_AP_SHIFT) |
-                                       (CS42L42_ASP_RX_CH_RES_32 <<
-                                       CS42L42_ASP_RX_CH_RES_SHIFT));
-                       /* Channel 2 on high LRCLK, 32 bit */
-                       snd_soc_component_update_bits(component,
-                                       CS42L42_ASP_RX_DAI0_CH2_AP_RES,
-                                       CS42L42_ASP_RX_CH_AP_MASK |
-                                       CS42L42_ASP_RX_CH_RES_MASK,
-                                       (CS42L42_ASP_RX_CH_AP_HI <<
-                                       CS42L42_ASP_RX_CH_AP_SHIFT) |
-                                       (CS42L42_ASP_RX_CH_RES_32 <<
-                                       CS42L42_ASP_RX_CH_RES_SHIFT));
                        if (pll_ratio_table[i].mclk_src_sel == 0) {
                                /* Pass the clock straight through */
                                snd_soc_component_update_bits(component,
@@ -797,27 +741,23 @@ static int cs42l42_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
        /* Bitclock/frame inversion */
        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
        case SND_SOC_DAIFMT_NB_NF:
+               asp_cfg_val |= CS42L42_ASP_SCPOL_NOR << CS42L42_ASP_SCPOL_SHIFT;
                break;
        case SND_SOC_DAIFMT_NB_IF:
-               asp_cfg_val |= CS42L42_ASP_POL_INV <<
-                               CS42L42_ASP_LCPOL_IN_SHIFT;
+               asp_cfg_val |= CS42L42_ASP_SCPOL_NOR << CS42L42_ASP_SCPOL_SHIFT;
+               asp_cfg_val |= CS42L42_ASP_LCPOL_INV << CS42L42_ASP_LCPOL_SHIFT;
                break;
        case SND_SOC_DAIFMT_IB_NF:
-               asp_cfg_val |= CS42L42_ASP_POL_INV <<
-                               CS42L42_ASP_SCPOL_IN_DAC_SHIFT;
                break;
        case SND_SOC_DAIFMT_IB_IF:
-               asp_cfg_val |= CS42L42_ASP_POL_INV <<
-                               CS42L42_ASP_LCPOL_IN_SHIFT;
-               asp_cfg_val |= CS42L42_ASP_POL_INV <<
-                               CS42L42_ASP_SCPOL_IN_DAC_SHIFT;
+               asp_cfg_val |= CS42L42_ASP_LCPOL_INV << CS42L42_ASP_LCPOL_SHIFT;
                break;
        }
 
-       snd_soc_component_update_bits(component, CS42L42_ASP_CLK_CFG,
-                               CS42L42_ASP_MODE_MASK |
-                               CS42L42_ASP_SCPOL_IN_DAC_MASK |
-                               CS42L42_ASP_LCPOL_IN_MASK, asp_cfg_val);
+       snd_soc_component_update_bits(component, CS42L42_ASP_CLK_CFG, CS42L42_ASP_MODE_MASK |
+                                                                     CS42L42_ASP_SCPOL_MASK |
+                                                                     CS42L42_ASP_LCPOL_MASK,
+                                                                     asp_cfg_val);
 
        return 0;
 }
@@ -828,14 +768,29 @@ static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_component *component = dai->component;
        struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component);
-       int retval;
+       unsigned int width = (params_width(params) / 8) - 1;
+       unsigned int val = 0;
 
        cs42l42->srate = params_rate(params);
-       cs42l42->swidth = params_width(params);
 
-       retval = cs42l42_pll_config(component);
+       switch(substream->stream) {
+       case SNDRV_PCM_STREAM_PLAYBACK:
+               val |= width << CS42L42_ASP_RX_CH_RES_SHIFT;
+               /* channel 1 on low LRCLK */
+               snd_soc_component_update_bits(component, CS42L42_ASP_RX_DAI0_CH1_AP_RES,
+                                                        CS42L42_ASP_RX_CH_AP_MASK |
+                                                        CS42L42_ASP_RX_CH_RES_MASK, val);
+               /* Channel 2 on high LRCLK */
+               val |= CS42L42_ASP_RX_CH_AP_HI << CS42L42_ASP_RX_CH_AP_SHIFT;
+               snd_soc_component_update_bits(component, CS42L42_ASP_RX_DAI0_CH2_AP_RES,
+                                                        CS42L42_ASP_RX_CH_AP_MASK |
+                                                        CS42L42_ASP_RX_CH_RES_MASK, val);
+               break;
+       default:
+               break;
+       }
 
-       return retval;
+       return cs42l42_pll_config(component);
 }
 
 static int cs42l42_set_sysclk(struct snd_soc_dai *dai,
@@ -900,9 +855,9 @@ static int cs42l42_mute(struct snd_soc_dai *dai, int mute, int direction)
        return 0;
 }
 
-#define CS42L42_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \
-                       SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | \
-                       SNDRV_PCM_FMTBIT_S32_LE)
+#define CS42L42_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+                        SNDRV_PCM_FMTBIT_S24_LE |\
+                        SNDRV_PCM_FMTBIT_S32_LE )
 
 
 static const struct snd_soc_dai_ops cs42l42_ops = {
@@ -1801,7 +1756,7 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client,
                dev_dbg(&i2c_client->dev, "Found reset GPIO\n");
                gpiod_set_value_cansleep(cs42l42->reset_gpio, 1);
        }
-       mdelay(3);
+       usleep_range(CS42L42_BOOT_TIME_US, CS42L42_BOOT_TIME_US * 2);
 
        /* Request IRQ */
        ret = devm_request_threaded_irq(&i2c_client->dev,
@@ -1926,6 +1881,7 @@ static int cs42l42_runtime_resume(struct device *dev)
        }
 
        gpiod_set_value_cansleep(cs42l42->reset_gpio, 1);
+       usleep_range(CS42L42_BOOT_TIME_US, CS42L42_BOOT_TIME_US * 2);
 
        regcache_cache_only(cs42l42->regmap, false);
        regcache_sync(cs42l42->regmap);
index 9e3cc52..866d7c8 100644 (file)
 #define CS42L42_ASP_SLAVE_MODE         0x00
 #define CS42L42_ASP_MODE_SHIFT         4
 #define CS42L42_ASP_MODE_MASK          (1 << CS42L42_ASP_MODE_SHIFT)
-#define CS42L42_ASP_SCPOL_IN_DAC_SHIFT 2
-#define CS42L42_ASP_SCPOL_IN_DAC_MASK  (1 << CS42L42_ASP_SCPOL_IN_DAC_SHIFT)
-#define CS42L42_ASP_LCPOL_IN_SHIFT     0
-#define CS42L42_ASP_LCPOL_IN_MASK      (1 << CS42L42_ASP_LCPOL_IN_SHIFT)
-#define CS42L42_ASP_POL_INV            1
+#define CS42L42_ASP_SCPOL_SHIFT                2
+#define CS42L42_ASP_SCPOL_MASK         (3 << CS42L42_ASP_SCPOL_SHIFT)
+#define CS42L42_ASP_SCPOL_NOR          3
+#define CS42L42_ASP_LCPOL_SHIFT                0
+#define CS42L42_ASP_LCPOL_MASK         (3 << CS42L42_ASP_LCPOL_SHIFT)
+#define CS42L42_ASP_LCPOL_INV          3
 
 #define CS42L42_ASP_FRM_CFG            (CS42L42_PAGE_12 + 0x08)
 #define CS42L42_ASP_STP_SHIFT          4
 #define CS42L42_FRAC2_VAL(val) (((val) & 0xff0000) >> 16)
 
 #define CS42L42_NUM_SUPPLIES   5
+#define CS42L42_BOOT_TIME_US   3000
 
 static const char *const cs42l42_supply_names[CS42L42_NUM_SUPPLIES] = {
        "VA",
@@ -756,7 +758,6 @@ struct  cs42l42_private {
        struct completion pdn_done;
        u32 sclk;
        u32 srate;
-       u32 swidth;
        u8 plug_state;
        u8 hs_type;
        u8 ts_inv;
index d632055..067757d 100644 (file)
@@ -63,13 +63,8 @@ static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(adc_pga_gain_tlv,
        1, 1, TLV_DB_SCALE_ITEM(0, 0, 0),
        2, 2, TLV_DB_SCALE_ITEM(250, 0, 0),
        3, 3, TLV_DB_SCALE_ITEM(450, 0, 0),
-       4, 4, TLV_DB_SCALE_ITEM(700, 0, 0),
-       5, 5, TLV_DB_SCALE_ITEM(1000, 0, 0),
-       6, 6, TLV_DB_SCALE_ITEM(1300, 0, 0),
-       7, 7, TLV_DB_SCALE_ITEM(1600, 0, 0),
-       8, 8, TLV_DB_SCALE_ITEM(1800, 0, 0),
-       9, 9, TLV_DB_SCALE_ITEM(2100, 0, 0),
-       10, 10, TLV_DB_SCALE_ITEM(2400, 0, 0),
+       4, 7, TLV_DB_SCALE_ITEM(700, 300, 0),
+       8, 10, TLV_DB_SCALE_ITEM(1800, 300, 0),
 );
 
 static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(hpout_vol_tlv,
index c9c21d2..8c04b3b 100644 (file)
@@ -2895,7 +2895,7 @@ static int rx_macro_enable_echo(struct snd_soc_dapm_widget *w,
 {
        struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
        u16 val, ec_hq_reg;
-       int ec_tx;
+       int ec_tx = -1;
 
        val = snd_soc_component_read(component,
                        CDC_RX_INP_MUX_RX_MIX_CFG4);
index 91e6890..3d6976a 100644 (file)
@@ -189,7 +189,6 @@ struct va_macro {
        struct device *dev;
        unsigned long active_ch_mask[VA_MACRO_MAX_DAIS];
        unsigned long active_ch_cnt[VA_MACRO_MAX_DAIS];
-       unsigned long active_decimator[VA_MACRO_MAX_DAIS];
        u16 dmic_clk_div;
 
        int dec_mode[VA_MACRO_NUM_DECIMATORS];
@@ -549,11 +548,9 @@ static int va_macro_tx_mixer_put(struct snd_kcontrol *kcontrol,
        if (enable) {
                set_bit(dec_id, &va->active_ch_mask[dai_id]);
                va->active_ch_cnt[dai_id]++;
-               va->active_decimator[dai_id] = dec_id;
        } else {
                clear_bit(dec_id, &va->active_ch_mask[dai_id]);
                va->active_ch_cnt[dai_id]--;
-               va->active_decimator[dai_id] = -1;
        }
 
        snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, update);
@@ -880,18 +877,19 @@ static int va_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
        struct va_macro *va = snd_soc_component_get_drvdata(component);
        u16 tx_vol_ctl_reg, decimator;
 
-       decimator = va->active_decimator[dai->id];
-
-       tx_vol_ctl_reg = CDC_VA_TX0_TX_PATH_CTL +
-                               VA_MACRO_TX_PATH_OFFSET * decimator;
-       if (mute)
-               snd_soc_component_update_bits(component, tx_vol_ctl_reg,
-                                             CDC_VA_TX_PATH_PGA_MUTE_EN_MASK,
-                                             CDC_VA_TX_PATH_PGA_MUTE_EN);
-       else
-               snd_soc_component_update_bits(component, tx_vol_ctl_reg,
-                                             CDC_VA_TX_PATH_PGA_MUTE_EN_MASK,
-                                             CDC_VA_TX_PATH_PGA_MUTE_DISABLE);
+       for_each_set_bit(decimator, &va->active_ch_mask[dai->id],
+                        VA_MACRO_DEC_MAX) {
+               tx_vol_ctl_reg = CDC_VA_TX0_TX_PATH_CTL +
+                                       VA_MACRO_TX_PATH_OFFSET * decimator;
+               if (mute)
+                       snd_soc_component_update_bits(component, tx_vol_ctl_reg,
+                                       CDC_VA_TX_PATH_PGA_MUTE_EN_MASK,
+                                       CDC_VA_TX_PATH_PGA_MUTE_EN);
+               else
+                       snd_soc_component_update_bits(component, tx_vol_ctl_reg,
+                                       CDC_VA_TX_PATH_PGA_MUTE_EN_MASK,
+                                       CDC_VA_TX_PATH_PGA_MUTE_DISABLE);
+       }
 
        return 0;
 }
index 5ebcd93..9ca49a1 100644 (file)
@@ -1211,14 +1211,16 @@ static int wsa_macro_enable_mix_path(struct snd_soc_dapm_widget *w,
                                     struct snd_kcontrol *kcontrol, int event)
 {
        struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
-       u16 gain_reg;
+       u16 path_reg, gain_reg;
        int val;
 
-       switch (w->reg) {
-       case CDC_WSA_RX0_RX_PATH_MIX_CTL:
+       switch (w->shift) {
+       case WSA_MACRO_RX_MIX0:
+               path_reg = CDC_WSA_RX0_RX_PATH_MIX_CTL;
                gain_reg = CDC_WSA_RX0_RX_VOL_MIX_CTL;
                break;
-       case CDC_WSA_RX1_RX_PATH_MIX_CTL:
+       case WSA_MACRO_RX_MIX1:
+               path_reg = CDC_WSA_RX1_RX_PATH_MIX_CTL;
                gain_reg = CDC_WSA_RX1_RX_VOL_MIX_CTL;
                break;
        default:
@@ -1231,7 +1233,7 @@ static int wsa_macro_enable_mix_path(struct snd_soc_dapm_widget *w,
                snd_soc_component_write(component, gain_reg, val);
                break;
        case SND_SOC_DAPM_POST_PMD:
-               snd_soc_component_update_bits(component, w->reg,
+               snd_soc_component_update_bits(component, path_reg,
                                              CDC_WSA_RX_PATH_MIX_CLK_EN_MASK,
                                              CDC_WSA_RX_PATH_MIX_CLK_DISABLE);
                break;
@@ -2068,14 +2070,14 @@ static const struct snd_soc_dapm_widget wsa_macro_dapm_widgets[] = {
        SND_SOC_DAPM_MUX("WSA_RX0 INP0", SND_SOC_NOPM, 0, 0, &rx0_prim_inp0_mux),
        SND_SOC_DAPM_MUX("WSA_RX0 INP1", SND_SOC_NOPM, 0, 0, &rx0_prim_inp1_mux),
        SND_SOC_DAPM_MUX("WSA_RX0 INP2", SND_SOC_NOPM, 0, 0, &rx0_prim_inp2_mux),
-       SND_SOC_DAPM_MUX_E("WSA_RX0 MIX INP", CDC_WSA_RX0_RX_PATH_MIX_CTL,
-                          0, 0, &rx0_mix_mux, wsa_macro_enable_mix_path,
+       SND_SOC_DAPM_MUX_E("WSA_RX0 MIX INP", SND_SOC_NOPM, WSA_MACRO_RX_MIX0,
+                          0, &rx0_mix_mux, wsa_macro_enable_mix_path,
                           SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
        SND_SOC_DAPM_MUX("WSA_RX1 INP0", SND_SOC_NOPM, 0, 0, &rx1_prim_inp0_mux),
        SND_SOC_DAPM_MUX("WSA_RX1 INP1", SND_SOC_NOPM, 0, 0, &rx1_prim_inp1_mux),
        SND_SOC_DAPM_MUX("WSA_RX1 INP2", SND_SOC_NOPM, 0, 0, &rx1_prim_inp2_mux),
-       SND_SOC_DAPM_MUX_E("WSA_RX1 MIX INP", CDC_WSA_RX1_RX_PATH_MIX_CTL,
-                          0, 0, &rx1_mix_mux, wsa_macro_enable_mix_path,
+       SND_SOC_DAPM_MUX_E("WSA_RX1 MIX INP", SND_SOC_NOPM, WSA_MACRO_RX_MIX1,
+                          0, &rx1_mix_mux, wsa_macro_enable_mix_path,
                           SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 
        SND_SOC_DAPM_MIXER_E("WSA_RX INT0 MIX", SND_SOC_NOPM, 0, 0, NULL, 0,
index 37b5795..844e407 100644 (file)
@@ -209,6 +209,7 @@ static bool rt1015_volatile_register(struct device *dev, unsigned int reg)
        case RT1015_VENDOR_ID:
        case RT1015_DEVICE_ID:
        case RT1015_PRO_ALT:
+       case RT1015_MAN_I2C:
        case RT1015_DAC3:
        case RT1015_VBAT_TEST_OUT1:
        case RT1015_VBAT_TEST_OUT2:
@@ -513,6 +514,7 @@ static void rt1015_calibrate(struct rt1015_priv *rt1015)
        msleep(300);
        regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x0008);
        regmap_write(regmap, RT1015_SYS_RST1, 0x05F5);
+       regmap_write(regmap, RT1015_CLK_DET, 0x8000);
 
        regcache_cache_bypass(regmap, false);
        regcache_mark_dirty(regmap);
index 1414ad1..a5674c2 100644 (file)
@@ -339,9 +339,9 @@ static bool rt5640_readable_register(struct device *dev, unsigned int reg)
 }
 
 static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
-static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
+static const DECLARE_TLV_DB_MINMAX(dac_vol_tlv, -6562, 0);
 static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
-static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_MINMAX(adc_vol_tlv, -1762, 3000);
 static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
 
 /* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
index d198e19..e59fdc8 100644 (file)
@@ -285,9 +285,9 @@ static bool rt5651_readable_register(struct device *dev, unsigned int reg)
 }
 
 static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
-static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
+static const DECLARE_TLV_DB_MINMAX(dac_vol_tlv, -6562, 0);
 static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
-static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_MINMAX(adc_vol_tlv, -1762, 3000);
 static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
 
 /* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
index 41e5917..91a4ef7 100644 (file)
@@ -3426,12 +3426,17 @@ static int rt5659_set_component_sysclk(struct snd_soc_component *component, int
 {
        struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
        unsigned int reg_val = 0;
+       int ret;
 
        if (freq == rt5659->sysclk && clk_id == rt5659->sysclk_src)
                return 0;
 
        switch (clk_id) {
        case RT5659_SCLK_S_MCLK:
+               ret = clk_set_rate(rt5659->mclk, freq);
+               if (ret)
+                       return ret;
+
                reg_val |= RT5659_SCLK_SRC_MCLK;
                break;
        case RT5659_SCLK_S_PLL1:
index c29317e..4063aac 100644 (file)
@@ -629,21 +629,69 @@ static SOC_ENUM_SINGLE_DECL(rt5670_if2_dac_enum, RT5670_DIG_INF1_DATA,
 static SOC_ENUM_SINGLE_DECL(rt5670_if2_adc_enum, RT5670_DIG_INF1_DATA,
                                RT5670_IF2_ADC_SEL_SFT, rt5670_data_select);
 
+/*
+ * For reliable output-mute LED control we need a "DAC1 Playback Switch" control.
+ * We emulate this by only clearing the RT5670_M_DAC1_L/_R AD_DA_MIXER register
+ * bits when both our emulated DAC1 Playback Switch control and the DAC1 MIXL/R
+ * DAPM-mixer DAC1 input are enabled.
+ */
+static void rt5670_update_ad_da_mixer_dac1_m_bits(struct rt5670_priv *rt5670)
+{
+       int val = RT5670_M_DAC1_L | RT5670_M_DAC1_R;
+
+       if (rt5670->dac1_mixl_dac1_switch && rt5670->dac1_playback_switch_l)
+               val &= ~RT5670_M_DAC1_L;
+
+       if (rt5670->dac1_mixr_dac1_switch && rt5670->dac1_playback_switch_r)
+               val &= ~RT5670_M_DAC1_R;
+
+       regmap_update_bits(rt5670->regmap, RT5670_AD_DA_MIXER,
+                          RT5670_M_DAC1_L | RT5670_M_DAC1_R, val);
+}
+
+static int rt5670_dac1_playback_switch_get(struct snd_kcontrol *kcontrol,
+                                          struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
+
+       ucontrol->value.integer.value[0] = rt5670->dac1_playback_switch_l;
+       ucontrol->value.integer.value[1] = rt5670->dac1_playback_switch_r;
+
+       return 0;
+}
+
+static int rt5670_dac1_playback_switch_put(struct snd_kcontrol *kcontrol,
+                                          struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
+
+       if (rt5670->dac1_playback_switch_l == ucontrol->value.integer.value[0] &&
+           rt5670->dac1_playback_switch_r == ucontrol->value.integer.value[1])
+               return 0;
+
+       rt5670->dac1_playback_switch_l = ucontrol->value.integer.value[0];
+       rt5670->dac1_playback_switch_r = ucontrol->value.integer.value[1];
+
+       rt5670_update_ad_da_mixer_dac1_m_bits(rt5670);
+
+       return 1;
+}
+
 static const struct snd_kcontrol_new rt5670_snd_controls[] = {
        /* Headphone Output Volume */
-       SOC_DOUBLE("HP Playback Switch", RT5670_HP_VOL,
-               RT5670_L_MUTE_SFT, RT5670_R_MUTE_SFT, 1, 1),
        SOC_DOUBLE_TLV("HP Playback Volume", RT5670_HP_VOL,
                RT5670_L_VOL_SFT, RT5670_R_VOL_SFT,
                39, 1, out_vol_tlv),
        /* OUTPUT Control */
-       SOC_DOUBLE("OUT Channel Switch", RT5670_LOUT1,
-               RT5670_VOL_L_SFT, RT5670_VOL_R_SFT, 1, 1),
        SOC_DOUBLE_TLV("OUT Playback Volume", RT5670_LOUT1,
                RT5670_L_VOL_SFT, RT5670_R_VOL_SFT, 39, 1, out_vol_tlv),
        /* DAC Digital Volume */
        SOC_DOUBLE("DAC2 Playback Switch", RT5670_DAC_CTRL,
                RT5670_M_DAC_L2_VOL_SFT, RT5670_M_DAC_R2_VOL_SFT, 1, 1),
+       SOC_DOUBLE_EXT("DAC1 Playback Switch", SND_SOC_NOPM, 0, 1, 1, 0,
+                       rt5670_dac1_playback_switch_get, rt5670_dac1_playback_switch_put),
        SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5670_DAC1_DIG_VOL,
                        RT5670_L_VOL_SFT, RT5670_R_VOL_SFT,
                        175, 0, dac_vol_tlv),
@@ -913,18 +961,44 @@ static const struct snd_kcontrol_new rt5670_mono_adc_r_mix[] = {
                        RT5670_M_MONO_ADC_R2_SFT, 1, 1),
 };
 
+/* See comment above rt5670_update_ad_da_mixer_dac1_m_bits() */
+static int rt5670_put_dac1_mix_dac1_switch(struct snd_kcontrol *kcontrol,
+                                          struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
+       struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+       struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
+       int ret;
+
+       if (mc->shift == 0)
+               rt5670->dac1_mixl_dac1_switch = ucontrol->value.integer.value[0];
+       else
+               rt5670->dac1_mixr_dac1_switch = ucontrol->value.integer.value[0];
+
+       /* Apply the update (if any) */
+       ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
+       if (ret == 0)
+               return 0;
+
+       rt5670_update_ad_da_mixer_dac1_m_bits(rt5670);
+
+       return 1;
+}
+
+#define SOC_DAPM_SINGLE_RT5670_DAC1_SW(name, shift) \
+       SOC_SINGLE_EXT(name, SND_SOC_NOPM, shift, 1, 0, \
+                      snd_soc_dapm_get_volsw, rt5670_put_dac1_mix_dac1_switch)
+
 static const struct snd_kcontrol_new rt5670_dac_l_mix[] = {
        SOC_DAPM_SINGLE("Stereo ADC Switch", RT5670_AD_DA_MIXER,
                        RT5670_M_ADCMIX_L_SFT, 1, 1),
-       SOC_DAPM_SINGLE("DAC1 Switch", RT5670_AD_DA_MIXER,
-                       RT5670_M_DAC1_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE_RT5670_DAC1_SW("DAC1 Switch", 0),
 };
 
 static const struct snd_kcontrol_new rt5670_dac_r_mix[] = {
        SOC_DAPM_SINGLE("Stereo ADC Switch", RT5670_AD_DA_MIXER,
                        RT5670_M_ADCMIX_R_SFT, 1, 1),
-       SOC_DAPM_SINGLE("DAC1 Switch", RT5670_AD_DA_MIXER,
-                       RT5670_M_DAC1_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE_RT5670_DAC1_SW("DAC1 Switch", 1),
 };
 
 static const struct snd_kcontrol_new rt5670_sto_dac_l_mix[] = {
@@ -1656,12 +1730,10 @@ static const struct snd_soc_dapm_widget rt5670_dapm_widgets[] = {
                            RT5670_PWR_ADC_S1F_BIT, 0, NULL, 0),
        SND_SOC_DAPM_SUPPLY("ADC Stereo2 Filter", RT5670_PWR_DIG2,
                            RT5670_PWR_ADC_S2F_BIT, 0, NULL, 0),
-       SND_SOC_DAPM_MIXER("Sto1 ADC MIXL", RT5670_STO1_ADC_DIG_VOL,
-                          RT5670_L_MUTE_SFT, 1, rt5670_sto1_adc_l_mix,
-                          ARRAY_SIZE(rt5670_sto1_adc_l_mix)),
-       SND_SOC_DAPM_MIXER("Sto1 ADC MIXR", RT5670_STO1_ADC_DIG_VOL,
-                          RT5670_R_MUTE_SFT, 1, rt5670_sto1_adc_r_mix,
-                          ARRAY_SIZE(rt5670_sto1_adc_r_mix)),
+       SND_SOC_DAPM_MIXER("Sto1 ADC MIXL", SND_SOC_NOPM, 0, 0,
+                          rt5670_sto1_adc_l_mix, ARRAY_SIZE(rt5670_sto1_adc_l_mix)),
+       SND_SOC_DAPM_MIXER("Sto1 ADC MIXR", SND_SOC_NOPM, 0, 0,
+                          rt5670_sto1_adc_r_mix, ARRAY_SIZE(rt5670_sto1_adc_r_mix)),
        SND_SOC_DAPM_MIXER("Sto2 ADC MIXL", SND_SOC_NOPM, 0, 0,
                           rt5670_sto2_adc_l_mix,
                           ARRAY_SIZE(rt5670_sto2_adc_l_mix)),
@@ -2999,6 +3071,16 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,
                dev_info(&i2c->dev, "quirk JD mode 3\n");
        }
 
+       /*
+        * Enable the emulated "DAC1 Playback Switch" by default to avoid
+        * muting the output with older UCM profiles.
+        */
+       rt5670->dac1_playback_switch_l = true;
+       rt5670->dac1_playback_switch_r = true;
+       /* The Power-On-Reset values for the DAC1 mixer have the DAC1 input enabled. */
+       rt5670->dac1_mixl_dac1_switch = true;
+       rt5670->dac1_mixr_dac1_switch = true;
+
        rt5670->regmap = devm_regmap_init_i2c(i2c, &rt5670_regmap);
        if (IS_ERR(rt5670->regmap)) {
                ret = PTR_ERR(rt5670->regmap);
index 56b13fe..6fb3c36 100644 (file)
 /* global definition */
 #define RT5670_L_MUTE                          (0x1 << 15)
 #define RT5670_L_MUTE_SFT                      15
-#define RT5670_VOL_L_MUTE                      (0x1 << 14)
-#define RT5670_VOL_L_SFT                       14
 #define RT5670_R_MUTE                          (0x1 << 7)
 #define RT5670_R_MUTE_SFT                      7
-#define RT5670_VOL_R_MUTE                      (0x1 << 6)
-#define RT5670_VOL_R_SFT                       6
 #define RT5670_L_VOL_MASK                      (0x3f << 8)
 #define RT5670_L_VOL_SFT                       8
 #define RT5670_R_VOL_MASK                      (0x3f)
@@ -2017,6 +2013,11 @@ struct rt5670_priv {
        int dsp_rate;
        int jack_type;
        int jack_type_saved;
+
+       bool dac1_mixl_dac1_switch;
+       bool dac1_mixr_dac1_switch;
+       bool dac1_playback_switch_l;
+       bool dac1_playback_switch_r;
 };
 
 void rt5670_jack_suspend(struct snd_soc_component *component);
index 85f7441..047f4e6 100644 (file)
@@ -895,6 +895,13 @@ static int rt711_probe(struct snd_soc_component *component)
        return 0;
 }
 
+static void rt711_remove(struct snd_soc_component *component)
+{
+       struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component);
+
+       regcache_cache_only(rt711->regmap, true);
+}
+
 static const struct snd_soc_component_driver soc_codec_dev_rt711 = {
        .probe = rt711_probe,
        .set_bias_level = rt711_set_bias_level,
@@ -905,6 +912,7 @@ static const struct snd_soc_component_driver soc_codec_dev_rt711 = {
        .dapm_routes = rt711_audio_map,
        .num_dapm_routes = ARRAY_SIZE(rt711_audio_map),
        .set_jack = rt711_set_jack_detect,
+       .remove = rt711_remove,
 };
 
 static int rt711_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
index 73551e3..6d9bb25 100644 (file)
@@ -71,7 +71,7 @@ static const struct reg_default sgtl5000_reg_defaults[] = {
        { SGTL5000_DAP_EQ_BASS_BAND4,           0x002f },
        { SGTL5000_DAP_MAIN_CHAN,               0x8000 },
        { SGTL5000_DAP_MIX_CHAN,                0x0000 },
-       { SGTL5000_DAP_AVC_CTRL,                0x0510 },
+       { SGTL5000_DAP_AVC_CTRL,                0x5100 },
        { SGTL5000_DAP_AVC_THRESHOLD,           0x1473 },
        { SGTL5000_DAP_AVC_ATTACK,              0x0028 },
        { SGTL5000_DAP_AVC_DECAY,               0x0050 },
diff --git a/sound/soc/codecs/sirf-audio-codec.h b/sound/soc/codecs/sirf-audio-codec.h
deleted file mode 100644 (file)
index a7fe268..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * SiRF inner codec controllers define
- *
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
- */
-
-#ifndef _SIRF_AUDIO_CODEC_H
-#define _SIRF_AUDIO_CODEC_H
-
-
-#define AUDIO_IC_CODEC_PWR                     (0x00E0)
-#define AUDIO_IC_CODEC_CTRL0                   (0x00E4)
-#define AUDIO_IC_CODEC_CTRL1                   (0x00E8)
-#define AUDIO_IC_CODEC_CTRL2                   (0x00EC)
-#define AUDIO_IC_CODEC_CTRL3                   (0x00F0)
-
-#define MICBIASEN              (1 << 3)
-
-#define IC_RDACEN              (1 << 0)
-#define IC_LDACEN              (1 << 1)
-#define IC_HSREN               (1 << 2)
-#define IC_HSLEN               (1 << 3)
-#define IC_SPEN                        (1 << 4)
-#define IC_CPEN                        (1 << 5)
-
-#define IC_HPRSELR             (1 << 6)
-#define IC_HPLSELR             (1 << 7)
-#define IC_HPRSELL             (1 << 8)
-#define IC_HPLSELL             (1 << 9)
-#define IC_SPSELR              (1 << 10)
-#define IC_SPSELL              (1 << 11)
-
-#define IC_MONOR               (1 << 12)
-#define IC_MONOL               (1 << 13)
-
-#define IC_RXOSRSEL            (1 << 28)
-#define IC_CPFREQ              (1 << 29)
-#define IC_HSINVEN             (1 << 30)
-
-#define IC_MICINREN            (1 << 0)
-#define IC_MICINLEN            (1 << 1)
-#define IC_MICIN1SEL           (1 << 2)
-#define IC_MICIN2SEL           (1 << 3)
-#define IC_MICDIFSEL           (1 << 4)
-#define        IC_LINEIN1SEL           (1 << 5)
-#define        IC_LINEIN2SEL           (1 << 6)
-#define        IC_RADCEN               (1 << 7)
-#define        IC_LADCEN               (1 << 8)
-#define        IC_ALM                  (1 << 9)
-
-#define IC_DIGMICEN             (1 << 22)
-#define IC_DIGMICFREQ           (1 << 23)
-#define IC_ADC14B_12            (1 << 24)
-#define IC_FIRDAC_HSL_EN        (1 << 25)
-#define IC_FIRDAC_HSR_EN        (1 << 26)
-#define IC_FIRDAC_LOUT_EN       (1 << 27)
-#define IC_POR                  (1 << 28)
-#define IC_CODEC_CLK_EN         (1 << 29)
-#define IC_HP_3DB_BOOST         (1 << 30)
-
-#define IC_ADC_LEFT_GAIN_SHIFT 16
-#define IC_ADC_RIGHT_GAIN_SHIFT 10
-#define IC_ADC_GAIN_MASK       0x3F
-#define IC_MIC_MAX_GAIN                0x39
-
-#define IC_RXPGAR_MASK         0x3F
-#define IC_RXPGAR_SHIFT                14
-#define IC_RXPGAL_MASK         0x3F
-#define IC_RXPGAL_SHIFT                21
-#define IC_RXPGAR              0x7B
-#define IC_RXPGAL              0x7B
-
-#define AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK     0x3F
-#define AUDIO_PORT_TX_FIFO_SC_OFFSET    0
-#define AUDIO_PORT_TX_FIFO_LC_OFFSET    10
-#define AUDIO_PORT_TX_FIFO_HC_OFFSET    20
-
-#define TX_FIFO_SC(x)           (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \
-                               << AUDIO_PORT_TX_FIFO_SC_OFFSET)
-#define TX_FIFO_LC(x)           (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \
-                               << AUDIO_PORT_TX_FIFO_LC_OFFSET)
-#define TX_FIFO_HC(x)           (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \
-                               << AUDIO_PORT_TX_FIFO_HC_OFFSET)
-
-#define AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK     0x0F
-#define AUDIO_PORT_RX_FIFO_SC_OFFSET    0
-#define AUDIO_PORT_RX_FIFO_LC_OFFSET    10
-#define AUDIO_PORT_RX_FIFO_HC_OFFSET    20
-
-#define RX_FIFO_SC(x)           (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \
-                               << AUDIO_PORT_RX_FIFO_SC_OFFSET)
-#define RX_FIFO_LC(x)           (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \
-                               << AUDIO_PORT_RX_FIFO_LC_OFFSET)
-#define RX_FIFO_HC(x)           (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \
-                               << AUDIO_PORT_RX_FIFO_HC_OFFSET)
-#define AUDIO_PORT_IC_CODEC_TX_CTRL            (0x00F4)
-#define AUDIO_PORT_IC_CODEC_RX_CTRL            (0x00F8)
-
-#define AUDIO_PORT_IC_TXFIFO_OP                        (0x00FC)
-#define AUDIO_PORT_IC_TXFIFO_LEV_CHK           (0x0100)
-#define AUDIO_PORT_IC_TXFIFO_STS               (0x0104)
-#define AUDIO_PORT_IC_TXFIFO_INT               (0x0108)
-#define AUDIO_PORT_IC_TXFIFO_INT_MSK           (0x010C)
-
-#define AUDIO_PORT_IC_RXFIFO_OP                        (0x0110)
-#define AUDIO_PORT_IC_RXFIFO_LEV_CHK           (0x0114)
-#define AUDIO_PORT_IC_RXFIFO_STS               (0x0118)
-#define AUDIO_PORT_IC_RXFIFO_INT               (0x011C)
-#define AUDIO_PORT_IC_RXFIFO_INT_MSK           (0x0120)
-
-#define AUDIO_FIFO_START               (1 << 0)
-#define AUDIO_FIFO_RESET               (1 << 1)
-
-#define AUDIO_FIFO_FULL                        (1 << 0)
-#define AUDIO_FIFO_EMPTY               (1 << 1)
-#define AUDIO_FIFO_OFLOW               (1 << 2)
-#define AUDIO_FIFO_UFLOW               (1 << 3)
-
-#define IC_TX_ENABLE           (0x03)
-#define IC_RX_ENABLE_MONO      (0x01)
-#define IC_RX_ENABLE_STEREO    (0x03)
-
-#endif /*__SIRF_AUDIO_CODEC_H*/
index 40f682f..d18ae5e 100644 (file)
@@ -1873,6 +1873,12 @@ static int wcd934x_set_channel_map(struct snd_soc_dai *dai,
 
        wcd = snd_soc_component_get_drvdata(dai->component);
 
+       if (tx_num > WCD934X_TX_MAX || rx_num > WCD934X_RX_MAX) {
+               dev_err(wcd->dev, "Invalid tx %d or rx %d channel count\n",
+                       tx_num, rx_num);
+               return -EINVAL;
+       }
+
        if (!tx_slot || !rx_slot) {
                dev_err(wcd->dev, "Invalid tx_slot=%p, rx_slot=%p\n",
                        tx_slot, rx_slot);
index 5781174..ad8af3f 100644 (file)
@@ -878,6 +878,7 @@ static int fsl_ssi_hw_free(struct snd_pcm_substream *substream,
 static int _fsl_ssi_set_dai_fmt(struct fsl_ssi *ssi, unsigned int fmt)
 {
        u32 strcr = 0, scr = 0, stcr, srcr, mask;
+       unsigned int slots;
 
        ssi->dai_fmt = fmt;
 
@@ -909,10 +910,11 @@ static int _fsl_ssi_set_dai_fmt(struct fsl_ssi *ssi, unsigned int fmt)
                        return -EINVAL;
                }
 
+               slots = ssi->slots ? : 2;
                regmap_update_bits(ssi->regs, REG_SSI_STCCR,
-                                  SSI_SxCCR_DC_MASK, SSI_SxCCR_DC(2));
+                                  SSI_SxCCR_DC_MASK, SSI_SxCCR_DC(slots));
                regmap_update_bits(ssi->regs, REG_SSI_SRCCR,
-                                  SSI_SxCCR_DC_MASK, SSI_SxCCR_DC(2));
+                                  SSI_SxCCR_DC_MASK, SSI_SxCCR_DC(slots));
 
                /* Data on rising edge of bclk, frame low, 1clk before data */
                strcr |= SSI_STCR_TFSI | SSI_STCR_TSCKP | SSI_STCR_TEFS;
index ab31045..6cada4c 100644 (file)
@@ -172,15 +172,16 @@ int asoc_simple_parse_clk(struct device *dev,
         *  or device's module clock.
         */
        clk = devm_get_clk_from_child(dev, node, NULL);
-       if (IS_ERR(clk))
-               clk = devm_get_clk_from_child(dev, dlc->of_node, NULL);
-
        if (!IS_ERR(clk)) {
-               simple_dai->clk = clk;
                simple_dai->sysclk = clk_get_rate(clk);
-       } else if (!of_property_read_u32(node, "system-clock-frequency",
-                                        &val)) {
+
+               simple_dai->clk = clk;
+       } else if (!of_property_read_u32(node, "system-clock-frequency", &val)) {
                simple_dai->sysclk = val;
+       } else {
+               clk = devm_get_clk_from_child(dev, dlc->of_node, NULL);
+               if (!IS_ERR(clk))
+                       simple_dai->sysclk = clk_get_rate(clk);
        }
 
        if (of_property_read_bool(node, "system-clock-direction-out"))
index 782f2b4..5d48cc3 100644 (file)
@@ -581,7 +581,7 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
                },
                .driver_data = (void *)(BYT_RT5640_DMIC1_MAP |
                                        BYT_RT5640_JD_SRC_JD1_IN4P |
-                                       BYT_RT5640_OVCD_TH_1500UA |
+                                       BYT_RT5640_OVCD_TH_2000UA |
                                        BYT_RT5640_OVCD_SF_0P75 |
                                        BYT_RT5640_MCLK_EN),
        },
index f5de1d7..f3bebed 100644 (file)
@@ -555,7 +555,9 @@ static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream,
 
        /* set tdm */
        if (tdm_priv->bck_invert)
-               tdm_con |= 1 << BCK_INVERSE_SFT;
+               regmap_update_bits(afe->regmap, AUDIO_TOP_CON3,
+                                  BCK_INVERSE_MASK_SFT,
+                                  0x1 << BCK_INVERSE_SFT);
 
        if (tdm_priv->lck_invert)
                tdm_con |= 1 << LRCK_INVERSE_SFT;
index 562f25c..b9fb80d 100644 (file)
@@ -21,6 +21,11 @@ enum {
 /*****************************************************************************
  *                  R E G I S T E R       D E F I N I T I O N
  *****************************************************************************/
+/* AUDIO_TOP_CON3 */
+#define BCK_INVERSE_SFT                              3
+#define BCK_INVERSE_MASK                             0x1
+#define BCK_INVERSE_MASK_SFT                         (0x1 << 3)
+
 /* AFE_DAC_CON0 */
 #define VUL12_ON_SFT                                   31
 #define VUL12_ON_MASK                                  0x1
@@ -2079,9 +2084,6 @@ enum {
 #define TDM_EN_SFT                                     0
 #define TDM_EN_MASK                                    0x1
 #define TDM_EN_MASK_SFT                                (0x1 << 0)
-#define BCK_INVERSE_SFT                                1
-#define BCK_INVERSE_MASK                               0x1
-#define BCK_INVERSE_MASK_SFT                           (0x1 << 1)
 #define LRCK_INVERSE_SFT                               2
 #define LRCK_INVERSE_MASK                              0x1
 #define LRCK_INVERSE_MASK_SFT                          (0x1 << 2)
index c642e5f..be360a4 100644 (file)
@@ -739,7 +739,7 @@ static void of_lpass_cpu_parse_dai_data(struct device *dev,
 
        for_each_child_of_node(dev->of_node, node) {
                ret = of_property_read_u32(node, "reg", &id);
-               if (ret || id < 0 || id >= data->variant->num_dai) {
+               if (ret || id < 0) {
                        dev_err(dev, "valid dai id not found: %d\n", ret);
                        continue;
                }
index 6c2760e..153e9b2 100644 (file)
 #define SPK_TDM_RX_MASK         0x03
 #define NUM_TDM_SLOTS           8
 #define SLIM_MAX_TX_PORTS 16
-#define SLIM_MAX_RX_PORTS 16
+#define SLIM_MAX_RX_PORTS 13
 #define WCD934X_DEFAULT_MCLK_RATE      9600000
 
 struct sdm845_snd_data {
        struct snd_soc_jack jack;
        bool jack_setup;
-       bool stream_prepared[SLIM_MAX_RX_PORTS];
+       bool stream_prepared[AFE_PORT_MAX];
        struct snd_soc_card *card;
        uint32_t pri_mi2s_clk_count;
        uint32_t sec_mi2s_clk_count;
        uint32_t quat_tdm_clk_count;
-       struct sdw_stream_runtime *sruntime[SLIM_MAX_RX_PORTS];
+       struct sdw_stream_runtime *sruntime[AFE_PORT_MAX];
 };
 
 static unsigned int tdm_slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28};
index f6d4e99..0cffc95 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/of.h>
 #include <linux/of_graph.h>
 #include <linux/dmi.h>
+#include <linux/acpi.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -1573,6 +1574,9 @@ int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour)
        if (card->long_name)
                return 0; /* long name already set by driver or from DMI */
 
+       if (!is_acpi_device_node(card->dev->fwnode))
+               return 0;
+
        /* make up dmi long name as: vendor-product-version-board */
        vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
        if (!vendor || !is_dmi_valid(vendor)) {
index 5788fe3..c3b757c 100644 (file)
@@ -207,7 +207,7 @@ int hda_dsp_core_power_down(struct snd_sof_dev *sdev, unsigned int core_mask)
 
        ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
                                HDA_DSP_REG_ADSPCS, adspcs,
-                               !(adspcs & HDA_DSP_ADSPCS_SPA_MASK(core_mask)),
+                               !(adspcs & HDA_DSP_ADSPCS_CPA_MASK(core_mask)),
                                HDA_DSP_REG_POLL_INTERVAL_US,
                                HDA_DSP_PD_TIMEOUT * USEC_PER_MSEC);
        if (ret < 0)
index 1d29b1f..0c096db 100644 (file)
@@ -897,6 +897,7 @@ free_streams:
 /* dsp_unmap: not currently used */
        iounmap(sdev->bar[HDA_DSP_BAR]);
 hdac_bus_unmap:
+       platform_device_unregister(hdev->dmic_dev);
        iounmap(bus->remap_addr);
        hda_codec_i915_exit(sdev);
 err:
index 9d0da5f..d24ae00 100644 (file)
@@ -62,7 +62,6 @@ MODULE_PARM_DESC(enable, "Enable Sun AMD7930 soundcard.");
 MODULE_AUTHOR("Thomas K. Dyas and David S. Miller");
 MODULE_DESCRIPTION("Sun AMD7930");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Sun,AMD7930}}");
 
 /* Device register layout.  */
 
index 0eed5f7..35c1780 100644 (file)
@@ -52,7 +52,6 @@ MODULE_PARM_DESC(enable, "Enable Sun CS4231 soundcard.");
 MODULE_AUTHOR("Jaroslav Kysela, Derrick J. Brashear and David S. Miller");
 MODULE_DESCRIPTION("Sun CS4231");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Sun,CS4231}}");
 
 #ifdef SBUS_SUPPORT
 struct sbus_dma_info {
index 5a6fb66..b055f58 100644 (file)
@@ -76,7 +76,6 @@
 MODULE_AUTHOR("Rudolf Koenig, Brent Baccala and Martin Habets");
 MODULE_DESCRIPTION("Sun DBRI");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Sun,DBRI}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
index 08c6e6a..33e9621 100644 (file)
@@ -26,7 +26,6 @@
 MODULE_AUTHOR("Torsten Schenk <torsten.schenk@zoho.com>");
 MODULE_DESCRIPTION("TerraTec DMX 6Fire USB audio driver");
 MODULE_LICENSE("GPL v2");
-MODULE_SUPPORTED_DEVICE("{{TerraTec,DMX 6Fire USB}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for card */
index e03481c..49f63f8 100644 (file)
 MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
 MODULE_DESCRIPTION("caiaq USB audio");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Native Instruments,RigKontrol2},"
-                        "{Native Instruments,RigKontrol3},"
-                        "{Native Instruments,Kore Controller},"
-                        "{Native Instruments,Kore Controller 2},"
-                        "{Native Instruments,Audio Kontrol 1},"
-                        "{Native Instruments,Audio 2 DJ},"
-                        "{Native Instruments,Audio 4 DJ},"
-                        "{Native Instruments,Audio 8 DJ},"
-                        "{Native Instruments,Traktor Audio 2},"
-                        "{Native Instruments,Session I/O},"
-                        "{Native Instruments,GuitarRig mobile},"
-                        "{Native Instruments,Traktor Kontrol X1},"
-                        "{Native Instruments,Traktor Kontrol S4},"
-                        "{Native Instruments,Maschine Controller}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
 static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */
index 85ed850..0826a43 100644 (file)
@@ -58,8 +58,6 @@
 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
 MODULE_DESCRIPTION("USB Audio");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Generic,USB Audio}}");
-
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
@@ -830,6 +828,9 @@ static int usb_audio_probe(struct usb_interface *intf,
                snd_media_device_create(chip, intf);
        }
 
+       if (quirk)
+               chip->quirk_type = quirk->type;
+
        usb_chip[chip->index] = chip;
        chip->intf[chip->num_interfaces] = intf;
        chip->num_interfaces++;
@@ -904,6 +905,9 @@ static void usb_audio_disconnect(struct usb_interface *intf)
                }
        }
 
+       if (chip->quirk_type & QUIRK_SETUP_DISABLE_AUTOSUSPEND)
+               usb_enable_autosuspend(interface_to_usbdev(intf));
+
        chip->num_interfaces--;
        if (chip->num_interfaces <= 0) {
                usb_chip[chip->index] = NULL;
index c282418..95385e9 100644 (file)
@@ -21,23 +21,6 @@ MODULE_AUTHOR("Michael Trimarchi <michael@amarulasolutions.com>");
 MODULE_AUTHOR("Antonio Ospite <ao2@amarulasolutions.com>");
 MODULE_DESCRIPTION("M2Tech hiFace USB-SPDIF audio driver");
 MODULE_LICENSE("GPL v2");
-MODULE_SUPPORTED_DEVICE("{{M2Tech,Young},"
-                        "{M2Tech,hiFace},"
-                        "{M2Tech,North Star},"
-                        "{M2Tech,W4S Young},"
-                        "{M2Tech,Corrson},"
-                        "{M2Tech,AUDIA},"
-                        "{M2Tech,SL Audio},"
-                        "{M2Tech,Empirical},"
-                        "{M2Tech,Rockna},"
-                        "{M2Tech,Pathos},"
-                        "{M2Tech,Metronome},"
-                        "{M2Tech,CAD},"
-                        "{M2Tech,Audio Esclusive},"
-                        "{M2Tech,Rotel},"
-                        "{M2Tech,Eeaudio},"
-                        "{The Chord Company,CHORD},"
-                        "{AVA Group A/S,Vitus}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for card */
index 6b30155..5834d1d 100644 (file)
@@ -19,7 +19,6 @@
 MODULE_DESCRIPTION("Edirol UA-101/1000 driver");
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
 MODULE_LICENSE("GPL v2");
-MODULE_SUPPORTED_DEVICE("{{Edirol,UA-101},{Edirol,UA-1000}}");
 
 /*
  * Should not be lower than the minimum scheduling delay of the host
index 08873d2..ffd9223 100644 (file)
@@ -2883,7 +2883,7 @@ static int snd_djm_controls_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_v
        u8 group = (private_value & SND_DJM_GROUP_MASK) >> SND_DJM_GROUP_SHIFT;
        u16 value = elem->value.enumerated.item[0];
 
-       kctl->private_value = ((device << SND_DJM_DEVICE_SHIFT) |
+       kctl->private_value = (((unsigned long)device << SND_DJM_DEVICE_SHIFT) |
                              (group << SND_DJM_GROUP_SHIFT) |
                              value);
 
@@ -2921,7 +2921,7 @@ static int snd_djm_controls_create(struct usb_mixer_interface *mixer,
                value = device->controls[i].default_value;
                knew.name = device->controls[i].name;
                knew.private_value = (
-                       (device_idx << SND_DJM_DEVICE_SHIFT) |
+                       ((unsigned long)device_idx << SND_DJM_DEVICE_SHIFT) |
                        (i << SND_DJM_GROUP_SHIFT) |
                        value);
                err = snd_djm_controls_update(mixer, device_idx, i, value);
index 737b272..d3001fb 100644 (file)
@@ -547,7 +547,7 @@ static int setup_disable_autosuspend(struct snd_usb_audio *chip,
                                       struct usb_driver *driver,
                                       const struct snd_usb_audio_quirk *quirk)
 {
-       driver->supports_autosuspend = 0;
+       usb_disable_autosuspend(interface_to_usbdev(iface));
        return 1;       /* Continue with creating streams and mixer */
 }
 
@@ -1520,6 +1520,7 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip)
        case USB_ID(0x1901, 0x0191): /* GE B850V3 CP2114 audio interface */
        case USB_ID(0x21b4, 0x0081): /* AudioQuest DragonFly */
        case USB_ID(0x2912, 0x30c8): /* Audioengine D1 */
+       case USB_ID(0x413c, 0xa506): /* Dell AE515 sound bar */
                return true;
        }
 
@@ -1670,6 +1671,14 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
            && (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
                msleep(20);
 
+       /*
+        * Plantronics headsets (C320, C320-M, etc) need a delay to avoid
+        * random microhpone failures.
+        */
+       if (USB_ID_VENDOR(chip->usb_id) == 0x047f &&
+           (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
+               msleep(20);
+
        /* Zoom R16/24, many Logitech(at least H650e/H570e/BCC950),
         * Jabra 550a, Kingston HyperX needs a tiny delay here,
         * otherwise requests like get/set frequency return
index 215c177..60b9dd7 100644 (file)
@@ -27,6 +27,7 @@ struct snd_usb_audio {
        struct snd_card *card;
        struct usb_interface *intf[MAX_CARD_INTERFACES];
        u32 usb_id;
+       uint16_t quirk_type;
        struct mutex mutex;
        unsigned int system_suspend;
        atomic_t active;
index c541581..3cd28d2 100644 (file)
 MODULE_AUTHOR("Karsten Wiese <annabellesgarden@yahoo.de>");
 MODULE_DESCRIPTION("TASCAM "NAME_ALLCAPS" Version 0.8.7.2");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{TASCAM(0x1604),"NAME_ALLCAPS"(0x8001)(0x8005)(0x8007)}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
 static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */
index 1d66c3a..33b12aa 100644 (file)
@@ -1887,4 +1887,3 @@ MODULE_AUTHOR("Vaibhav Agarwal <vaibhav.agarwal@intel.com>");
 MODULE_AUTHOR("Jerome Anand <jerome.anand@intel.com>");
 MODULE_DESCRIPTION("Intel HDMI Audio driver");
 MODULE_LICENSE("GPL v2");
-MODULE_SUPPORTED_DEVICE("{Intel,Intel_HAD}");
index 228d820..2cb0a19 100644 (file)
@@ -391,4 +391,3 @@ module_exit(xen_drv_fini);
 MODULE_DESCRIPTION("Xen virtual sound device frontend");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("xen:" XENSND_DRIVER_NAME);
-MODULE_SUPPORTED_DEVICE("{{ALSA,Virtual soundcard}}");
index 543dd70..ad64d67 100644 (file)
 #define ACR_SIZE       4
 
 
-#define PTRACE_OLDSETOPTIONS        21
-
+#define PTRACE_OLDSETOPTIONS           21
+#define PTRACE_SYSEMU                  31
+#define PTRACE_SYSEMU_SINGLESTEP       32
 #ifndef __ASSEMBLY__
 #include <linux/stddef.h>
 #include <linux/types.h>
index 84b8878..cc96e26 100644 (file)
@@ -13,7 +13,7 @@
 /*
  * Defines x86 CPU feature bits
  */
-#define NCAPINTS                       19         /* N 32-bit words worth of info */
+#define NCAPINTS                       20         /* N 32-bit words worth of info */
 #define NBUGINTS                       1          /* N 32-bit bug flags */
 
 /*
@@ -96,7 +96,7 @@
 #define X86_FEATURE_SYSCALL32          ( 3*32+14) /* "" syscall in IA32 userspace */
 #define X86_FEATURE_SYSENTER32         ( 3*32+15) /* "" sysenter in IA32 userspace */
 #define X86_FEATURE_REP_GOOD           ( 3*32+16) /* REP microcode works well */
-#define X86_FEATURE_SME_COHERENT       ( 3*32+17) /* "" AMD hardware-enforced cache coherency */
+/* FREE!                                ( 3*32+17) */
 #define X86_FEATURE_LFENCE_RDTSC       ( 3*32+18) /* "" LFENCE synchronizes RDTSC */
 #define X86_FEATURE_ACC_POWER          ( 3*32+19) /* AMD Accumulated Power Mechanism */
 #define X86_FEATURE_NOPL               ( 3*32+20) /* The NOPL (0F 1F) instructions */
 #define X86_FEATURE_INVPCID_SINGLE     ( 7*32+ 7) /* Effectively INVPCID && CR4.PCIDE=1 */
 #define X86_FEATURE_HW_PSTATE          ( 7*32+ 8) /* AMD HW-PState */
 #define X86_FEATURE_PROC_FEEDBACK      ( 7*32+ 9) /* AMD ProcFeedbackInterface */
-#define X86_FEATURE_SME                        ( 7*32+10) /* AMD Secure Memory Encryption */
+/* FREE!                                ( 7*32+10) */
 #define X86_FEATURE_PTI                        ( 7*32+11) /* Kernel Page Table Isolation enabled */
 #define X86_FEATURE_RETPOLINE          ( 7*32+12) /* "" Generic Retpoline mitigation for Spectre variant 2 */
 #define X86_FEATURE_RETPOLINE_AMD      ( 7*32+13) /* "" AMD Retpoline mitigation for Spectre variant 2 */
 #define X86_FEATURE_SSBD               ( 7*32+17) /* Speculative Store Bypass Disable */
 #define X86_FEATURE_MBA                        ( 7*32+18) /* Memory Bandwidth Allocation */
 #define X86_FEATURE_RSB_CTXSW          ( 7*32+19) /* "" Fill RSB on context switches */
-#define X86_FEATURE_SEV                        ( 7*32+20) /* AMD Secure Encrypted Virtualization */
+/* FREE!                                ( 7*32+20) */
 #define X86_FEATURE_USE_IBPB           ( 7*32+21) /* "" Indirect Branch Prediction Barrier enabled */
 #define X86_FEATURE_USE_IBRS_FW                ( 7*32+22) /* "" Use IBRS during runtime firmware calls */
 #define X86_FEATURE_SPEC_STORE_BYPASS_DISABLE  ( 7*32+23) /* "" Disable Speculative Store Bypass. */
 #define X86_FEATURE_EPT_AD             ( 8*32+17) /* Intel Extended Page Table access-dirty bit */
 #define X86_FEATURE_VMCALL             ( 8*32+18) /* "" Hypervisor supports the VMCALL instruction */
 #define X86_FEATURE_VMW_VMMCALL                ( 8*32+19) /* "" VMware prefers VMMCALL hypercall instruction */
-#define X86_FEATURE_SEV_ES             ( 8*32+20) /* AMD Secure Encrypted Virtualization - Encrypted State */
-#define X86_FEATURE_VM_PAGE_FLUSH      ( 8*32+21) /* "" VM Page Flush MSR is supported */
 
 /* Intel-defined CPU features, CPUID level 0x00000007:0 (EBX), word 9 */
 #define X86_FEATURE_FSGSBASE           ( 9*32+ 0) /* RDFSBASE, WRFSBASE, RDGSBASE, WRGSBASE instructions*/
 #define X86_FEATURE_PER_THREAD_MBA     (11*32+ 7) /* "" Per-thread Memory Bandwidth Allocation */
 
 /* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */
+#define X86_FEATURE_AVX_VNNI           (12*32+ 4) /* AVX VNNI instructions */
 #define X86_FEATURE_AVX512_BF16                (12*32+ 5) /* AVX512 BFLOAT16 instructions */
 
 /* AMD-defined CPU features, CPUID level 0x80000008 (EBX), word 13 */
 #define X86_FEATURE_AVIC               (15*32+13) /* Virtual Interrupt Controller */
 #define X86_FEATURE_V_VMSAVE_VMLOAD    (15*32+15) /* Virtual VMSAVE VMLOAD */
 #define X86_FEATURE_VGIF               (15*32+16) /* Virtual GIF */
+#define X86_FEATURE_SVME_ADDR_CHK      (15*32+28) /* "" SVME addr check */
 
 /* Intel-defined CPU features, CPUID level 0x00000007:0 (ECX), word 16 */
 #define X86_FEATURE_AVX512VBMI         (16*32+ 1) /* AVX512 Vector Bit Manipulation instructions*/
 #define X86_FEATURE_CORE_CAPABILITIES  (18*32+30) /* "" IA32_CORE_CAPABILITIES MSR */
 #define X86_FEATURE_SPEC_CTRL_SSBD     (18*32+31) /* "" Speculative Store Bypass Disable */
 
+/* AMD-defined memory encryption features, CPUID level 0x8000001f (EAX), word 19 */
+#define X86_FEATURE_SME                        (19*32+ 0) /* AMD Secure Memory Encryption */
+#define X86_FEATURE_SEV                        (19*32+ 1) /* AMD Secure Encrypted Virtualization */
+#define X86_FEATURE_VM_PAGE_FLUSH      (19*32+ 2) /* "" VM Page Flush MSR is supported */
+#define X86_FEATURE_SEV_ES             (19*32+ 3) /* AMD Secure Encrypted Virtualization - Encrypted State */
+#define X86_FEATURE_SME_COHERENT       (19*32+10) /* "" AMD hardware-enforced cache coherency */
+
 /*
  * BUG word(s)
  */
index 8e76d37..5a3022c 100644 (file)
@@ -112,6 +112,7 @@ struct kvm_ioapic_state {
 #define KVM_NR_IRQCHIPS          3
 
 #define KVM_RUN_X86_SMM                 (1 << 0)
+#define KVM_RUN_X86_BUS_LOCK     (1 << 1)
 
 /* for KVM_GET_REGS and KVM_SET_REGS */
 struct kvm_regs {
index ada955c..b8e650a 100644 (file)
@@ -89,6 +89,7 @@
 #define EXIT_REASON_XRSTORS             64
 #define EXIT_REASON_UMWAIT              67
 #define EXIT_REASON_TPAUSE              68
+#define EXIT_REASON_BUS_LOCK            74
 
 #define VMX_EXIT_REASONS \
        { EXIT_REASON_EXCEPTION_NMI,         "EXCEPTION_NMI" }, \
        { EXIT_REASON_XSAVES,                "XSAVES" }, \
        { EXIT_REASON_XRSTORS,               "XRSTORS" }, \
        { EXIT_REASON_UMWAIT,                "UMWAIT" }, \
-       { EXIT_REASON_TPAUSE,                "TPAUSE" }
+       { EXIT_REASON_TPAUSE,                "TPAUSE" }, \
+       { EXIT_REASON_BUS_LOCK,              "BUS_LOCK" }
 
 #define VMX_EXIT_REASON_FLAGS \
        { VMX_EXIT_REASONS_FAILED_VMENTRY,      "FAILED_VMENTRY" }
index 7409d78..80d966c 100644 (file)
@@ -260,6 +260,11 @@ static struct btf_id *add_symbol(struct rb_root *root, char *name, size_t size)
        return btf_id__add(root, id, false);
 }
 
+/* Older libelf.h and glibc elf.h might not yet define the ELF compression types. */
+#ifndef SHF_COMPRESSED
+#define SHF_COMPRESSED (1 << 11) /* Section with compressed data. */
+#endif
+
 /*
  * The data of compressed section should be aligned to 4
  * (for 32bit) or 8 (for 64 bit) bytes. The binutils ld
index bae48e6..5ed41b9 100644 (file)
@@ -30,12 +30,18 @@ build     := -f $(srctree)/tools/build/Makefile.build dir=. obj
 
 all: $(OUTPUT)fixdep
 
+# Make sure there's anything to clean,
+# feature contains check for existing OUTPUT
+TMP_O := $(if $(OUTPUT),$(OUTPUT)/feature,./)
+
 clean:
        $(call QUIET_CLEAN, fixdep)
        $(Q)find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
        $(Q)rm -f $(OUTPUT)fixdep
        $(call QUIET_CLEAN, feature-detect)
-       $(Q)$(MAKE) -C feature/ clean >/dev/null
+ifneq ($(wildcard $(TMP_O)),)
+       $(Q)$(MAKE) -C feature OUTPUT=$(TMP_O) clean >/dev/null
+endif
 
 $(OUTPUT)fixdep-in.o: FORCE
        $(Q)$(MAKE) $(build)=fixdep
index b0e35ee..4ac5c08 100644 (file)
 #define CORESIGHT_ETM_PMU_NAME "cs_etm"
 #define CORESIGHT_ETM_PMU_SEED  0x10
 
-/* ETMv3.5/PTM's ETMCR config bit */
-#define ETM_OPT_CYCACC  12
-#define ETM_OPT_CTXTID 14
-#define ETM_OPT_TS      28
-#define ETM_OPT_RETSTK 29
+/*
+ * Below are the definition of bit offsets for perf option, and works as
+ * arbitrary values for all ETM versions.
+ *
+ * Most of them are orignally from ETMv3.5/PTM's ETMCR config, therefore,
+ * ETMv3.5/PTM doesn't define ETMCR config bits with prefix "ETM3_" and
+ * directly use below macros as config bits.
+ */
+#define ETM_OPT_CYCACC         12
+#define ETM_OPT_CTXTID         14
+#define ETM_OPT_CTXTID2                15
+#define ETM_OPT_TS             28
+#define ETM_OPT_RETSTK         29
 
 /* ETMv4 CONFIGR programming bits for the ETM OPTs */
 #define ETM4_CFG_BIT_CYCACC    4
 #define ETM4_CFG_BIT_CTXTID    6
+#define ETM4_CFG_BIT_VMID      7
 #define ETM4_CFG_BIT_TS                11
 #define ETM4_CFG_BIT_RETSTK    12
+#define ETM4_CFG_BIT_VMID_OPT  15
 
 static inline int coresight_get_trace_id(int cpu)
 {
index 808b48a..0827037 100644 (file)
@@ -1,11 +1,10 @@
-/**
- * \file drm.h
+/*
  * Header for the Direct Rendering Manager
  *
- * \author Rickard E. (Rik) Faith <faith@valinux.com>
+ * Author: Rickard E. (Rik) Faith <faith@valinux.com>
  *
- * \par Acknowledgments:
- * Dec 1999, Richard Henderson <rth@twiddle.net>, move to generic \c cmpxchg.
+ * Acknowledgments:
+ * Dec 1999, Richard Henderson <rth@twiddle.net>, move to generic cmpxchg.
  */
 
 /*
@@ -85,7 +84,7 @@ typedef unsigned int drm_context_t;
 typedef unsigned int drm_drawable_t;
 typedef unsigned int drm_magic_t;
 
-/**
+/*
  * Cliprect.
  *
  * \warning: If you change this structure, make sure you change
@@ -101,7 +100,7 @@ struct drm_clip_rect {
        unsigned short y2;
 };
 
-/**
+/*
  * Drawable information.
  */
 struct drm_drawable_info {
@@ -109,7 +108,7 @@ struct drm_drawable_info {
        struct drm_clip_rect *rects;
 };
 
-/**
+/*
  * Texture region,
  */
 struct drm_tex_region {
@@ -120,7 +119,7 @@ struct drm_tex_region {
        unsigned int age;
 };
 
-/**
+/*
  * Hardware lock.
  *
  * The lock structure is a simple cache-line aligned integer.  To avoid
@@ -132,7 +131,7 @@ struct drm_hw_lock {
        char padding[60];                       /**< Pad to cache line */
 };
 
-/**
+/*
  * DRM_IOCTL_VERSION ioctl argument type.
  *
  * \sa drmGetVersion().
@@ -149,7 +148,7 @@ struct drm_version {
        char __user *desc;        /**< User-space buffer to hold desc */
 };
 
-/**
+/*
  * DRM_IOCTL_GET_UNIQUE ioctl argument type.
  *
  * \sa drmGetBusid() and drmSetBusId().
@@ -168,7 +167,7 @@ struct drm_block {
        int unused;
 };
 
-/**
+/*
  * DRM_IOCTL_CONTROL ioctl argument type.
  *
  * \sa drmCtlInstHandler() and drmCtlUninstHandler().
@@ -183,7 +182,7 @@ struct drm_control {
        int irq;
 };
 
-/**
+/*
  * Type of memory to map.
  */
 enum drm_map_type {
@@ -195,7 +194,7 @@ enum drm_map_type {
        _DRM_CONSISTENT = 5       /**< Consistent memory for PCI DMA */
 };
 
-/**
+/*
  * Memory mapping flags.
  */
 enum drm_map_flags {
@@ -214,7 +213,7 @@ struct drm_ctx_priv_map {
        void *handle;            /**< Handle of map */
 };
 
-/**
+/*
  * DRM_IOCTL_GET_MAP, DRM_IOCTL_ADD_MAP and DRM_IOCTL_RM_MAP ioctls
  * argument type.
  *
@@ -231,7 +230,7 @@ struct drm_map {
        /*   Private data */
 };
 
-/**
+/*
  * DRM_IOCTL_GET_CLIENT ioctl argument type.
  */
 struct drm_client {
@@ -263,7 +262,7 @@ enum drm_stat_type {
            /* Add to the *END* of the list */
 };
 
-/**
+/*
  * DRM_IOCTL_GET_STATS ioctl argument type.
  */
 struct drm_stats {
@@ -274,7 +273,7 @@ struct drm_stats {
        } data[15];
 };
 
-/**
+/*
  * Hardware locking flags.
  */
 enum drm_lock_flags {
@@ -289,7 +288,7 @@ enum drm_lock_flags {
        _DRM_HALT_CUR_QUEUES = 0x20  /**< Halt all current queues */
 };
 
-/**
+/*
  * DRM_IOCTL_LOCK, DRM_IOCTL_UNLOCK and DRM_IOCTL_FINISH ioctl argument type.
  *
  * \sa drmGetLock() and drmUnlock().
@@ -299,7 +298,7 @@ struct drm_lock {
        enum drm_lock_flags flags;
 };
 
-/**
+/*
  * DMA flags
  *
  * \warning
@@ -328,7 +327,7 @@ enum drm_dma_flags {
        _DRM_DMA_LARGER_OK = 0x40     /**< Larger-than-requested buffers OK */
 };
 
-/**
+/*
  * DRM_IOCTL_ADD_BUFS and DRM_IOCTL_MARK_BUFS ioctl argument type.
  *
  * \sa drmAddBufs().
@@ -351,7 +350,7 @@ struct drm_buf_desc {
                                  */
 };
 
-/**
+/*
  * DRM_IOCTL_INFO_BUFS ioctl argument type.
  */
 struct drm_buf_info {
@@ -359,7 +358,7 @@ struct drm_buf_info {
        struct drm_buf_desc __user *list;
 };
 
-/**
+/*
  * DRM_IOCTL_FREE_BUFS ioctl argument type.
  */
 struct drm_buf_free {
@@ -367,7 +366,7 @@ struct drm_buf_free {
        int __user *list;
 };
 
-/**
+/*
  * Buffer information
  *
  * \sa drm_buf_map.
@@ -379,7 +378,7 @@ struct drm_buf_pub {
        void __user *address;          /**< Address of buffer */
 };
 
-/**
+/*
  * DRM_IOCTL_MAP_BUFS ioctl argument type.
  */
 struct drm_buf_map {
@@ -392,7 +391,7 @@ struct drm_buf_map {
        struct drm_buf_pub __user *list;        /**< Buffer information */
 };
 
-/**
+/*
  * DRM_IOCTL_DMA ioctl argument type.
  *
  * Indices here refer to the offset into the buffer list in drm_buf_get.
@@ -417,7 +416,7 @@ enum drm_ctx_flags {
        _DRM_CONTEXT_2DONLY = 0x02
 };
 
-/**
+/*
  * DRM_IOCTL_ADD_CTX ioctl argument type.
  *
  * \sa drmCreateContext() and drmDestroyContext().
@@ -427,7 +426,7 @@ struct drm_ctx {
        enum drm_ctx_flags flags;
 };
 
-/**
+/*
  * DRM_IOCTL_RES_CTX ioctl argument type.
  */
 struct drm_ctx_res {
@@ -435,14 +434,14 @@ struct drm_ctx_res {
        struct drm_ctx __user *contexts;
 };
 
-/**
+/*
  * DRM_IOCTL_ADD_DRAW and DRM_IOCTL_RM_DRAW ioctl argument type.
  */
 struct drm_draw {
        drm_drawable_t handle;
 };
 
-/**
+/*
  * DRM_IOCTL_UPDATE_DRAW ioctl argument type.
  */
 typedef enum {
@@ -456,14 +455,14 @@ struct drm_update_draw {
        unsigned long long data;
 };
 
-/**
+/*
  * DRM_IOCTL_GET_MAGIC and DRM_IOCTL_AUTH_MAGIC ioctl argument type.
  */
 struct drm_auth {
        drm_magic_t magic;
 };
 
-/**
+/*
  * DRM_IOCTL_IRQ_BUSID ioctl argument type.
  *
  * \sa drmGetInterruptFromBusID().
@@ -505,7 +504,7 @@ struct drm_wait_vblank_reply {
        long tval_usec;
 };
 
-/**
+/*
  * DRM_IOCTL_WAIT_VBLANK ioctl argument type.
  *
  * \sa drmWaitVBlank().
@@ -518,7 +517,7 @@ union drm_wait_vblank {
 #define _DRM_PRE_MODESET 1
 #define _DRM_POST_MODESET 2
 
-/**
+/*
  * DRM_IOCTL_MODESET_CTL ioctl argument type
  *
  * \sa drmModesetCtl().
@@ -528,7 +527,7 @@ struct drm_modeset_ctl {
        __u32 cmd;
 };
 
-/**
+/*
  * DRM_IOCTL_AGP_ENABLE ioctl argument type.
  *
  * \sa drmAgpEnable().
@@ -537,7 +536,7 @@ struct drm_agp_mode {
        unsigned long mode;     /**< AGP mode */
 };
 
-/**
+/*
  * DRM_IOCTL_AGP_ALLOC and DRM_IOCTL_AGP_FREE ioctls argument type.
  *
  * \sa drmAgpAlloc() and drmAgpFree().
@@ -549,7 +548,7 @@ struct drm_agp_buffer {
        unsigned long physical; /**< Physical used by i810 */
 };
 
-/**
+/*
  * DRM_IOCTL_AGP_BIND and DRM_IOCTL_AGP_UNBIND ioctls argument type.
  *
  * \sa drmAgpBind() and drmAgpUnbind().
@@ -559,7 +558,7 @@ struct drm_agp_binding {
        unsigned long offset;   /**< In bytes -- will round to page boundary */
 };
 
-/**
+/*
  * DRM_IOCTL_AGP_INFO ioctl argument type.
  *
  * \sa drmAgpVersionMajor(), drmAgpVersionMinor(), drmAgpGetMode(),
@@ -580,7 +579,7 @@ struct drm_agp_info {
        unsigned short id_device;
 };
 
-/**
+/*
  * DRM_IOCTL_SG_ALLOC ioctl argument type.
  */
 struct drm_scatter_gather {
@@ -588,7 +587,7 @@ struct drm_scatter_gather {
        unsigned long handle;   /**< Used for mapping / unmapping */
 };
 
-/**
+/*
  * DRM_IOCTL_SET_VERSION ioctl argument type.
  */
 struct drm_set_version {
@@ -598,14 +597,14 @@ struct drm_set_version {
        int drm_dd_minor;
 };
 
-/** DRM_IOCTL_GEM_CLOSE ioctl argument type */
+/* DRM_IOCTL_GEM_CLOSE ioctl argument type */
 struct drm_gem_close {
        /** Handle of the object to be closed. */
        __u32 handle;
        __u32 pad;
 };
 
-/** DRM_IOCTL_GEM_FLINK ioctl argument type */
+/* DRM_IOCTL_GEM_FLINK ioctl argument type */
 struct drm_gem_flink {
        /** Handle for the object being named */
        __u32 handle;
@@ -614,7 +613,7 @@ struct drm_gem_flink {
        __u32 name;
 };
 
-/** DRM_IOCTL_GEM_OPEN ioctl argument type */
+/* DRM_IOCTL_GEM_OPEN ioctl argument type */
 struct drm_gem_open {
        /** Name of object being opened */
        __u32 name;
@@ -652,7 +651,7 @@ struct drm_gem_open {
 #define DRM_CAP_SYNCOBJ                0x13
 #define DRM_CAP_SYNCOBJ_TIMELINE       0x14
 
-/** DRM_IOCTL_GET_CAP ioctl argument type */
+/* DRM_IOCTL_GET_CAP ioctl argument type */
 struct drm_get_cap {
        __u64 capability;
        __u64 value;
@@ -678,7 +677,9 @@ struct drm_get_cap {
 /**
  * DRM_CLIENT_CAP_ATOMIC
  *
- * If set to 1, the DRM core will expose atomic properties to userspace
+ * If set to 1, the DRM core will expose atomic properties to userspace. This
+ * implicitly enables &DRM_CLIENT_CAP_UNIVERSAL_PLANES and
+ * &DRM_CLIENT_CAP_ASPECT_RATIO.
  */
 #define DRM_CLIENT_CAP_ATOMIC  3
 
@@ -698,7 +699,7 @@ struct drm_get_cap {
  */
 #define DRM_CLIENT_CAP_WRITEBACK_CONNECTORS    5
 
-/** DRM_IOCTL_SET_CLIENT_CAP ioctl argument type */
+/* DRM_IOCTL_SET_CLIENT_CAP ioctl argument type */
 struct drm_set_client_cap {
        __u64 capability;
        __u64 value;
@@ -950,7 +951,7 @@ extern "C" {
 
 #define DRM_IOCTL_MODE_GETFB2          DRM_IOWR(0xCE, struct drm_mode_fb_cmd2)
 
-/**
+/*
  * Device specific ioctls should only be in their respective headers
  * The device specific ioctl range is from 0x40 to 0x9f.
  * Generic IOCTLS restart at 0xA0.
@@ -961,7 +962,7 @@ extern "C" {
 #define DRM_COMMAND_BASE                0x40
 #define DRM_COMMAND_END                        0xA0
 
-/**
+/*
  * Header for events written back to userspace on the drm fd.  The
  * type defines the type of event, the length specifies the total
  * length of the event (including the header), and user_data is
index fa1f3d6..1987e2e 100644 (file)
@@ -177,8 +177,9 @@ enum drm_i915_pmu_engine_sample {
 #define I915_PMU_REQUESTED_FREQUENCY   __I915_PMU_OTHER(1)
 #define I915_PMU_INTERRUPTS            __I915_PMU_OTHER(2)
 #define I915_PMU_RC6_RESIDENCY         __I915_PMU_OTHER(3)
+#define I915_PMU_SOFTWARE_GT_AWAKE_TIME        __I915_PMU_OTHER(4)
 
-#define I915_PMU_LAST I915_PMU_RC6_RESIDENCY
+#define I915_PMU_LAST /* Deprecated - do not use */ I915_PMU_RC6_RESIDENCY
 
 /* Each region is a minimum of 16k, and there are at most 255 of them.
  */
index 4c24daa..79c8933 100644 (file)
@@ -3850,7 +3850,6 @@ union bpf_attr {
  *
  * long bpf_check_mtu(void *ctx, u32 ifindex, u32 *mtu_len, s32 len_diff, u64 flags)
  *     Description
-
  *             Check ctx packet size against exceeding MTU of net device (based
  *             on *ifindex*).  This helper will likely be used in combination
  *             with helpers that adjust/change the packet size.
index abb89bb..8b281f7 100644 (file)
@@ -216,6 +216,20 @@ struct kvm_hyperv_exit {
        } u;
 };
 
+struct kvm_xen_exit {
+#define KVM_EXIT_XEN_HCALL          1
+       __u32 type;
+       union {
+               struct {
+                       __u32 longmode;
+                       __u32 cpl;
+                       __u64 input;
+                       __u64 result;
+                       __u64 params[6];
+               } hcall;
+       } u;
+};
+
 #define KVM_S390_GET_SKEYS_NONE   1
 #define KVM_S390_SKEYS_MAX        1048576
 
@@ -252,6 +266,8 @@ struct kvm_hyperv_exit {
 #define KVM_EXIT_X86_WRMSR        30
 #define KVM_EXIT_DIRTY_RING_FULL  31
 #define KVM_EXIT_AP_RESET_HOLD    32
+#define KVM_EXIT_X86_BUS_LOCK     33
+#define KVM_EXIT_XEN              34
 
 /* For KVM_EXIT_INTERNAL_ERROR */
 /* Emulate instruction failed. */
@@ -428,6 +444,8 @@ struct kvm_run {
                        __u32 index; /* kernel -> user */
                        __u64 data; /* kernel <-> user */
                } msr;
+               /* KVM_EXIT_XEN */
+               struct kvm_xen_exit xen;
                /* Fix the size of the union. */
                char padding[256];
        };
@@ -1058,6 +1076,7 @@ struct kvm_ppc_resize_hpt {
 #define KVM_CAP_ENFORCE_PV_FEATURE_CPUID 190
 #define KVM_CAP_SYS_HYPERV_CPUID 191
 #define KVM_CAP_DIRTY_LOG_RING 192
+#define KVM_CAP_X86_BUS_LOCK_EXIT 193
 #define KVM_CAP_PPC_DAWR1 194
 
 #ifdef KVM_CAP_IRQ_ROUTING
@@ -1132,6 +1151,10 @@ struct kvm_x86_mce {
 #endif
 
 #ifdef KVM_CAP_XEN_HVM
+#define KVM_XEN_HVM_CONFIG_HYPERCALL_MSR       (1 << 0)
+#define KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL     (1 << 1)
+#define KVM_XEN_HVM_CONFIG_SHARED_INFO         (1 << 2)
+
 struct kvm_xen_hvm_config {
        __u32 flags;
        __u32 msr;
@@ -1566,6 +1589,45 @@ struct kvm_pv_cmd {
 /* Available with KVM_CAP_DIRTY_LOG_RING */
 #define KVM_RESET_DIRTY_RINGS          _IO(KVMIO, 0xc7)
 
+/* Per-VM Xen attributes */
+#define KVM_XEN_HVM_GET_ATTR   _IOWR(KVMIO, 0xc8, struct kvm_xen_hvm_attr)
+#define KVM_XEN_HVM_SET_ATTR   _IOW(KVMIO,  0xc9, struct kvm_xen_hvm_attr)
+
+struct kvm_xen_hvm_attr {
+       __u16 type;
+       __u16 pad[3];
+       union {
+               __u8 long_mode;
+               __u8 vector;
+               struct {
+                       __u64 gfn;
+               } shared_info;
+               __u64 pad[8];
+       } u;
+};
+
+/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO */
+#define KVM_XEN_ATTR_TYPE_LONG_MODE            0x0
+#define KVM_XEN_ATTR_TYPE_SHARED_INFO          0x1
+#define KVM_XEN_ATTR_TYPE_UPCALL_VECTOR                0x2
+
+/* Per-vCPU Xen attributes */
+#define KVM_XEN_VCPU_GET_ATTR  _IOWR(KVMIO, 0xca, struct kvm_xen_vcpu_attr)
+#define KVM_XEN_VCPU_SET_ATTR  _IOW(KVMIO,  0xcb, struct kvm_xen_vcpu_attr)
+
+struct kvm_xen_vcpu_attr {
+       __u16 type;
+       __u16 pad[3];
+       union {
+               __u64 gpa;
+               __u64 pad[8];
+       } u;
+};
+
+/* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO */
+#define KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO       0x0
+#define KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO  0x1
+
 /* Secure Encrypted Virtualization command */
 enum sev_cmd_id {
        /* Guest initialization commands */
@@ -1594,6 +1656,8 @@ enum sev_cmd_id {
        KVM_SEV_DBG_ENCRYPT,
        /* Guest certificates commands */
        KVM_SEV_CERT_EXPORT,
+       /* Attestation report */
+       KVM_SEV_GET_ATTESTATION_REPORT,
 
        KVM_SEV_NR_MAX,
 };
@@ -1646,6 +1710,12 @@ struct kvm_sev_dbg {
        __u32 len;
 };
 
+struct kvm_sev_attestation_report {
+       __u8 mnonce[16];
+       __u64 uaddr;
+       __u32 len;
+};
+
 #define KVM_DEV_ASSIGN_ENABLE_IOMMU    (1 << 0)
 #define KVM_DEV_ASSIGN_PCI_2_3         (1 << 1)
 #define KVM_DEV_ASSIGN_MASK_INTX       (1 << 2)
@@ -1767,4 +1837,7 @@ struct kvm_dirty_gfn {
        __u64 offset;
 };
 
+#define KVM_BUS_LOCK_DETECTION_OFF             (1 << 0)
+#define KVM_BUS_LOCK_DETECTION_EXIT            (1 << 1)
+
 #endif /* __LINUX_KVM_H */
index dd8306e..e6524ea 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _UAPI_LINUX_MOUNT_H
 #define _UAPI_LINUX_MOUNT_H
 
+#include <linux/types.h>
+
 /*
  * These are the fs-independent mount-flags: up to 32 flags are supported
  *
@@ -117,5 +119,19 @@ enum fsconfig_command {
 #define MOUNT_ATTR_NOATIME     0x00000010 /* - Do not update access times. */
 #define MOUNT_ATTR_STRICTATIME 0x00000020 /* - Always perform atime updates */
 #define MOUNT_ATTR_NODIRATIME  0x00000080 /* Do not update directory access times */
+#define MOUNT_ATTR_IDMAP       0x00100000 /* Idmap mount to @userns_fd in struct mount_attr. */
+
+/*
+ * mount_setattr()
+ */
+struct mount_attr {
+       __u64 attr_set;
+       __u64 attr_clr;
+       __u64 propagation;
+       __u64 userns_fd;
+};
+
+/* List of all mount_attr versions. */
+#define MOUNT_ATTR_SIZE_VER0   32 /* sizeof first published struct */
 
 #endif /* _UAPI_LINUX_MOUNT_H */
index 58b1eb7..a5feb76 100644 (file)
@@ -35,5 +35,9 @@ struct open_how {
 #define RESOLVE_IN_ROOT                0x10 /* Make all jumps to "/" and ".."
                                        be scoped inside the dirfd
                                        (similar to chroot(2)). */
+#define RESOLVE_CACHED         0x20 /* Only complete if resolution can be
+                                       completed through cached lookup. May
+                                       return -EAGAIN if that's not
+                                       possible. */
 
 #endif /* _UAPI_LINUX_OPENAT2_H */
index ffbb588..526fc35 100644 (file)
@@ -610,15 +610,16 @@ static int xsk_lookup_bpf_maps(struct xsk_socket *xsk)
                if (fd < 0)
                        continue;
 
+               memset(&map_info, 0, map_len);
                err = bpf_obj_get_info_by_fd(fd, &map_info, &map_len);
                if (err) {
                        close(fd);
                        continue;
                }
 
-               if (!strcmp(map_info.name, "xsks_map")) {
+               if (!strncmp(map_info.name, "xsks_map", sizeof(map_info.name))) {
                        ctx->xsks_map_fd = fd;
-                       continue;
+                       break;
                }
 
                close(fd);
index 17465d4..a0aaf38 100644 (file)
 
 void perf_evlist__init(struct perf_evlist *evlist)
 {
-       int i;
-
-       for (i = 0; i < PERF_EVLIST__HLIST_SIZE; ++i)
-               INIT_HLIST_HEAD(&evlist->heads[i]);
        INIT_LIST_HEAD(&evlist->entries);
        evlist->nr_entries = 0;
        fdarray__init(&evlist->pollfd, 64);
+       perf_evlist__reset_id_hash(evlist);
 }
 
 static void __perf_evlist__propagate_maps(struct perf_evlist *evlist,
@@ -237,6 +234,14 @@ static void perf_evlist__id_hash(struct perf_evlist *evlist,
        hlist_add_head(&sid->node, &evlist->heads[hash]);
 }
 
+void perf_evlist__reset_id_hash(struct perf_evlist *evlist)
+{
+       int i;
+
+       for (i = 0; i < PERF_EVLIST__HLIST_SIZE; ++i)
+               INIT_HLIST_HEAD(&evlist->heads[i]);
+}
+
 void perf_evlist__id_add(struct perf_evlist *evlist,
                         struct perf_evsel *evsel,
                         int cpu, int thread, u64 id)
index 2d0fa02..212c290 100644 (file)
@@ -124,4 +124,6 @@ int perf_evlist__id_add_fd(struct perf_evlist *evlist,
                           struct perf_evsel *evsel,
                           int cpu, int thread, int fd);
 
+void perf_evlist__reset_id_hash(struct perf_evlist *evlist);
+
 #endif /* __LIBPERF_INTERNAL_EVLIST_H */
index 068cdb4..5e5388a 100644 (file)
@@ -2442,6 +2442,9 @@ static int handle_insn_ops(struct instruction *insn, struct insn_state *state)
                if (update_cfi_state(insn, &state->cfi, op))
                        return 1;
 
+               if (!insn->alt_group)
+                       continue;
+
                if (op->dest.type == OP_DEST_PUSHF) {
                        if (!state->uaccess_stack) {
                                state->uaccess_stack = 1;
index c0a6640..9af8b8d 100644 (file)
@@ -29,7 +29,7 @@ OPTIONS
        Show just the sample frequency used for each event.
 
 -v::
---verbose=::
+--verbose::
        Show all fields.
 
 -g::
index 1e91121..6e82b7c 100644 (file)
@@ -28,8 +28,8 @@ OPTIONS
        specified: function_graph or function.
 
 -v::
---verbose=::
-        Verbosity level.
+--verbose::
+        Increase the verbosity level.
 
 -F::
 --funcs::
index f3c6209..c97527d 100644 (file)
@@ -20,5 +20,5 @@ modules).
 OPTIONS
 -------
 -v::
---verbose=::
+--verbose::
        Increase verbosity level, showing details about symbol table loading, etc.
index abc9b5d..f0da8cf 100644 (file)
@@ -97,8 +97,8 @@ filter out the startup phase of the program, which is often very different.
        Filter out events for these pids and for 'trace' itself (comma separated list).
 
 -v::
---verbose=::
-        Verbosity level.
+--verbose::
+        Increase the verbosity level.
 
 --no-inherit::
        Child tasks do not inherit counters.
index 5345ac7..f6e6096 100644 (file)
@@ -607,7 +607,7 @@ arch_errno_hdr_dir := $(srctree)/tools
 arch_errno_tbl := $(srctree)/tools/perf/trace/beauty/arch_errno_names.sh
 
 $(arch_errno_name_array): $(arch_errno_tbl)
-       $(Q)$(SHELL) '$(arch_errno_tbl)' $(firstword $(CC)) $(arch_errno_hdr_dir) > $@
+       $(Q)$(SHELL) '$(arch_errno_tbl)' '$(patsubst -%,,$(CC))' $(arch_errno_hdr_dir) > $@
 
 sync_file_range_arrays := $(beauty_outdir)/sync_file_range_arrays.c
 sync_file_range_tbls := $(srctree)/tools/perf/trace/beauty/sync_file_range.sh
@@ -1001,14 +1001,6 @@ $(INSTALL_DOC_TARGETS):
 
 ### Cleaning rules
 
-#
-# This is here, not in Makefile.config, because Makefile.config does
-# not get included for the clean target:
-#
-config-clean:
-       $(call QUIET_CLEAN, config)
-       $(Q)$(MAKE) -C $(srctree)/tools/build/feature/ $(if $(OUTPUT),OUTPUT=$(OUTPUT)feature/,) clean >/dev/null
-
 python-clean:
        $(python-clean)
 
@@ -1048,7 +1040,7 @@ endif # BUILD_BPF_SKEL
 bpf-skel-clean:
        $(call QUIET_CLEAN, bpf-skel) $(RM) -r $(SKEL_TMP_OUT) $(SKELETONS)
 
-clean:: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean $(LIBPERF)-clean config-clean fixdep-clean python-clean bpf-skel-clean
+clean:: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean $(LIBPERF)-clean fixdep-clean python-clean bpf-skel-clean
        $(call QUIET_CLEAN, core-objs)  $(RM) $(LIBPERF_A) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS)
        $(Q)find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
        $(Q)$(RM) $(OUTPUT).config-detected
index bd446ab..c25c878 100644 (file)
@@ -156,6 +156,10 @@ out:
        return err;
 }
 
+#define ETM_SET_OPT_CTXTID     (1 << 0)
+#define ETM_SET_OPT_TS         (1 << 1)
+#define ETM_SET_OPT_MASK       (ETM_SET_OPT_CTXTID | ETM_SET_OPT_TS)
+
 static int cs_etm_set_option(struct auxtrace_record *itr,
                             struct evsel *evsel, u32 option)
 {
@@ -169,17 +173,17 @@ static int cs_etm_set_option(struct auxtrace_record *itr,
                    !cpu_map__has(online_cpus, i))
                        continue;
 
-               if (option & ETM_OPT_CTXTID) {
+               if (option & ETM_SET_OPT_CTXTID) {
                        err = cs_etm_set_context_id(itr, evsel, i);
                        if (err)
                                goto out;
                }
-               if (option & ETM_OPT_TS) {
+               if (option & ETM_SET_OPT_TS) {
                        err = cs_etm_set_timestamp(itr, evsel, i);
                        if (err)
                                goto out;
                }
-               if (option & ~(ETM_OPT_CTXTID | ETM_OPT_TS))
+               if (option & ~(ETM_SET_OPT_MASK))
                        /* Nothing else is currently supported */
                        goto out;
        }
@@ -406,7 +410,7 @@ static int cs_etm_recording_options(struct auxtrace_record *itr,
                evsel__set_sample_bit(cs_etm_evsel, CPU);
 
                err = cs_etm_set_option(itr, cs_etm_evsel,
-                                       ETM_OPT_CTXTID | ETM_OPT_TS);
+                                       ETM_SET_OPT_CTXTID | ETM_SET_OPT_TS);
                if (err)
                        goto out;
        }
index f744eb5..0b2480c 100644 (file)
@@ -9,9 +9,7 @@
 #
 0      nospu   restart_syscall                 sys_restart_syscall
 1      nospu   exit                            sys_exit
-2      32      fork                            ppc_fork                        sys_fork
-2      64      fork                            sys_fork
-2      spu     fork                            sys_ni_syscall
+2      nospu   fork                            sys_fork
 3      common  read                            sys_read
 4      common  write                           sys_write
 5      common  open                            sys_open                        compat_sys_open
 119    32      sigreturn                       sys_sigreturn                   compat_sys_sigreturn
 119    64      sigreturn                       sys_ni_syscall
 119    spu     sigreturn                       sys_ni_syscall
-120    32      clone                           ppc_clone                       sys_clone
-120    64      clone                           sys_clone
-120    spu     clone                           sys_ni_syscall
+120    nospu   clone                           sys_clone
 121    common  setdomainname                   sys_setdomainname
 122    common  uname                           sys_newuname
 123    common  modify_ldt                      sys_ni_syscall
 186    spu     sendfile                        sys_sendfile64
 187    common  getpmsg                         sys_ni_syscall
 188    common  putpmsg                         sys_ni_syscall
-189    32      vfork                           ppc_vfork                       sys_vfork
-189    64      vfork                           sys_vfork
-189    spu     vfork                           sys_ni_syscall
+189    nospu   vfork                           sys_vfork
 190    common  ugetrlimit                      sys_getrlimit                   compat_sys_getrlimit
 191    common  readahead                       sys_readahead                   compat_sys_readahead
 192    32      mmap2                           sys_mmap2                       compat_sys_mmap2
 248    32      clock_nanosleep                 sys_clock_nanosleep_time32
 248    64      clock_nanosleep                 sys_clock_nanosleep
 248    spu     clock_nanosleep                 sys_clock_nanosleep
-249    32      swapcontext                     ppc_swapcontext                 compat_sys_swapcontext
-249    64      swapcontext                     sys_swapcontext
-249    spu     swapcontext                     sys_ni_syscall
+249    nospu   swapcontext                     sys_swapcontext                 compat_sys_swapcontext
 250    common  tgkill                          sys_tgkill
 251    32      utimes                          sys_utimes_time32
 251    64      utimes                          sys_utimes
 432    common  fsmount                         sys_fsmount
 433    common  fspick                          sys_fspick
 434    common  pidfd_open                      sys_pidfd_open
-435    32      clone3                          ppc_clone3                      sys_clone3
-435    64      clone3                          sys_clone3
-435    spu     clone3                          sys_ni_syscall
+435    nospu   clone3                          sys_clone3
 436    common  close_range                     sys_close_range
 437    common  openat2                         sys_openat2
 438    common  pidfd_getfd                     sys_pidfd_getfd
 439    common  faccessat2                      sys_faccessat2
 440    common  process_madvise                 sys_process_madvise
 441    common  epoll_pwait2                    sys_epoll_pwait2                compat_sys_epoll_pwait2
+442    common  mount_setattr                   sys_mount_setattr
index d443423..3abef21 100644 (file)
 439  common    faccessat2              sys_faccessat2                  sys_faccessat2
 440  common    process_madvise         sys_process_madvise             sys_process_madvise
 441  common    epoll_pwait2            sys_epoll_pwait2                compat_sys_epoll_pwait2
+442  common    mount_setattr           sys_mount_setattr               sys_mount_setattr
index 8cc6642..5a9f9a7 100644 (file)
@@ -10,10 +10,11 @@ PERF_HAVE_JITDUMP := 1
 # Syscall table generation
 #
 
-out    := $(OUTPUT)arch/x86/include/generated/asm
-header := $(out)/syscalls_64.c
-sys    := $(srctree)/tools/perf/arch/x86/entry/syscalls
-systbl := $(sys)/syscalltbl.sh
+generated := $(OUTPUT)arch/x86/include/generated
+out       := $(generated)/asm
+header    := $(out)/syscalls_64.c
+sys       := $(srctree)/tools/perf/arch/x86/entry/syscalls
+systbl    := $(sys)/syscalltbl.sh
 
 # Create output directory if not already present
 _dummy := $(shell [ -d '$(out)' ] || mkdir -p '$(out)')
@@ -22,6 +23,6 @@ $(header): $(sys)/syscall_64.tbl $(systbl)
        $(Q)$(SHELL) '$(systbl)' $(sys)/syscall_64.tbl 'x86_64' > $@
 
 clean::
-       $(call QUIET_CLEAN, x86) $(RM) $(header)
+       $(call QUIET_CLEAN, x86) $(RM) -r $(header) $(generated)
 
 archheaders: $(header)
index 7867212..7bf01cb 100644 (file)
 439    common  faccessat2              sys_faccessat2
 440    common  process_madvise         sys_process_madvise
 441    common  epoll_pwait2            sys_epoll_pwait2
+442    common  mount_setattr           sys_mount_setattr
 
 #
 # Due to a historical design error, certain syscalls are numbered differently
index 6a54b94..0e20f3d 100644 (file)
@@ -10,6 +10,7 @@ int test__rdpmc(struct test *test __maybe_unused, int subtest);
 int test__insn_x86(struct test *test __maybe_unused, int subtest);
 int test__intel_pt_pkt_decoder(struct test *test, int subtest);
 int test__bp_modify(struct test *test, int subtest);
+int test__x86_sample_parsing(struct test *test, int subtest);
 
 #ifdef HAVE_DWARF_UNWIND_SUPPORT
 struct thread;
index 36d4f24..28d7933 100644 (file)
@@ -3,5 +3,6 @@ perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
 
 perf-y += arch-tests.o
 perf-y += rdpmc.o
+perf-y += sample-parsing.o
 perf-$(CONFIG_AUXTRACE) += insn-x86.o intel-pt-pkt-decoder-test.o
 perf-$(CONFIG_X86_64) += bp-modify.o
index bc25d72..71aa673 100644 (file)
@@ -30,6 +30,10 @@ struct test arch_tests[] = {
                .func = test__bp_modify,
        },
 #endif
+       {
+               .desc = "x86 Sample parsing",
+               .func = test__x86_sample_parsing,
+       },
        {
                .func = NULL,
        },
index f782ef8..4f75ae9 100644 (file)
@@ -1,11 +1,11 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <linux/types.h>
-#include "../../../../arch/x86/include/asm/insn.h"
 #include <string.h>
 
 #include "debug.h"
 #include "tests/tests.h"
 #include "arch-tests.h"
+#include "../../../../arch/x86/include/asm/insn.h"
 
 #include "intel-pt-decoder/intel-pt-insn-decoder.h"
 
diff --git a/tools/perf/arch/x86/tests/sample-parsing.c b/tools/perf/arch/x86/tests/sample-parsing.c
new file mode 100644 (file)
index 0000000..c92db87
--- /dev/null
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <stdbool.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#include "event.h"
+#include "evsel.h"
+#include "debug.h"
+#include "util/synthetic-events.h"
+
+#include "tests/tests.h"
+#include "arch-tests.h"
+
+#define COMP(m) do {                                   \
+       if (s1->m != s2->m) {                           \
+               pr_debug("Samples differ at '"#m"'\n"); \
+               return false;                           \
+       }                                               \
+} while (0)
+
+static bool samples_same(const struct perf_sample *s1,
+                        const struct perf_sample *s2,
+                        u64 type)
+{
+       if (type & PERF_SAMPLE_WEIGHT_STRUCT)
+               COMP(ins_lat);
+
+       return true;
+}
+
+static int do_test(u64 sample_type)
+{
+       struct evsel evsel = {
+               .needs_swap = false,
+               .core = {
+                       . attr = {
+                               .sample_type = sample_type,
+                               .read_format = 0,
+                       },
+               },
+       };
+       union perf_event *event;
+       struct perf_sample sample = {
+               .weight         = 101,
+               .ins_lat        = 102,
+       };
+       struct perf_sample sample_out;
+       size_t i, sz, bufsz;
+       int err, ret = -1;
+
+       sz = perf_event__sample_event_size(&sample, sample_type, 0);
+       bufsz = sz + 4096; /* Add a bit for overrun checking */
+       event = malloc(bufsz);
+       if (!event) {
+               pr_debug("malloc failed\n");
+               return -1;
+       }
+
+       memset(event, 0xff, bufsz);
+       event->header.type = PERF_RECORD_SAMPLE;
+       event->header.misc = 0;
+       event->header.size = sz;
+
+       err = perf_event__synthesize_sample(event, sample_type, 0, &sample);
+       if (err) {
+               pr_debug("%s failed for sample_type %#"PRIx64", error %d\n",
+                        "perf_event__synthesize_sample", sample_type, err);
+               goto out_free;
+       }
+
+       /* The data does not contain 0xff so we use that to check the size */
+       for (i = bufsz; i > 0; i--) {
+               if (*(i - 1 + (u8 *)event) != 0xff)
+                       break;
+       }
+       if (i != sz) {
+               pr_debug("Event size mismatch: actual %zu vs expected %zu\n",
+                        i, sz);
+               goto out_free;
+       }
+
+       evsel.sample_size = __evsel__sample_size(sample_type);
+
+       err = evsel__parse_sample(&evsel, event, &sample_out);
+       if (err) {
+               pr_debug("%s failed for sample_type %#"PRIx64", error %d\n",
+                        "evsel__parse_sample", sample_type, err);
+               goto out_free;
+       }
+
+       if (!samples_same(&sample, &sample_out, sample_type)) {
+               pr_debug("parsing failed for sample_type %#"PRIx64"\n",
+                        sample_type);
+               goto out_free;
+       }
+
+       ret = 0;
+out_free:
+       free(event);
+
+       return ret;
+}
+
+/**
+ * test__x86_sample_parsing - test X86 specific sample parsing
+ *
+ * This function implements a test that synthesizes a sample event, parses it
+ * and then checks that the parsed sample matches the original sample. If the
+ * test passes %0 is returned, otherwise %-1 is returned.
+ *
+ * For now, the PERF_SAMPLE_WEIGHT_STRUCT is the only X86 specific sample type.
+ * The test only checks the PERF_SAMPLE_WEIGHT_STRUCT type.
+ */
+int test__x86_sample_parsing(struct test *test __maybe_unused, int subtest __maybe_unused)
+{
+       return do_test(PERF_SAMPLE_WEIGHT_STRUCT);
+}
index 3e67915..34d600c 100644 (file)
@@ -1,10 +1,10 @@
 // SPDX-License-Identifier: GPL-2.0
-#include "../../../../arch/x86/include/asm/insn.h"
 #include "archinsn.h"
 #include "event.h"
 #include "machine.h"
 #include "thread.h"
 #include "symbol.h"
+#include "../../../../arch/x86/include/asm/insn.h"
 
 void arch_fetch_insn(struct perf_sample *sample,
                     struct thread *thread,
index 11726ec..20b87e2 100644 (file)
@@ -344,18 +344,22 @@ static void mempol_restore(void)
 
 static void bind_to_memnode(int node)
 {
-       unsigned long nodemask;
+       struct bitmask *node_mask;
        int ret;
 
        if (node == NUMA_NO_NODE)
                return;
 
-       BUG_ON(g->p.nr_nodes > (int)sizeof(nodemask)*8);
-       nodemask = 1L << node;
+       node_mask = numa_allocate_nodemask();
+       BUG_ON(!node_mask);
 
-       ret = set_mempolicy(MPOL_BIND, &nodemask, sizeof(nodemask)*8);
-       dprintf("binding to node %d, mask: %016lx => %d\n", node, nodemask, ret);
+       numa_bitmask_clearall(node_mask);
+       numa_bitmask_setbit(node_mask, node);
 
+       ret = set_mempolicy(MPOL_BIND, node_mask->maskp, node_mask->size + 1);
+       dprintf("binding to node %d, mask: %016lx => %d\n", node, *node_mask->maskp, ret);
+
+       numa_bitmask_free(node_mask);
        BUG_ON(ret);
 }
 
@@ -876,8 +880,6 @@ static void update_curr_cpu(int task_nr, unsigned long bytes_worked)
        prctl(0, bytes_worked);
 }
 
-#define MAX_NR_NODES   64
-
 /*
  * Count the number of nodes a process's threads
  * are spread out on.
@@ -888,10 +890,15 @@ static void update_curr_cpu(int task_nr, unsigned long bytes_worked)
  */
 static int count_process_nodes(int process_nr)
 {
-       char node_present[MAX_NR_NODES] = { 0, };
+       char *node_present;
        int nodes;
        int n, t;
 
+       node_present = (char *)malloc(g->p.nr_nodes * sizeof(char));
+       BUG_ON(!node_present);
+       for (nodes = 0; nodes < g->p.nr_nodes; nodes++)
+               node_present[nodes] = 0;
+
        for (t = 0; t < g->p.nr_threads; t++) {
                struct thread_data *td;
                int task_nr;
@@ -901,17 +908,20 @@ static int count_process_nodes(int process_nr)
                td = g->threads + task_nr;
 
                node = numa_node_of_cpu(td->curr_cpu);
-               if (node < 0) /* curr_cpu was likely still -1 */
+               if (node < 0) /* curr_cpu was likely still -1 */ {
+                       free(node_present);
                        return 0;
+               }
 
                node_present[node] = 1;
        }
 
        nodes = 0;
 
-       for (n = 0; n < MAX_NR_NODES; n++)
+       for (n = 0; n < g->p.nr_nodes; n++)
                nodes += node_present[n];
 
+       free(node_present);
        return nodes;
 }
 
@@ -980,7 +990,7 @@ static void calc_convergence(double runtime_ns_max, double *convergence)
 {
        unsigned int loops_done_min, loops_done_max;
        int process_groups;
-       int nodes[MAX_NR_NODES];
+       int *nodes;
        int distance;
        int nr_min;
        int nr_max;
@@ -994,6 +1004,8 @@ static void calc_convergence(double runtime_ns_max, double *convergence)
        if (!g->p.show_convergence && !g->p.measure_convergence)
                return;
 
+       nodes = (int *)malloc(g->p.nr_nodes * sizeof(int));
+       BUG_ON(!nodes);
        for (node = 0; node < g->p.nr_nodes; node++)
                nodes[node] = 0;
 
@@ -1035,8 +1047,10 @@ static void calc_convergence(double runtime_ns_max, double *convergence)
 
        BUG_ON(sum > g->p.nr_tasks);
 
-       if (0 && (sum < g->p.nr_tasks))
+       if (0 && (sum < g->p.nr_tasks)) {
+               free(nodes);
                return;
+       }
 
        /*
         * Count the number of distinct process groups present
@@ -1088,6 +1102,8 @@ static void calc_convergence(double runtime_ns_max, double *convergence)
                }
                tprintf("\n");
        }
+
+       free(nodes);
 }
 
 static void show_summary(double runtime_ns_max, int l, double *convergence)
@@ -1413,7 +1429,7 @@ static int init(void)
        g->p.nr_nodes = numa_max_node() + 1;
 
        /* char array in count_process_nodes(): */
-       BUG_ON(g->p.nr_nodes > MAX_NR_NODES || g->p.nr_nodes < 0);
+       BUG_ON(g->p.nr_nodes < 0);
 
        if (g->p.show_quiet && !g->p.show_details)
                g->p.show_details = -1;
index cecce93..488f6e6 100644 (file)
@@ -309,11 +309,11 @@ int bench_sched_messaging(int argc, const char **argv)
                       num_groups, num_groups * 2 * num_fds,
                       thread_mode ? "threads" : "processes");
                printf(" %14s: %lu.%03lu [sec]\n", "Total time",
-                      diff.tv_sec,
+                      (unsigned long) diff.tv_sec,
                       (unsigned long) (diff.tv_usec / USEC_PER_MSEC));
                break;
        case BENCH_FORMAT_SIMPLE:
-               printf("%lu.%03lu\n", diff.tv_sec,
+               printf("%lu.%03lu\n", (unsigned long) diff.tv_sec,
                       (unsigned long) (diff.tv_usec / USEC_PER_MSEC));
                break;
        default:
index 3c88d1f..a960e7a 100644 (file)
@@ -156,7 +156,7 @@ int bench_sched_pipe(int argc, const char **argv)
                result_usec += diff.tv_usec;
 
                printf(" %14s: %lu.%03lu [sec]\n\n", "Total time",
-                      diff.tv_sec,
+                      (unsigned long) diff.tv_sec,
                       (unsigned long) (diff.tv_usec / USEC_PER_MSEC));
 
                printf(" %14lf usecs/op\n",
@@ -168,7 +168,7 @@ int bench_sched_pipe(int argc, const char **argv)
 
        case BENCH_FORMAT_SIMPLE:
                printf("%lu.%03lu\n",
-                      diff.tv_sec,
+                      (unsigned long) diff.tv_sec,
                       (unsigned long) (diff.tv_usec / USEC_PER_MSEC));
                break;
 
index 5fe621c..9b75101 100644 (file)
@@ -54,7 +54,7 @@ int bench_syscall_basic(int argc, const char **argv)
                result_usec += diff.tv_usec;
 
                printf(" %14s: %lu.%03lu [sec]\n\n", "Total time",
-                      diff.tv_sec,
+                      (unsigned long) diff.tv_sec,
                       (unsigned long) (diff.tv_usec/1000));
 
                printf(" %14lf usecs/op\n",
@@ -66,7 +66,7 @@ int bench_syscall_basic(int argc, const char **argv)
 
        case BENCH_FORMAT_SIMPLE:
                printf("%lu.%03lu\n",
-                      diff.tv_sec,
+                      (unsigned long) diff.tv_sec,
                       (unsigned long) (diff.tv_usec / 1000));
                break;
 
index 617feaf..ace8772 100644 (file)
@@ -161,7 +161,7 @@ static int session_config(struct daemon *daemon, const char *var, const char *va
        struct daemon_session *session;
        char name[100];
 
-       if (get_session_name(var, name, sizeof(name)))
+       if (get_session_name(var, name, sizeof(name) - 1))
                return -EINVAL;
 
        var = strchr(var, '.');
@@ -373,12 +373,12 @@ static int daemon_session__run(struct daemon_session *session,
        dup2(fd, 2);
        close(fd);
 
-       if (mkfifo(SESSION_CONTROL, O_RDWR) && errno != EEXIST) {
+       if (mkfifo(SESSION_CONTROL, 0600) && errno != EEXIST) {
                perror("failed: create control fifo");
                return -1;
        }
 
-       if (mkfifo(SESSION_ACK, O_RDWR) && errno != EEXIST) {
+       if (mkfifo(SESSION_ACK, 0600) && errno != EEXIST) {
                perror("failed: create ack fifo");
                return -1;
        }
index 8f6c784..878e04b 100644 (file)
@@ -1236,7 +1236,8 @@ static int __cmd_diff(void)
 
  out_delete:
        data__for_each_file(i, d) {
-               perf_session__delete(d->session);
+               if (!IS_ERR(d->session))
+                       perf_session__delete(d->session);
                data__free(d);
        }
 
index 85b6a46..7ec18ff 100644 (file)
@@ -3964,9 +3964,6 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
 
        evlist__config(evlist, &trace->opts, &callchain_param);
 
-       signal(SIGCHLD, sig_handler);
-       signal(SIGINT, sig_handler);
-
        if (forks) {
                err = evlist__prepare_workload(evlist, &trace->opts.target, argv, false, NULL);
                if (err < 0) {
@@ -4827,6 +4824,8 @@ int cmd_trace(int argc, const char **argv)
 
        signal(SIGSEGV, sighandler_dump_stack);
        signal(SIGFPE, sighandler_dump_stack);
+       signal(SIGCHLD, sig_handler);
+       signal(SIGINT, sig_handler);
 
        trace.evlist = evlist__new();
        trace.sctbl = syscalltbl__new();
index 0cfb3e2..133f0ed 100644 (file)
@@ -20,9 +20,8 @@ else
 fi
 
 BUILDIDS=$(mktemp /tmp/perf-archive-buildids.XXXXXX)
-NOBUILDID=0000000000000000000000000000000000000000
 
-perf buildid-list -i $PERF_DATA --with-hits | grep -v "^$NOBUILDID " > $BUILDIDS
+perf buildid-list -i $PERF_DATA --with-hits | grep -v "^ " > $BUILDIDS
 if [ ! -s $BUILDIDS ] ; then
        echo "perf archive: no build-ids found"
        rm $BUILDIDS || true
index ec972e0..dd39ce9 100644 (file)
@@ -182,14 +182,20 @@ int test__attr(struct test *test __maybe_unused, int subtest __maybe_unused)
        struct stat st;
        char path_perf[PATH_MAX];
        char path_dir[PATH_MAX];
+       char *exec_path;
 
        /* First try development tree tests. */
        if (!lstat("./tests", &st))
                return run_dir("./tests", "./perf");
 
+       exec_path = get_argv_exec_path();
+       if (exec_path == NULL)
+               return -1;
+
        /* Then installed path. */
-       snprintf(path_dir,  PATH_MAX, "%s/tests", get_argv_exec_path());
+       snprintf(path_dir,  PATH_MAX, "%s/tests", exec_path);
        snprintf(path_perf, PATH_MAX, "%s/perf", BINDIR);
+       free(exec_path);
 
        if (!lstat(path_dir, &st) &&
            !lstat(path_perf, &st))
index 280f034..2fdc7b2 100644 (file)
@@ -706,13 +706,9 @@ static int do_test_code_reading(bool try_kcore)
 out_put:
        thread__put(thread);
 out_err:
-
-       if (evlist) {
-               evlist__delete(evlist);
-       } else {
-               perf_cpu_map__put(cpus);
-               perf_thread_map__put(threads);
-       }
+       evlist__delete(evlist);
+       perf_cpu_map__put(cpus);
+       perf_thread_map__put(threads);
        machine__delete_threads(machine);
        machine__delete(machine);
 
index 29c793a..0472b11 100644 (file)
@@ -106,6 +106,8 @@ static int cpu_map_print(const char *str)
                return -1;
 
        cpu_map__snprint(map, buf, sizeof(buf));
+       perf_cpu_map__put(map);
+
        return !strcmp(buf, str);
 }
 
index e6f1b2a..a0438b0 100644 (file)
@@ -154,10 +154,9 @@ out_err:
        if (evlist) {
                evlist__disable(evlist);
                evlist__delete(evlist);
-       } else {
-               perf_cpu_map__put(cpus);
-               perf_thread_map__put(threads);
        }
+       perf_cpu_map__put(cpus);
+       perf_thread_map__put(threads);
 
        return err;
 }
index 57093ae..73ae8f7 100644 (file)
@@ -158,8 +158,6 @@ out_init:
 
 out_delete_evlist:
        evlist__delete(evlist);
-       cpus    = NULL;
-       threads = NULL;
 out_free_cpus:
        perf_cpu_map__put(cpus);
 out_free_threads:
index 7cff026..680c3cf 100644 (file)
@@ -167,6 +167,8 @@ next_event:
 
 out_err:
        evlist__delete(evlist);
+       perf_cpu_map__put(cpus);
+       perf_thread_map__put(threads);
        return err;
 }
 
index 0dbe3aa..8fd8a4e 100644 (file)
@@ -129,9 +129,6 @@ static bool samples_same(const struct perf_sample *s1,
        if (type & PERF_SAMPLE_WEIGHT)
                COMP(weight);
 
-       if (type & PERF_SAMPLE_WEIGHT_STRUCT)
-               COMP(ins_lat);
-
        if (type & PERF_SAMPLE_DATA_SRC)
                COMP(data_src);
 
@@ -245,7 +242,6 @@ static int do_test(u64 sample_type, u64 sample_regs, u64 read_format)
                .cgroup         = 114,
                .data_page_size = 115,
                .code_page_size = 116,
-               .ins_lat        = 117,
                .aux_sample     = {
                        .size   = sizeof(aux_data),
                        .data   = (void *)aux_data,
index e5b824d..5ad3ca8 100755 (executable)
@@ -140,10 +140,10 @@ test_list()
 base=BASE
 
 [session-size]
-run = -e cpu-clock
+run = -e cpu-clock -m 1 sleep 10
 
 [session-time]
-run = -e task-clock
+run = -e task-clock -m 1 sleep 10
 EOF
 
        sed -i -e "s|BASE|${base}|" ${config}
@@ -159,14 +159,14 @@ EOF
        # check 1st session
        # pid:size:-e cpu-clock:base/size:base/size/output:base/size/control:base/size/ack:0
        local line=`perf daemon --config ${config} -x: | head -2 | tail -1`
-       check_line_other "${line}" size "-e cpu-clock" ${base}/session-size \
+       check_line_other "${line}" size "-e cpu-clock -m 1 sleep 10" ${base}/session-size \
                         ${base}/session-size/output ${base}/session-size/control \
                         ${base}/session-size/ack "0"
 
        # check 2nd session
        # pid:time:-e task-clock:base/time:base/time/output:base/time/control:base/time/ack:0
        local line=`perf daemon --config ${config} -x: | head -3 | tail -1`
-       check_line_other "${line}" time "-e task-clock" ${base}/session-time \
+       check_line_other "${line}" time "-e task-clock -m 1 sleep 10" ${base}/session-time \
                         ${base}/session-time/output ${base}/session-time/control \
                         ${base}/session-time/ack "0"
 
@@ -190,10 +190,10 @@ test_reconfig()
 base=BASE
 
 [session-size]
-run = -e cpu-clock
+run = -e cpu-clock -m 1 sleep 10
 
 [session-time]
-run = -e task-clock
+run = -e task-clock -m 1 sleep 10
 EOF
 
        sed -i -e "s|BASE|${base}|" ${config}
@@ -204,7 +204,7 @@ EOF
        # check 2nd session
        # pid:time:-e task-clock:base/time:base/time/output:base/time/control:base/time/ack:0
        local line=`perf daemon --config ${config} -x: | head -3 | tail -1`
-       check_line_other "${line}" time "-e task-clock" ${base}/session-time \
+       check_line_other "${line}" time "-e task-clock -m 1 sleep 10" ${base}/session-time \
                         ${base}/session-time/output ${base}/session-time/control ${base}/session-time/ack "0"
        local pid=`echo "${line}" | awk 'BEGIN { FS = ":" } ; { print $1 }'`
 
@@ -215,10 +215,10 @@ EOF
 base=BASE
 
 [session-size]
-run = -e cpu-clock
+run = -e cpu-clock -m 1 sleep 10
 
 [session-time]
-run = -e cpu-clock
+run = -e cpu-clock -m 1 sleep 10
 EOF
 
        # TEST 1 - change config
@@ -238,7 +238,7 @@ EOF
        # check reconfigured 2nd session
        # pid:time:-e task-clock:base/time:base/time/output:base/time/control:base/time/ack:0
        local line=`perf daemon --config ${config} -x: | head -3 | tail -1`
-       check_line_other "${line}" time "-e cpu-clock" ${base}/session-time \
+       check_line_other "${line}" time "-e cpu-clock -m 1 sleep 10" ${base}/session-time \
                         ${base}/session-time/output ${base}/session-time/control ${base}/session-time/ack "0"
 
        # TEST 2 - empty config
@@ -309,10 +309,10 @@ test_stop()
 base=BASE
 
 [session-size]
-run = -e cpu-clock
+run = -e cpu-clock -m 1 sleep 10
 
 [session-time]
-run = -e task-clock
+run = -e task-clock -m 1 sleep 10
 EOF
 
        sed -i -e "s|BASE|${base}|" ${config}
@@ -361,7 +361,7 @@ test_signal()
 base=BASE
 
 [session-test]
-run = -e cpu-clock --switch-output
+run = -e cpu-clock --switch-output -m 1 sleep 10
 EOF
 
        sed -i -e "s|BASE|${base}|" ${config}
@@ -400,10 +400,10 @@ test_ping()
 base=BASE
 
 [session-size]
-run = -e cpu-clock
+run = -e cpu-clock -m 1 sleep 10
 
 [session-time]
-run = -e task-clock
+run = -e task-clock -m 1 sleep 10
 EOF
 
        sed -i -e "s|BASE|${base}|" ${config}
@@ -439,7 +439,7 @@ test_lock()
 base=BASE
 
 [session-size]
-run = -e cpu-clock
+run = -e cpu-clock -m 1 sleep 10
 EOF
 
        sed -i -e "s|BASE|${base}|" ${config}
index a49c9e2..7498884 100644 (file)
@@ -42,8 +42,8 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
                .disabled = 1,
                .freq = 1,
        };
-       struct perf_cpu_map *cpus;
-       struct perf_thread_map *threads;
+       struct perf_cpu_map *cpus = NULL;
+       struct perf_thread_map *threads = NULL;
        struct mmap *md;
 
        attr.sample_freq = 500;
@@ -66,14 +66,11 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
        if (!cpus || !threads) {
                err = -ENOMEM;
                pr_debug("Not enough memory to create thread/cpu maps\n");
-               goto out_free_maps;
+               goto out_delete_evlist;
        }
 
        perf_evlist__set_maps(&evlist->core, cpus, threads);
 
-       cpus    = NULL;
-       threads = NULL;
-
        if (evlist__open(evlist)) {
                const char *knob = "/proc/sys/kernel/perf_event_max_sample_rate";
 
@@ -129,10 +126,9 @@ out_init:
                err = -1;
        }
 
-out_free_maps:
+out_delete_evlist:
        perf_cpu_map__put(cpus);
        perf_thread_map__put(threads);
-out_delete_evlist:
        evlist__delete(evlist);
        return err;
 }
index 15a2ab7..3ebaa75 100644 (file)
@@ -574,10 +574,9 @@ out:
        if (evlist) {
                evlist__disable(evlist);
                evlist__delete(evlist);
-       } else {
-               perf_cpu_map__put(cpus);
-               perf_thread_map__put(threads);
        }
+       perf_cpu_map__put(cpus);
+       perf_thread_map__put(threads);
 
        return err;
 
index bbf94e4..4c2969d 100644 (file)
@@ -75,14 +75,11 @@ int test__task_exit(struct test *test __maybe_unused, int subtest __maybe_unused
        if (!cpus || !threads) {
                err = -ENOMEM;
                pr_debug("Not enough memory to create thread/cpu maps\n");
-               goto out_free_maps;
+               goto out_delete_evlist;
        }
 
        perf_evlist__set_maps(&evlist->core, cpus, threads);
 
-       cpus    = NULL;
-       threads = NULL;
-
        err = evlist__prepare_workload(evlist, &target, argv, false, workload_exec_failed_signal);
        if (err < 0) {
                pr_debug("Couldn't run the workload!\n");
@@ -137,7 +134,7 @@ out_init:
                if (retry_count++ > 1000) {
                        pr_debug("Failed after retrying 1000 times\n");
                        err = -1;
-                       goto out_free_maps;
+                       goto out_delete_evlist;
                }
 
                goto retry;
@@ -148,10 +145,9 @@ out_init:
                err = -1;
        }
 
-out_free_maps:
+out_delete_evlist:
        perf_cpu_map__put(cpus);
        perf_thread_map__put(threads);
-out_delete_evlist:
        evlist__delete(evlist);
        return err;
 }
index 28f51c4..d1e208b 100644 (file)
@@ -102,6 +102,7 @@ int test__thread_map_synthesize(struct test *test __maybe_unused, int subtest __
        TEST_ASSERT_VAL("failed to synthesize map",
                !perf_event__synthesize_thread_map2(NULL, threads, process_event, NULL));
 
+       perf_thread_map__put(threads);
        return 0;
 }
 
@@ -109,12 +110,12 @@ int test__thread_map_remove(struct test *test __maybe_unused, int subtest __mayb
 {
        struct perf_thread_map *threads;
        char *str;
-       int i;
 
        TEST_ASSERT_VAL("failed to allocate map string",
                        asprintf(&str, "%d,%d", getpid(), getppid()) >= 0);
 
        threads = thread_map__new_str(str, NULL, 0, false);
+       free(str);
 
        TEST_ASSERT_VAL("failed to allocate thread_map",
                        threads);
@@ -141,9 +142,6 @@ int test__thread_map_remove(struct test *test __maybe_unused, int subtest __mayb
        TEST_ASSERT_VAL("failed to not remove thread",
                        thread_map__remove(threads, 0));
 
-       for (i = 0; i < threads->nr; i++)
-               zfree(&threads->map[i].comm);
-
-       free(threads);
+       perf_thread_map__put(threads);
        return 0;
 }
index 5121b4d..882cd1f 100644 (file)
@@ -1306,6 +1306,7 @@ void evlist__close(struct evlist *evlist)
                perf_evsel__free_fd(&evsel->core);
                perf_evsel__free_id(&evsel->core);
        }
+       perf_evlist__reset_id_hash(&evlist->core);
 }
 
 static int evlist__create_syswide_maps(struct evlist *evlist)
index 1bf7686..7ecbc8e 100644 (file)
@@ -46,6 +46,7 @@
 #include "string2.h"
 #include "memswap.h"
 #include "util.h"
+#include "hashmap.h"
 #include "../perf-sys.h"
 #include "util/parse-branch-options.h"
 #include <internal/xyarray.h>
@@ -1390,7 +1391,9 @@ void evsel__exit(struct evsel *evsel)
        zfree(&evsel->group_name);
        zfree(&evsel->name);
        zfree(&evsel->pmu_name);
-       zfree(&evsel->per_pkg_mask);
+       evsel__zero_per_pkg(evsel);
+       hashmap__free(evsel->per_pkg_mask);
+       evsel->per_pkg_mask = NULL;
        zfree(&evsel->metric_events);
        perf_evsel__object.fini(evsel);
 }
@@ -2781,3 +2784,16 @@ int evsel__store_ids(struct evsel *evsel, struct evlist *evlist)
 
        return store_evsel_ids(evsel, evlist);
 }
+
+void evsel__zero_per_pkg(struct evsel *evsel)
+{
+       struct hashmap_entry *cur;
+       size_t bkt;
+
+       if (evsel->per_pkg_mask) {
+               hashmap__for_each_entry(evsel->per_pkg_mask, cur, bkt)
+                       free((char *)cur->key);
+
+               hashmap__clear(evsel->per_pkg_mask);
+       }
+}
index 4e8e49f..6026487 100644 (file)
@@ -19,6 +19,7 @@ struct perf_stat_evsel;
 union perf_event;
 struct bpf_counter_ops;
 struct target;
+struct hashmap;
 
 typedef int (evsel__sb_cb_t)(union perf_event *event, void *data);
 
@@ -112,7 +113,7 @@ struct evsel {
        bool                    merged_stat;
        bool                    reset_group;
        bool                    errored;
-       unsigned long           *per_pkg_mask;
+       struct hashmap          *per_pkg_mask;
        struct evsel            *leader;
        struct list_head        config_terms;
        int                     err;
@@ -433,4 +434,5 @@ struct perf_env *evsel__env(struct evsel *evsel);
 
 int evsel__store_ids(struct evsel *evsel, struct evlist *evlist);
 
+void evsel__zero_per_pkg(struct evsel *evsel);
 #endif /* __PERF_EVSEL_H */
index 4fe9e2a..20effdf 100644 (file)
@@ -1618,8 +1618,8 @@ static void print_clock_data(struct feat_fd *ff, FILE *fp)
 
        fprintf(fp, "# clockid: %s (%u)\n", clockid_name(clockid), clockid);
        fprintf(fp, "# reference time: %s = %ld.%06d (TOD) = %ld.%09ld (%s)\n",
-                   tstr, tod_ns.tv_sec, (int) tod_ns.tv_usec,
-                   clockid_ns.tv_sec, clockid_ns.tv_nsec,
+                   tstr, (long) tod_ns.tv_sec, (int) tod_ns.tv_usec,
+                   (long) clockid_ns.tv_sec, clockid_ns.tv_nsec,
                    clockid_name(clockid));
 }
 
index 692e56d..fbc40a2 100644 (file)
@@ -77,8 +77,7 @@ static inline bool replace_android_lib(const char *filename, char *newfilename)
        if (strstarts(filename, "/system/lib/")) {
                char *ndk, *app;
                const char *arch;
-               size_t ndk_length;
-               size_t app_length;
+               int ndk_length, app_length;
 
                ndk = getenv("NDK_ROOT");
                app = getenv("APP_PLATFORM");
@@ -106,8 +105,8 @@ static inline bool replace_android_lib(const char *filename, char *newfilename)
                if (new_length > PATH_MAX)
                        return false;
                snprintf(newfilename, new_length,
-                       "%s/platforms/%s/arch-%s/usr/lib/%s",
-                       ndk, app, arch, libname);
+                       "%.*s/platforms/%.*s/arch-%s/usr/lib/%s",
+                       ndk_length, ndk, app_length, app, arch, libname);
 
                return true;
        }
index d5b6aff..d57ac86 100644 (file)
@@ -89,6 +89,7 @@ static void inc_group_count(struct list_head *list,
 %type <str> PE_EVENT_NAME
 %type <str> PE_PMU_EVENT_PRE PE_PMU_EVENT_SUF PE_KERNEL_PMU_EVENT PE_PMU_EVENT_FAKE
 %type <str> PE_DRV_CFG_TERM
+%type <str> event_pmu_name
 %destructor { free ($$); } <str>
 %type <term> event_term
 %destructor { parse_events_term__delete ($$); } <term>
@@ -272,8 +273,11 @@ event_def: event_pmu |
           event_legacy_raw sep_dc |
           event_bpf_file
 
+event_pmu_name:
+PE_NAME | PE_PMU_EVENT_PRE
+
 event_pmu:
-PE_NAME opt_pmu_config
+event_pmu_name opt_pmu_config
 {
        struct parse_events_state *parse_state = _parse_state;
        struct parse_events_error *error = parse_state->error;
index 71b7535..845dd46 100644 (file)
@@ -36,3 +36,4 @@ util/symbol_fprintf.c
 util/units.c
 util/affinity.c
 util/rwsem.c
+util/hashmap.c
index 0d5ad42..552b590 100644 (file)
@@ -3140,7 +3140,7 @@ int output_field_add(struct perf_hpp_list *list, char *tok)
                if (strncasecmp(tok, sd->name, strlen(tok)))
                        continue;
 
-               if (sort__mode != SORT_MODE__MEMORY)
+               if (sort__mode != SORT_MODE__BRANCH)
                        return -EINVAL;
 
                return __sort_dimension__add_output(list, sd);
@@ -3152,7 +3152,7 @@ int output_field_add(struct perf_hpp_list *list, char *tok)
                if (strncasecmp(tok, sd->name, strlen(tok)))
                        continue;
 
-               if (sort__mode != SORT_MODE__BRANCH)
+               if (sort__mode != SORT_MODE__MEMORY)
                        return -EINVAL;
 
                return __sort_dimension__add_output(list, sd);
index cce7a76..7f09cda 100644 (file)
@@ -983,7 +983,7 @@ static void print_interval(struct perf_stat_config *config,
        if (config->interval_clear)
                puts(CONSOLE_CLEAR);
 
-       sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, config->csv_sep);
+       sprintf(prefix, "%6lu.%09lu%s", (unsigned long) ts->tv_sec, ts->tv_nsec, config->csv_sep);
 
        if ((num_print_interval == 0 && !config->csv_output) || config->interval_clear) {
                switch (config->aggr_mode) {
index 5d8af29..c400f8d 100644 (file)
@@ -13,6 +13,7 @@
 #include "evlist.h"
 #include "evsel.h"
 #include "thread_map.h"
+#include "hashmap.h"
 #include <linux/zalloc.h>
 
 void update_stats(struct stats *stats, u64 val)
@@ -277,18 +278,29 @@ void evlist__save_aggr_prev_raw_counts(struct evlist *evlist)
        }
 }
 
-static void zero_per_pkg(struct evsel *counter)
+static size_t pkg_id_hash(const void *__key, void *ctx __maybe_unused)
 {
-       if (counter->per_pkg_mask)
-               memset(counter->per_pkg_mask, 0, cpu__max_cpu());
+       uint64_t *key = (uint64_t *) __key;
+
+       return *key & 0xffffffff;
+}
+
+static bool pkg_id_equal(const void *__key1, const void *__key2,
+                        void *ctx __maybe_unused)
+{
+       uint64_t *key1 = (uint64_t *) __key1;
+       uint64_t *key2 = (uint64_t *) __key2;
+
+       return *key1 == *key2;
 }
 
 static int check_per_pkg(struct evsel *counter,
                         struct perf_counts_values *vals, int cpu, bool *skip)
 {
-       unsigned long *mask = counter->per_pkg_mask;
+       struct hashmap *mask = counter->per_pkg_mask;
        struct perf_cpu_map *cpus = evsel__cpus(counter);
-       int s;
+       int s, d, ret = 0;
+       uint64_t *key;
 
        *skip = false;
 
@@ -299,7 +311,7 @@ static int check_per_pkg(struct evsel *counter,
                return 0;
 
        if (!mask) {
-               mask = zalloc(cpu__max_cpu());
+               mask = hashmap__new(pkg_id_hash, pkg_id_equal, NULL);
                if (!mask)
                        return -ENOMEM;
 
@@ -321,8 +333,25 @@ static int check_per_pkg(struct evsel *counter,
        if (s < 0)
                return -1;
 
-       *skip = test_and_set_bit(s, mask) == 1;
-       return 0;
+       /*
+        * On multi-die system, die_id > 0. On no-die system, die_id = 0.
+        * We use hashmap(socket, die) to check the used socket+die pair.
+        */
+       d = cpu_map__get_die(cpus, cpu, NULL).die;
+       if (d < 0)
+               return -1;
+
+       key = malloc(sizeof(*key));
+       if (!key)
+               return -ENOMEM;
+
+       *key = (uint64_t)d << 32 | s;
+       if (hashmap__find(mask, (void *)key, NULL))
+               *skip = true;
+       else
+               ret = hashmap__add(mask, (void *)key, (void *)1);
+
+       return ret;
 }
 
 static int
@@ -422,7 +451,7 @@ int perf_stat_process_counter(struct perf_stat_config *config,
        }
 
        if (counter->per_pkg)
-               zero_per_pkg(counter);
+               evsel__zero_per_pkg(counter);
 
        ret = process_counter_maps(config, counter);
        if (ret)
index f507dff..8a01af7 100644 (file)
@@ -361,6 +361,7 @@ static int read_saved_cmdline(struct tep_handle *pevent)
                pr_debug("error reading saved cmdlines\n");
                goto out;
        }
+       buf[ret] = '\0';
 
        parse_saved_cmdline(pevent, buf, size);
        ret = 0;
index b2282be..612d389 100644 (file)
@@ -332,5 +332,5 @@ int main(void)
 
        ksft_print_cnts();
 
-       return 0;
+       return ret;
 }
index 6b67003..1d8918d 100644 (file)
@@ -16,6 +16,13 @@ bool skip = false;
 #define STRSIZE                        2048
 #define EXPECTED_STRSIZE       256
 
+#if defined(bpf_target_s390)
+/* NULL points to a readable struct lowcore on s390, so take the last page */
+#define BADPTR                 ((void *)0xFFFFFFFFFFFFF000ULL)
+#else
+#define BADPTR                 0
+#endif
+
 #ifndef ARRAY_SIZE
 #define ARRAY_SIZE(x)  (sizeof(x) / sizeof((x)[0]))
 #endif
@@ -113,11 +120,11 @@ int BPF_PROG(trace_netif_receive_skb, struct sk_buff *skb)
        }
 
        /* Check invalid ptr value */
-       p.ptr = 0;
+       p.ptr = BADPTR;
        __ret = bpf_snprintf_btf(str, STRSIZE, &p, sizeof(p), 0);
        if (__ret >= 0) {
-               bpf_printk("printing NULL should generate error, got (%d)",
-                          __ret);
+               bpf_printk("printing %llx should generate error, got (%d)",
+                          (unsigned long long)BADPTR, __ret);
                ret = -ERANGE;
        }
 
index 2848804..ef5277d 100644 (file)
@@ -15,5 +15,5 @@ __noinline int foo(const struct S *s)
 SEC("cgroup_skb/ingress")
 int test_cls(struct __sk_buff *skb)
 {
-       return foo(skb);
+       return foo((const void *)skb);
 }
index a621b58..9afe947 100644 (file)
@@ -446,10 +446,8 @@ int _geneve_get_tunnel(struct __sk_buff *skb)
        }
 
        ret = bpf_skb_get_tunnel_opt(skb, &gopt, sizeof(gopt));
-       if (ret < 0) {
-               ERROR(ret);
-               return TC_ACT_SHOT;
-       }
+       if (ret < 0)
+               gopt.opt_class = 0;
 
        bpf_trace_printk(fmt, sizeof(fmt),
                        key.tunnel_id, key.remote_ipv4, gopt.opt_class);
index bed53b5..1b138cd 100644 (file)
        BPF_MOV64_IMM(BPF_REG_5, 0),
        BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
                     BPF_FUNC_csum_diff),
+       BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 0xffff),
        BPF_EXIT_INSN(),
        },
        .prog_type = BPF_PROG_TYPE_SCHED_CLS,
        .fixup_map_array_ro = { 3 },
        .result = ACCEPT,
-       .retval = -29,
+       .retval = 65507,
 },
 {
        "invalid write map access into a read-only array 1",
index 1bdc8e6..fe4bb70 100644 (file)
        },
        .result = ACCEPT,
 },
+{
+       "BPF_ATOMIC_AND with fetch - r0 as source reg",
+       .insns = {
+               /* val = 0x110; */
+               BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0x110),
+               /* old = atomic_fetch_and(&val, 0x011); */
+               BPF_MOV64_IMM(BPF_REG_0, 0x011),
+               BPF_ATOMIC_OP(BPF_DW, BPF_AND | BPF_FETCH, BPF_REG_10, BPF_REG_0, -8),
+               /* if (old != 0x110) exit(3); */
+               BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0x110, 2),
+               BPF_MOV64_IMM(BPF_REG_0, 3),
+               BPF_EXIT_INSN(),
+               /* if (val != 0x010) exit(2); */
+               BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_10, -8),
+               BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0x010, 2),
+               BPF_MOV64_IMM(BPF_REG_1, 2),
+               BPF_EXIT_INSN(),
+               /* exit(0); */
+               BPF_MOV64_IMM(BPF_REG_0, 0),
+               BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+},
index 2efd8bc..6e52dfc 100644 (file)
        .result = REJECT,
        .errstr = "invalid read from stack",
 },
+{
+       "BPF_W cmpxchg should zero top 32 bits",
+       .insns = {
+               /* r0 = U64_MAX; */
+               BPF_MOV64_IMM(BPF_REG_0, 0),
+               BPF_ALU64_IMM(BPF_SUB, BPF_REG_0, 1),
+               /* u64 val = r0; */
+               BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -8),
+               /* r0 = (u32)atomic_cmpxchg((u32 *)&val, r0, 1); */
+               BPF_MOV32_IMM(BPF_REG_1, 1),
+               BPF_ATOMIC_OP(BPF_W, BPF_CMPXCHG, BPF_REG_10, BPF_REG_1, -8),
+               /* r1 = 0x00000000FFFFFFFFull; */
+               BPF_MOV64_IMM(BPF_REG_1, 1),
+               BPF_ALU64_IMM(BPF_LSH, BPF_REG_1, 32),
+               BPF_ALU64_IMM(BPF_SUB, BPF_REG_1, 1),
+               /* if (r0 != r1) exit(1); */
+               BPF_JMP_REG(BPF_JEQ, BPF_REG_0, BPF_REG_1, 2),
+               BPF_MOV32_IMM(BPF_REG_0, 1),
+               BPF_EXIT_INSN(),
+               /* exit(0); */
+               BPF_MOV32_IMM(BPF_REG_0, 0),
+               BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+},
index 70f982e..9d0716a 100644 (file)
        },
        .result = ACCEPT,
 },
+{
+       "BPF_W atomic_fetch_or should zero top 32 bits",
+       .insns = {
+               /* r1 = U64_MAX; */
+               BPF_MOV64_IMM(BPF_REG_1, 0),
+               BPF_ALU64_IMM(BPF_SUB, BPF_REG_1, 1),
+               /* u64 val = r1; */
+               BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, -8),
+               /* r1 = (u32)atomic_fetch_or((u32 *)&val, 2); */
+               BPF_MOV32_IMM(BPF_REG_1, 2),
+               BPF_ATOMIC_OP(BPF_W, BPF_OR | BPF_FETCH, BPF_REG_10, BPF_REG_1, -8),
+               /* r2 = 0x00000000FFFFFFFF; */
+               BPF_MOV64_IMM(BPF_REG_2, 1),
+               BPF_ALU64_IMM(BPF_LSH, BPF_REG_2, 32),
+               BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 1),
+               /* if (r2 != r1) exit(1); */
+               BPF_JMP_REG(BPF_JEQ, BPF_REG_2, BPF_REG_1, 2),
+               BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
+               BPF_EXIT_INSN(),
+               /* exit(0); */
+               BPF_MOV32_IMM(BPF_REG_0, 0),
+               BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+},
index 4c69408..a4969f7 100644 (file)
@@ -1,2 +1,2 @@
 # SPDX-License-Identifier: GPL-2.0-only
-gpio-mockup-chardev
+gpio-mockup-cdev
index 32b87cc..7bd7e77 100644 (file)
@@ -8,10 +8,13 @@
 /x86_64/debug_regs
 /x86_64/evmcs_test
 /x86_64/get_cpuid_test
+/x86_64/get_msr_index_features
 /x86_64/kvm_pv_test
+/x86_64/hyperv_clock
 /x86_64/hyperv_cpuid
 /x86_64/mmio_warning_test
 /x86_64/platform_info_test
+/x86_64/set_boot_cpu_id
 /x86_64/set_sregs_test
 /x86_64/smm_test
 /x86_64/state_test
index a6d61f4..67eebb5 100644 (file)
@@ -39,12 +39,15 @@ LIBKVM_aarch64 = lib/aarch64/processor.c lib/aarch64/ucall.c
 LIBKVM_s390x = lib/s390x/processor.c lib/s390x/ucall.c lib/s390x/diag318_test_handler.c
 
 TEST_GEN_PROGS_x86_64 = x86_64/cr4_cpuid_sync_test
+TEST_GEN_PROGS_x86_64 += x86_64/get_msr_index_features
 TEST_GEN_PROGS_x86_64 += x86_64/evmcs_test
 TEST_GEN_PROGS_x86_64 += x86_64/get_cpuid_test
+TEST_GEN_PROGS_x86_64 += x86_64/hyperv_clock
 TEST_GEN_PROGS_x86_64 += x86_64/hyperv_cpuid
 TEST_GEN_PROGS_x86_64 += x86_64/kvm_pv_test
 TEST_GEN_PROGS_x86_64 += x86_64/mmio_warning_test
 TEST_GEN_PROGS_x86_64 += x86_64/platform_info_test
+TEST_GEN_PROGS_x86_64 += x86_64/set_boot_cpu_id
 TEST_GEN_PROGS_x86_64 += x86_64/set_sregs_test
 TEST_GEN_PROGS_x86_64 += x86_64/smm_test
 TEST_GEN_PROGS_x86_64 += x86_64/state_test
index 2d7eb69..0f4258e 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "sparsebit.h"
 
+#define KVM_DEV_PATH "/dev/kvm"
 #define KVM_MAX_VCPUS 512
 
 /*
@@ -133,6 +134,7 @@ void vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, unsigned long ioctl,
 int _vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, unsigned long ioctl,
                void *arg);
 void vm_ioctl(struct kvm_vm *vm, unsigned long ioctl, void *arg);
+int _vm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg);
 void kvm_ioctl(struct kvm_vm *vm, unsigned long ioctl, void *arg);
 int _kvm_ioctl(struct kvm_vm *vm, unsigned long ioctl, void *arg);
 void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags);
index e5fbf16..b8849a1 100644 (file)
@@ -1697,11 +1697,16 @@ void vm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg)
 {
        int ret;
 
-       ret = ioctl(vm->fd, cmd, arg);
+       ret = _vm_ioctl(vm, cmd, arg);
        TEST_ASSERT(ret == 0, "vm ioctl %lu failed, rc: %i errno: %i (%s)",
                cmd, ret, errno, strerror(errno));
 }
 
+int _vm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg)
+{
+       return ioctl(vm->fd, cmd, arg);
+}
+
 /*
  * KVM system ioctl
  *
index 34465dc..91ce1b5 100644 (file)
@@ -10,8 +10,6 @@
 
 #include "sparsebit.h"
 
-#define KVM_DEV_PATH           "/dev/kvm"
-
 struct userspace_mem_region {
        struct kvm_userspace_memory_region region;
        struct sparsebit *unused_phy_pages;
diff --git a/tools/testing/selftests/kvm/x86_64/get_msr_index_features.c b/tools/testing/selftests/kvm/x86_64/get_msr_index_features.c
new file mode 100644 (file)
index 0000000..cb953df
--- /dev/null
@@ -0,0 +1,134 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Test that KVM_GET_MSR_INDEX_LIST and
+ * KVM_GET_MSR_FEATURE_INDEX_LIST work as intended
+ *
+ * Copyright (C) 2020, Red Hat, Inc.
+ */
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include "test_util.h"
+#include "kvm_util.h"
+#include "processor.h"
+
+static int kvm_num_index_msrs(int kvm_fd, int nmsrs)
+{
+       struct kvm_msr_list *list;
+       int r;
+
+       list = malloc(sizeof(*list) + nmsrs * sizeof(list->indices[0]));
+       list->nmsrs = nmsrs;
+       r = ioctl(kvm_fd, KVM_GET_MSR_INDEX_LIST, list);
+       TEST_ASSERT(r == -1 && errno == E2BIG,
+                               "Unexpected result from KVM_GET_MSR_INDEX_LIST probe, r: %i",
+                               r);
+
+       r = list->nmsrs;
+       free(list);
+       return r;
+}
+
+static void test_get_msr_index(void)
+{
+       int old_res, res, kvm_fd, r;
+       struct kvm_msr_list *list;
+
+       kvm_fd = open(KVM_DEV_PATH, O_RDONLY);
+       if (kvm_fd < 0)
+               exit(KSFT_SKIP);
+
+       old_res = kvm_num_index_msrs(kvm_fd, 0);
+       TEST_ASSERT(old_res != 0, "Expecting nmsrs to be > 0");
+
+       if (old_res != 1) {
+               res = kvm_num_index_msrs(kvm_fd, 1);
+               TEST_ASSERT(res > 1, "Expecting nmsrs to be > 1");
+               TEST_ASSERT(res == old_res, "Expecting nmsrs to be identical");
+       }
+
+       list = malloc(sizeof(*list) + old_res * sizeof(list->indices[0]));
+       list->nmsrs = old_res;
+       r = ioctl(kvm_fd, KVM_GET_MSR_INDEX_LIST, list);
+
+       TEST_ASSERT(r == 0,
+                   "Unexpected result from KVM_GET_MSR_FEATURE_INDEX_LIST, r: %i",
+                   r);
+       TEST_ASSERT(list->nmsrs == old_res, "Expecting nmsrs to be identical");
+       free(list);
+
+       close(kvm_fd);
+}
+
+static int kvm_num_feature_msrs(int kvm_fd, int nmsrs)
+{
+       struct kvm_msr_list *list;
+       int r;
+
+       list = malloc(sizeof(*list) + nmsrs * sizeof(list->indices[0]));
+       list->nmsrs = nmsrs;
+       r = ioctl(kvm_fd, KVM_GET_MSR_FEATURE_INDEX_LIST, list);
+       TEST_ASSERT(r == -1 && errno == E2BIG,
+               "Unexpected result from KVM_GET_MSR_FEATURE_INDEX_LIST probe, r: %i",
+                               r);
+
+       r = list->nmsrs;
+       free(list);
+       return r;
+}
+
+struct kvm_msr_list *kvm_get_msr_feature_list(int kvm_fd, int nmsrs)
+{
+       struct kvm_msr_list *list;
+       int r;
+
+       list = malloc(sizeof(*list) + nmsrs * sizeof(list->indices[0]));
+       list->nmsrs = nmsrs;
+       r = ioctl(kvm_fd, KVM_GET_MSR_FEATURE_INDEX_LIST, list);
+
+       TEST_ASSERT(r == 0,
+               "Unexpected result from KVM_GET_MSR_FEATURE_INDEX_LIST, r: %i",
+               r);
+
+       return list;
+}
+
+static void test_get_msr_feature(void)
+{
+       int res, old_res, i, kvm_fd;
+       struct kvm_msr_list *feature_list;
+
+       kvm_fd = open(KVM_DEV_PATH, O_RDONLY);
+       if (kvm_fd < 0)
+               exit(KSFT_SKIP);
+
+       old_res = kvm_num_feature_msrs(kvm_fd, 0);
+       TEST_ASSERT(old_res != 0, "Expecting nmsrs to be > 0");
+
+       if (old_res != 1) {
+               res = kvm_num_feature_msrs(kvm_fd, 1);
+               TEST_ASSERT(res > 1, "Expecting nmsrs to be > 1");
+               TEST_ASSERT(res == old_res, "Expecting nmsrs to be identical");
+       }
+
+       feature_list = kvm_get_msr_feature_list(kvm_fd, old_res);
+       TEST_ASSERT(old_res == feature_list->nmsrs,
+                               "Unmatching number of msr indexes");
+
+       for (i = 0; i < feature_list->nmsrs; i++)
+               kvm_get_feature_msr(feature_list->indices[i]);
+
+       free(feature_list);
+       close(kvm_fd);
+}
+
+int main(int argc, char *argv[])
+{
+       if (kvm_check_cap(KVM_CAP_GET_MSR_FEATURES))
+               test_get_msr_feature();
+
+       test_get_msr_index();
+}
diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_clock.c b/tools/testing/selftests/kvm/x86_64/hyperv_clock.c
new file mode 100644 (file)
index 0000000..ffbc455
--- /dev/null
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2021, Red Hat, Inc.
+ *
+ * Tests for Hyper-V clocksources
+ */
+#include "test_util.h"
+#include "kvm_util.h"
+#include "processor.h"
+
+struct ms_hyperv_tsc_page {
+       volatile u32 tsc_sequence;
+       u32 reserved1;
+       volatile u64 tsc_scale;
+       volatile s64 tsc_offset;
+} __packed;
+
+#define HV_X64_MSR_GUEST_OS_ID                 0x40000000
+#define HV_X64_MSR_TIME_REF_COUNT              0x40000020
+#define HV_X64_MSR_REFERENCE_TSC               0x40000021
+#define HV_X64_MSR_TSC_FREQUENCY               0x40000022
+#define HV_X64_MSR_REENLIGHTENMENT_CONTROL     0x40000106
+#define HV_X64_MSR_TSC_EMULATION_CONTROL       0x40000107
+
+/* Simplified mul_u64_u64_shr() */
+static inline u64 mul_u64_u64_shr64(u64 a, u64 b)
+{
+       union {
+               u64 ll;
+               struct {
+                       u32 low, high;
+               } l;
+       } rm, rn, rh, a0, b0;
+       u64 c;
+
+       a0.ll = a;
+       b0.ll = b;
+
+       rm.ll = (u64)a0.l.low * b0.l.high;
+       rn.ll = (u64)a0.l.high * b0.l.low;
+       rh.ll = (u64)a0.l.high * b0.l.high;
+
+       rh.l.low = c = rm.l.high + rn.l.high + rh.l.low;
+       rh.l.high = (c >> 32) + rh.l.high;
+
+       return rh.ll;
+}
+
+static inline void nop_loop(void)
+{
+       int i;
+
+       for (i = 0; i < 1000000; i++)
+               asm volatile("nop");
+}
+
+static inline void check_tsc_msr_rdtsc(void)
+{
+       u64 tsc_freq, r1, r2, t1, t2;
+       s64 delta_ns;
+
+       tsc_freq = rdmsr(HV_X64_MSR_TSC_FREQUENCY);
+       GUEST_ASSERT(tsc_freq > 0);
+
+       /* First, check MSR-based clocksource */
+       r1 = rdtsc();
+       t1 = rdmsr(HV_X64_MSR_TIME_REF_COUNT);
+       nop_loop();
+       r2 = rdtsc();
+       t2 = rdmsr(HV_X64_MSR_TIME_REF_COUNT);
+
+       GUEST_ASSERT(r2 > r1 && t2 > t1);
+
+       /* HV_X64_MSR_TIME_REF_COUNT is in 100ns */
+       delta_ns = ((t2 - t1) * 100) - ((r2 - r1) * 1000000000 / tsc_freq);
+       if (delta_ns < 0)
+               delta_ns = -delta_ns;
+
+       /* 1% tolerance */
+       GUEST_ASSERT(delta_ns * 100 < (t2 - t1) * 100);
+}
+
+static inline void check_tsc_msr_tsc_page(struct ms_hyperv_tsc_page *tsc_page)
+{
+       u64 r1, r2, t1, t2;
+
+       /* Compare TSC page clocksource with HV_X64_MSR_TIME_REF_COUNT */
+       t1 = mul_u64_u64_shr64(rdtsc(), tsc_page->tsc_scale) + tsc_page->tsc_offset;
+       r1 = rdmsr(HV_X64_MSR_TIME_REF_COUNT);
+
+       /* 10 ms tolerance */
+       GUEST_ASSERT(r1 >= t1 && r1 - t1 < 100000);
+       nop_loop();
+
+       t2 = mul_u64_u64_shr64(rdtsc(), tsc_page->tsc_scale) + tsc_page->tsc_offset;
+       r2 = rdmsr(HV_X64_MSR_TIME_REF_COUNT);
+       GUEST_ASSERT(r2 >= t1 && r2 - t2 < 100000);
+}
+
+static void guest_main(struct ms_hyperv_tsc_page *tsc_page, vm_paddr_t tsc_page_gpa)
+{
+       u64 tsc_scale, tsc_offset;
+
+       /* Set Guest OS id to enable Hyper-V emulation */
+       GUEST_SYNC(1);
+       wrmsr(HV_X64_MSR_GUEST_OS_ID, (u64)0x8100 << 48);
+       GUEST_SYNC(2);
+
+       check_tsc_msr_rdtsc();
+
+       GUEST_SYNC(3);
+
+       /* Set up TSC page is disabled state, check that it's clean */
+       wrmsr(HV_X64_MSR_REFERENCE_TSC, tsc_page_gpa);
+       GUEST_ASSERT(tsc_page->tsc_sequence == 0);
+       GUEST_ASSERT(tsc_page->tsc_scale == 0);
+       GUEST_ASSERT(tsc_page->tsc_offset == 0);
+
+       GUEST_SYNC(4);
+
+       /* Set up TSC page is enabled state */
+       wrmsr(HV_X64_MSR_REFERENCE_TSC, tsc_page_gpa | 0x1);
+       GUEST_ASSERT(tsc_page->tsc_sequence != 0);
+
+       GUEST_SYNC(5);
+
+       check_tsc_msr_tsc_page(tsc_page);
+
+       GUEST_SYNC(6);
+
+       tsc_offset = tsc_page->tsc_offset;
+       /* Call KVM_SET_CLOCK from userspace, check that TSC page was updated */
+       GUEST_SYNC(7);
+       GUEST_ASSERT(tsc_page->tsc_offset != tsc_offset);
+
+       nop_loop();
+
+       /*
+        * Enable Re-enlightenment and check that TSC page stays constant across
+        * KVM_SET_CLOCK.
+        */
+       wrmsr(HV_X64_MSR_REENLIGHTENMENT_CONTROL, 0x1 << 16 | 0xff);
+       wrmsr(HV_X64_MSR_TSC_EMULATION_CONTROL, 0x1);
+       tsc_offset = tsc_page->tsc_offset;
+       tsc_scale = tsc_page->tsc_scale;
+       GUEST_SYNC(8);
+       GUEST_ASSERT(tsc_page->tsc_offset == tsc_offset);
+       GUEST_ASSERT(tsc_page->tsc_scale == tsc_scale);
+
+       GUEST_SYNC(9);
+
+       check_tsc_msr_tsc_page(tsc_page);
+
+       /*
+        * Disable re-enlightenment and TSC page, check that KVM doesn't update
+        * it anymore.
+        */
+       wrmsr(HV_X64_MSR_REENLIGHTENMENT_CONTROL, 0);
+       wrmsr(HV_X64_MSR_TSC_EMULATION_CONTROL, 0);
+       wrmsr(HV_X64_MSR_REFERENCE_TSC, 0);
+       memset(tsc_page, 0, sizeof(*tsc_page));
+
+       GUEST_SYNC(10);
+       GUEST_ASSERT(tsc_page->tsc_sequence == 0);
+       GUEST_ASSERT(tsc_page->tsc_offset == 0);
+       GUEST_ASSERT(tsc_page->tsc_scale == 0);
+
+       GUEST_DONE();
+}
+
+#define VCPU_ID 0
+
+static void host_check_tsc_msr_rdtsc(struct kvm_vm *vm)
+{
+       u64 tsc_freq, r1, r2, t1, t2;
+       s64 delta_ns;
+
+       tsc_freq = vcpu_get_msr(vm, VCPU_ID, HV_X64_MSR_TSC_FREQUENCY);
+       TEST_ASSERT(tsc_freq > 0, "TSC frequency must be nonzero");
+
+       /* First, check MSR-based clocksource */
+       r1 = rdtsc();
+       t1 = vcpu_get_msr(vm, VCPU_ID, HV_X64_MSR_TIME_REF_COUNT);
+       nop_loop();
+       r2 = rdtsc();
+       t2 = vcpu_get_msr(vm, VCPU_ID, HV_X64_MSR_TIME_REF_COUNT);
+
+       TEST_ASSERT(t2 > t1, "Time reference MSR is not monotonic (%ld <= %ld)", t1, t2);
+
+       /* HV_X64_MSR_TIME_REF_COUNT is in 100ns */
+       delta_ns = ((t2 - t1) * 100) - ((r2 - r1) * 1000000000 / tsc_freq);
+       if (delta_ns < 0)
+               delta_ns = -delta_ns;
+
+       /* 1% tolerance */
+       TEST_ASSERT(delta_ns * 100 < (t2 - t1) * 100,
+                   "Elapsed time does not match (MSR=%ld, TSC=%ld)",
+                   (t2 - t1) * 100, (r2 - r1) * 1000000000 / tsc_freq);
+}
+
+int main(void)
+{
+       struct kvm_vm *vm;
+       struct kvm_run *run;
+       struct ucall uc;
+       vm_vaddr_t tsc_page_gva;
+       int stage;
+
+       vm = vm_create_default(VCPU_ID, 0, guest_main);
+       run = vcpu_state(vm, VCPU_ID);
+
+       vcpu_set_hv_cpuid(vm, VCPU_ID);
+
+       tsc_page_gva = vm_vaddr_alloc(vm, getpagesize(), 0x10000, 0, 0);
+       memset(addr_gpa2hva(vm, tsc_page_gva), 0x0, getpagesize());
+       TEST_ASSERT((addr_gva2gpa(vm, tsc_page_gva) & (getpagesize() - 1)) == 0,
+               "TSC page has to be page aligned\n");
+       vcpu_args_set(vm, VCPU_ID, 2, tsc_page_gva, addr_gva2gpa(vm, tsc_page_gva));
+
+       host_check_tsc_msr_rdtsc(vm);
+
+       for (stage = 1;; stage++) {
+               _vcpu_run(vm, VCPU_ID);
+               TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
+                           "Stage %d: unexpected exit reason: %u (%s),\n",
+                           stage, run->exit_reason,
+                           exit_reason_str(run->exit_reason));
+
+               switch (get_ucall(vm, VCPU_ID, &uc)) {
+               case UCALL_ABORT:
+                       TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0],
+                                 __FILE__, uc.args[1]);
+                       /* NOT REACHED */
+               case UCALL_SYNC:
+                       break;
+               case UCALL_DONE:
+                       /* Keep in sync with guest_main() */
+                       TEST_ASSERT(stage == 11, "Testing ended prematurely, stage %d\n",
+                                   stage);
+                       goto out;
+               default:
+                       TEST_FAIL("Unknown ucall %lu", uc.cmd);
+               }
+
+               TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") &&
+                           uc.args[1] == stage,
+                           "Stage %d: Unexpected register values vmexit, got %lx",
+                           stage, (ulong)uc.args[1]);
+
+               /* Reset kvmclock triggering TSC page update */
+               if (stage == 7 || stage == 8 || stage == 10) {
+                       struct kvm_clock_data clock = {0};
+
+                       vm_ioctl(vm, KVM_SET_CLOCK, &clock);
+               }
+       }
+
+out:
+       kvm_vm_free(vm);
+}
diff --git a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c
new file mode 100644 (file)
index 0000000..12c558f
--- /dev/null
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Test that KVM_SET_BOOT_CPU_ID works as intended
+ *
+ * Copyright (C) 2020, Red Hat, Inc.
+ */
+#define _GNU_SOURCE /* for program_invocation_name */
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include "test_util.h"
+#include "kvm_util.h"
+#include "processor.h"
+
+#define N_VCPU 2
+#define VCPU_ID0 0
+#define VCPU_ID1 1
+
+static uint32_t get_bsp_flag(void)
+{
+       return rdmsr(MSR_IA32_APICBASE) & MSR_IA32_APICBASE_BSP;
+}
+
+static void guest_bsp_vcpu(void *arg)
+{
+       GUEST_SYNC(1);
+
+       GUEST_ASSERT(get_bsp_flag() != 0);
+
+       GUEST_DONE();
+}
+
+static void guest_not_bsp_vcpu(void *arg)
+{
+       GUEST_SYNC(1);
+
+       GUEST_ASSERT(get_bsp_flag() == 0);
+
+       GUEST_DONE();
+}
+
+static void test_set_boot_busy(struct kvm_vm *vm)
+{
+       int res;
+
+       res = _vm_ioctl(vm, KVM_SET_BOOT_CPU_ID, (void *) VCPU_ID0);
+       TEST_ASSERT(res == -1 && errno == EBUSY,
+                       "KVM_SET_BOOT_CPU_ID set while running vm");
+}
+
+static void run_vcpu(struct kvm_vm *vm, uint32_t vcpuid)
+{
+       struct ucall uc;
+       int stage;
+
+       for (stage = 0; stage < 2; stage++) {
+
+               vcpu_run(vm, vcpuid);
+
+               switch (get_ucall(vm, vcpuid, &uc)) {
+               case UCALL_SYNC:
+                       TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") &&
+                                       uc.args[1] == stage + 1,
+                                       "Stage %d: Unexpected register values vmexit, got %lx",
+                                       stage + 1, (ulong)uc.args[1]);
+                       test_set_boot_busy(vm);
+                       break;
+               case UCALL_DONE:
+                       TEST_ASSERT(stage == 1,
+                                       "Expected GUEST_DONE in stage 2, got stage %d",
+                                       stage);
+                       break;
+               case UCALL_ABORT:
+                       TEST_ASSERT(false, "%s at %s:%ld\n\tvalues: %#lx, %#lx",
+                                               (const char *)uc.args[0], __FILE__,
+                                               uc.args[1], uc.args[2], uc.args[3]);
+               default:
+                       TEST_ASSERT(false, "Unexpected exit: %s",
+                                       exit_reason_str(vcpu_state(vm, vcpuid)->exit_reason));
+               }
+       }
+}
+
+static struct kvm_vm *create_vm(void)
+{
+       struct kvm_vm *vm;
+       uint64_t vcpu_pages = (DEFAULT_STACK_PGS) * 2;
+       uint64_t extra_pg_pages = vcpu_pages / PTES_PER_MIN_PAGE * N_VCPU;
+       uint64_t pages = DEFAULT_GUEST_PHY_PAGES + vcpu_pages + extra_pg_pages;
+
+       pages = vm_adjust_num_guest_pages(VM_MODE_DEFAULT, pages);
+       vm = vm_create(VM_MODE_DEFAULT, pages, O_RDWR);
+
+       kvm_vm_elf_load(vm, program_invocation_name, 0, 0);
+       vm_create_irqchip(vm);
+
+       return vm;
+}
+
+static void add_x86_vcpu(struct kvm_vm *vm, uint32_t vcpuid, bool bsp_code)
+{
+       if (bsp_code)
+               vm_vcpu_add_default(vm, vcpuid, guest_bsp_vcpu);
+       else
+               vm_vcpu_add_default(vm, vcpuid, guest_not_bsp_vcpu);
+
+       vcpu_set_cpuid(vm, vcpuid, kvm_get_supported_cpuid());
+}
+
+static void run_vm_bsp(uint32_t bsp_vcpu)
+{
+       struct kvm_vm *vm;
+       bool is_bsp_vcpu1 = bsp_vcpu == VCPU_ID1;
+
+       vm = create_vm();
+
+       if (is_bsp_vcpu1)
+               vm_ioctl(vm, KVM_SET_BOOT_CPU_ID, (void *) VCPU_ID1);
+
+       add_x86_vcpu(vm, VCPU_ID0, !is_bsp_vcpu1);
+       add_x86_vcpu(vm, VCPU_ID1, is_bsp_vcpu1);
+
+       run_vcpu(vm, VCPU_ID0);
+       run_vcpu(vm, VCPU_ID1);
+
+       kvm_vm_free(vm);
+}
+
+static void check_set_bsp_busy(void)
+{
+       struct kvm_vm *vm;
+       int res;
+
+       vm = create_vm();
+
+       add_x86_vcpu(vm, VCPU_ID0, true);
+       add_x86_vcpu(vm, VCPU_ID1, false);
+
+       res = _vm_ioctl(vm, KVM_SET_BOOT_CPU_ID, (void *) VCPU_ID1);
+       TEST_ASSERT(res == -1 && errno == EBUSY, "KVM_SET_BOOT_CPU_ID set after adding vcpu");
+
+       run_vcpu(vm, VCPU_ID0);
+       run_vcpu(vm, VCPU_ID1);
+
+       res = _vm_ioctl(vm, KVM_SET_BOOT_CPU_ID, (void *) VCPU_ID1);
+       TEST_ASSERT(res == -1 && errno == EBUSY, "KVM_SET_BOOT_CPU_ID set to a terminated vcpu");
+
+       kvm_vm_free(vm);
+}
+
+int main(int argc, char *argv[])
+{
+       if (!kvm_check_cap(KVM_CAP_SET_BOOT_CPU_ID)) {
+               print_skip("set_boot_cpu_id not available");
+               return 0;
+       }
+
+       run_vm_bsp(VCPU_ID0);
+       run_vm_bsp(VCPU_ID1);
+       run_vm_bsp(VCPU_ID0);
+
+       check_set_bsp_busy();
+}
index 4c7d336..d98fb85 100755 (executable)
@@ -1524,6 +1524,14 @@ basic()
        run_cmd "$IP nexthop replace id 2 blackhole dev veth1"
        log_test $? 2 "Blackhole nexthop with other attributes"
 
+       # blackhole nexthop should not be affected by the state of the loopback
+       # device
+       run_cmd "$IP link set dev lo down"
+       check_nexthop "id 2" "id 2 blackhole"
+       log_test $? 0 "Blackhole nexthop with loopback device down"
+
+       run_cmd "$IP link set dev lo up"
+
        #
        # groups
        #
index 197e769..f8cda82 100755 (executable)
@@ -86,11 +86,20 @@ test_ip6gretap()
 
 test_gretap_stp()
 {
+       # Sometimes after mirror installation, the neighbor's state is not valid.
+       # The reason is that there is no SW datapath activity related to the
+       # neighbor for the remote GRE address. Therefore whether the corresponding
+       # neighbor will be valid is a matter of luck, and the test is thus racy.
+       # Set the neighbor's state to permanent, so it would be always valid.
+       ip neigh replace 192.0.2.130 lladdr $(mac_get $h3) \
+               nud permanent dev br2
        full_test_span_gre_stp gt4 $swp3.555 "mirror to gretap"
 }
 
 test_ip6gretap_stp()
 {
+       ip neigh replace 2001:db8:2::2 lladdr $(mac_get $h3) \
+               nud permanent dev br2
        full_test_span_gre_stp gt6 $swp3.555 "mirror to ip6gretap"
 }
 
index 17ced7d..f23438d 100644 (file)
@@ -1785,7 +1785,7 @@ static void grand_child_serv(unsigned int nr, int cmd_fd, void *buf,
                break;
        default:
                printk("got unknown msg type %d", msg->type);
-       };
+       }
 }
 
 static int grand_child_f(unsigned int nr, int cmd_fd, void *buf)
index 3006a8e..3171069 100644 (file)
@@ -4,7 +4,7 @@
 TEST_PROGS := nft_trans_stress.sh nft_nat.sh bridge_brouter.sh \
        conntrack_icmp_related.sh nft_flowtable.sh ipvs.sh \
        nft_concat_range.sh nft_conntrack_helper.sh \
-       nft_queue.sh nft_meta.sh \
+       nft_queue.sh nft_meta.sh nf_nat_edemux.sh \
        ipip-conntrack-mtu.sh
 
 LDLIBS = -lmnl
diff --git a/tools/testing/selftests/netfilter/nf_nat_edemux.sh b/tools/testing/selftests/netfilter/nf_nat_edemux.sh
new file mode 100755 (executable)
index 0000000..cfee3b6
--- /dev/null
@@ -0,0 +1,99 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Test NAT source port clash resolution
+#
+
+# Kselftest framework requirement - SKIP code is 4.
+ksft_skip=4
+ret=0
+
+sfx=$(mktemp -u "XXXXXXXX")
+ns1="ns1-$sfx"
+ns2="ns2-$sfx"
+
+cleanup()
+{
+       ip netns del $ns1
+       ip netns del $ns2
+}
+
+iperf3 -v > /dev/null 2>&1
+if [ $? -ne 0 ];then
+       echo "SKIP: Could not run test without iperf3"
+       exit $ksft_skip
+fi
+
+iptables --version > /dev/null 2>&1
+if [ $? -ne 0 ];then
+       echo "SKIP: Could not run test without iptables"
+       exit $ksft_skip
+fi
+
+ip -Version > /dev/null 2>&1
+if [ $? -ne 0 ];then
+       echo "SKIP: Could not run test without ip tool"
+       exit $ksft_skip
+fi
+
+ip netns add "$ns1"
+if [ $? -ne 0 ];then
+       echo "SKIP: Could not create net namespace $ns1"
+       exit $ksft_skip
+fi
+
+trap cleanup EXIT
+
+ip netns add $ns2
+
+# Connect the namespaces using a veth pair
+ip link add name veth2 type veth peer name veth1
+ip link set netns $ns1 dev veth1
+ip link set netns $ns2 dev veth2
+
+ip netns exec $ns1 ip link set up dev lo
+ip netns exec $ns1 ip link set up dev veth1
+ip netns exec $ns1 ip addr add 192.168.1.1/24 dev veth1
+
+ip netns exec $ns2 ip link set up dev lo
+ip netns exec $ns2 ip link set up dev veth2
+ip netns exec $ns2 ip addr add 192.168.1.2/24 dev veth2
+
+# Create a server in one namespace
+ip netns exec $ns1 iperf3 -s > /dev/null 2>&1 &
+iperfs=$!
+
+# Restrict source port to just one so we don't have to exhaust
+# all others.
+ip netns exec $ns2 sysctl -q net.ipv4.ip_local_port_range="10000 10000"
+
+# add a virtual IP using DNAT
+ip netns exec $ns2 iptables -t nat -A OUTPUT -d 10.96.0.1/32 -p tcp --dport 443 -j DNAT --to-destination 192.168.1.1:5201
+
+# ... and route it to the other namespace
+ip netns exec $ns2 ip route add 10.96.0.1 via 192.168.1.1
+
+sleep 1
+
+# add a persistent connection from the other namespace
+ip netns exec $ns2 nc -q 10 -w 10 192.168.1.1 5201 > /dev/null &
+
+sleep 1
+
+# ip daddr:dport will be rewritten to 192.168.1.1 5201
+# NAT must reallocate source port 10000 because
+# 192.168.1.2:10000 -> 192.168.1.1:5201 is already in use
+echo test | ip netns exec $ns2 nc -w 3 -q 3 10.96.0.1 443 >/dev/null
+ret=$?
+
+kill $iperfs
+
+# Check nc can connect to 10.96.0.1:443 (aka 192.168.1.1:5201).
+if [ $ret -eq 0 ]; then
+       echo "PASS: nc can connect via NAT'd address"
+else
+       echo "FAIL: nc cannot connect via NAT'd address"
+       exit 1
+fi
+
+exit 0